@wix/agent-skills 1.24.0 → 1.26.0
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/README.md +1 -0
- package/package.json +2 -1
- package/skills/wix-app/SKILL.md +16 -14
- package/skills/wix-app/references/BUSINESS_MANAGER_THEME.md +107 -0
- package/skills/wix-app/references/BUSINESS_MANAGER_TOKENS.md +81 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +41 -0
- package/skills/wix-app/references/DASHBOARD_PAGE.md +13 -11
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +19 -4
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +3 -2
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +66 -68
- package/skills/wix-app/references/dashboard-page/DYNAMIC_PARAMETERS.md +21 -38
- package/skills/wix-app/references/data-collection/LIFECYCLE.md +6 -4
- package/skills/wix-headless/SKILL.md +0 -1
- package/skills/wix-headless/references/CAPABILITIES.md +3 -3
- package/skills/wix-headless/references/DISCOVERY.md +1 -1
- package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
- package/skills/wix-headless/references/SEED.md +1 -1
- package/skills/wix-headless/references/SETUP.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +1 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +2 -2
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +3 -14
- package/skills/wix-headless/scripts/bootstrap.mjs +156 -0
- package/skills/wix-headless-kit/SKILL.md +4 -4
- package/skills/wix-headless-kit/install/AGENTS.md +2 -2
- package/skills/wix-headless-kit/install/bootstrap.mjs +156 -0
- package/skills/wix-headless-kit/install/check.mjs +1 -1
- package/skills/wix-manage/SKILL.md +2 -8
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +250 -18
- package/skills/wix-manage/references/cms/cms-schema-management.md +52 -1
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +0 -184
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +0 -203
- package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +0 -44
- package/skills/wix-manage/references/cms/cms-data-operations-extended.md +0 -263
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +0 -162
|
@@ -1,97 +1,95 @@
|
|
|
1
1
|
# Draft Template — the starting point for every dashboard page
|
|
2
2
|
|
|
3
|
-
**Start here for any Dashboard Page request, before writing a shell, provider, or router from scratch.**
|
|
3
|
+
**Start here for any Dashboard Page request, before writing a shell, provider, or router from scratch.** The templates themselves ship inside the installed `@wix/patterns`: whole, working pages that the package type-checks against its own release, so they never drift from the version your code compiles against. This file says how to find one, where its files go in a Wix CLI app, and what this skill adds on top. Which template fits, and the wiring each one must keep, is the package's answer — read it there.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Go through [WIX_PATTERNS_DOCS.md § Prerequisites](../WIX_PATTERNS_DOCS.md#prerequisites) first for `<pkgRoot>`; every path below is relative to it.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 1. Find the templates
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
| --- | --- | --- |
|
|
11
|
-
| A list/report whose rows are read-only — no create/edit form | **A — Collection + read-only detail** | Yes |
|
|
12
|
-
| A list **and** create/edit for each record (no separate app-settings area) | **B — Collection + Entity** | Yes |
|
|
13
|
-
| Only app-wide settings/config — no list at all | **C — Settings only** | No |
|
|
14
|
-
| A list, create/edit, **and** an app-settings area, all in one extension | **D — Collection + Entity + Settings** | Yes |
|
|
9
|
+
Templates are docs-index entries with `category: "Templates"`, and each lists every file of its page in `templateFiles` (relative to `dist/templates/`). One probe lists them all with the guide that chooses between them:
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
```bash
|
|
12
|
+
python3 -c "
|
|
13
|
+
import json; i = json.load(open('<pkgRoot>/dist/docs/index.json'))
|
|
14
|
+
for k, e in i.items():
|
|
15
|
+
if e.get('category') == 'Templates' or e.get('relatedTemplates'):
|
|
16
|
+
print(k, '|', e.get('templateFiles') or e.get('relatedTemplates'), '|', e.get('summary', '')[:200])
|
|
17
|
+
"
|
|
18
|
+
```
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
| --- | --- |
|
|
25
|
-
| A vertical SDK (`@wix/bookings`, `@wix/ecom`, …) or any API you call yourself | that SDK's own query method — [DATA_SOURCES.md](DATA_SOURCES.md) |
|
|
26
|
-
| A **CMS collection** — one your Data Collection extension ships, or an existing site collection | `@wix/data` `items.query()` — [WIX_DATA.md](../data-collection/WIX_DATA.md) |
|
|
20
|
+
**No `Templates` entries means the install predates them — upgrade `@wix/patterns`.** Do not rebuild a page from memory or from an older copy of this skill instead: the templates exist so the shell, provider nesting and router wiring come from the package.
|
|
27
21
|
|
|
28
|
-
|
|
29
|
-
`fetchData`, the filters and the columns for both.
|
|
22
|
+
## 2. Choose, then read the chosen template's page
|
|
30
23
|
|
|
31
|
-
|
|
24
|
+
1. `Read <pkgRoot>/dist/docs/Page Templates.md` — which pages the request needs (read-only list, list with create/edit, settings only, or list with create/edit and settings) and where the rows come from (your own fetch, or a CMS collection).
|
|
25
|
+
2. `Read` the chosen template's page (`dist/docs/<entry file>`) — its files, and the wiring to keep. Most of that wiring passes `tsc` and `wix build` when wrong and fails only in the browser, which is why [Step 5's Preview](../../SKILL.md#validation) is not optional for a routed page.
|
|
32
26
|
|
|
33
|
-
|
|
27
|
+
Take the smallest template that covers what the request names. A settings area or an edit form nobody asked for is not "more complete" — [Step 4c's checklist](../../SKILL.md#step-4c-ux-completeness-self-audit) does not ask for one.
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
src/extensions/dashboard/pages/{feature}/
|
|
37
|
-
{feature}.extension.ts # single wix generate scaffold — always exactly one route registered here
|
|
38
|
-
{feature}.tsx # entry — Case C: Section 1 below. Cases A/B/D: DRAFT_TEMPLATE_ROUTER.md
|
|
39
|
-
{Feature}App.tsx # Case A/B/D only — see DRAFT_TEMPLATE_ROUTER.md
|
|
40
|
-
{Feature}CollectionPage.tsx # Case A, B, D — see DRAFT_TEMPLATE_COLLECTION.md
|
|
41
|
-
{Feature}DetailPage.tsx # Case A only — read-only detail route, DRAFT_TEMPLATE_ROUTER.md §4
|
|
42
|
-
{Feature}EntityPage.tsx # Case B, D only — see DRAFT_TEMPLATE_ROUTER.md
|
|
43
|
-
{Feature}SettingsPage.tsx # Case C, D only — see DRAFT_TEMPLATE_SETTINGS.md
|
|
44
|
-
{feature}-api.ts # fetch/save calls — keep these out of the components
|
|
45
|
-
```
|
|
29
|
+
## 3. Copy it into the extension
|
|
46
30
|
|
|
47
|
-
Scaffold
|
|
31
|
+
Scaffold once — every template is one extension, however many routes it has:
|
|
48
32
|
|
|
49
33
|
```bash
|
|
50
34
|
wix generate --params '{"extensionType":"DASHBOARD_PAGE","title":"<title>","route":"<route>"}'
|
|
51
35
|
```
|
|
52
36
|
|
|
53
|
-
|
|
37
|
+
`route` takes no leading slash — `support-tickets`, not `/support-tickets`. See [Dashboard Page → Scaffold](../DASHBOARD_PAGE.md#scaffold).
|
|
38
|
+
|
|
39
|
+
Then copy **every** file in `templateFiles` into the generated folder (`src/extensions/dashboard/pages/<feature>/`). They import one another by relative path, so keep their names relative to each other; one file on its own does not compile.
|
|
40
|
+
|
|
41
|
+
- The template's `page.tsx` is the entry file, and the CLI generated none by that name: put its contents into the component file the builder's `component` path points at (e.g. `employee-shifts.tsx`), and add no separate `page.tsx`, which nothing loads. Leave the builder file and the `src/extensions.ts` registration as the CLI wrote them.
|
|
42
|
+
- Rename `Items` / `Item` to your feature and entity, in file names and identifiers alike.
|
|
43
|
+
- Route paths stay page-relative (`/`, `/:id`, `/new`) — never prefix them with `<route>` ([DASHBOARD_PAGE.md](../DASHBOARD_PAGE.md)).
|
|
44
|
+
|
|
45
|
+
- **Theme the entry file.** In it, replace the template's `WixDesignSystemProvider` and its `@wix/design-system/styles.global.css` import with the app's `BusinessManagerTheme` — written once per app ([BUSINESS_MANAGER_THEME.md § 2](../BUSINESS_MANAGER_THEME.md#2-the-wrapper--write-this-file-once-per-app)), kept in the entry file so it sits above `WixPatternsProvider`. **Business Manager passes none of the redesign through the extension's iframe**, so the bare provider renders the pre-redesign look while `tsc`, `wix build` and `wix preview` all pass.
|
|
46
|
+
|
|
47
|
+
## 4. Replace the data file
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
Each template's data file (`items-api.ts`, `settings-api.ts`) is an in-memory stand-in with the signatures the pages call. Replace the bodies, keep the signatures:
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
import { withDashboard } from '@wix/patterns';
|
|
61
|
-
import { WixPatternsProvider } from '@wix/patterns/provider';
|
|
62
|
-
import { WixDesignSystemProvider } from '@wix/design-system';
|
|
63
|
-
import '@wix/design-system/styles.global.css';
|
|
64
|
-
import { {Feature}SettingsPage } from './{Feature}SettingsPage'; // DRAFT_TEMPLATE_SETTINGS.md
|
|
51
|
+
- **Whose data it is decides the call.** Data an existing Wix app owns comes from that app's SDK, never a CMS collection ([SDK-First Rule](../../SKILL.md#sdk-first-rule-existing-wix-app-data-is-never-cms)). The method and field names: [DATA_SOURCES.md](DATA_SOURCES.md). Filter paths, operators and cursor paging: [QUERY_AND_PAGING.md](QUERY_AND_PAGING.md).
|
|
52
|
+
- **A CMS collection uses the CMS template, which has no data file** — its `collection.ts` takes the full scoped id, `<app-namespace>/<idSuffix>` for a collection your extension ships ([DATA_COLLECTION.md](../DATA_COLLECTION.md)). The collection does not exist until the app is released ([LIFECYCLE.md](../data-collection/LIFECYCLE.md#the-extension-does-not-create-the-collection)).
|
|
53
|
+
- **On a CMS collection, the prompt's fields are the collection's fields** — every one a column, none hand-written. For a collection your extension ships, create exactly those fields; an existing site collection shows all its fields, and the user hides the rest in the column picker. A stated column list decides the columns only on the hand-wired path.
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
<WixDesignSystemProvider>
|
|
68
|
-
<WixPatternsProvider>
|
|
69
|
-
<{Feature}SettingsPage />
|
|
70
|
-
</WixPatternsProvider>
|
|
71
|
-
</WixDesignSystemProvider>
|
|
72
|
-
);
|
|
55
|
+
### Installing the CMS pair
|
|
73
56
|
|
|
74
|
-
|
|
57
|
+
`@wix/patterns-cms` pins one exact `@wix/patterns` version, and the template's page says why a second copy breaks the page silently.
|
|
58
|
+
|
|
59
|
+
**Already in `package.json`** (some app templates ship both): don't install it again — go straight to the check. **Not there:** install it, then align `@wix/patterns` to its pin:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @wix/patterns-cms
|
|
63
|
+
npm install @wix/patterns@$(node -p "require('@wix/patterns-cms/package.json').dependencies['@wix/patterns']")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Either way, confirm a single copy:**
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm dedupe
|
|
70
|
+
find node_modules -path '*@wix/patterns/package.json' -not -path '*/dist/*'
|
|
75
71
|
```
|
|
76
72
|
|
|
77
|
-
|
|
73
|
+
More than one line is a bug that `tsc` and `wix build` both pass. Declared ranges produce it when `@wix/patterns` ships ahead of `@wix/patterns-cms`, or a lockfile holds an older one. Run the second `npm install` line above, then the check again.
|
|
74
|
+
|
|
75
|
+
### Turning `query.search` into a query
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
On the hand-wired path the data file turns one search term into a filter over *several* fields — an OR. **This is where search ships broken**: it renders, it reaches the query, and still returns every row. (The CMS template's source does this itself.)
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
There is no shared free-text operator; the shape differs per endpoint. Read its *Supported Filters* page ([QUERY_AND_PAGING.md](QUERY_AND_PAGING.md#the-filterable-fields-are-a-closed-list-published-per-endpoint)), then `$or` one clause per identity field it lists. Never route the term to a single field by its shape — a measured run shipped this, and one branch is always dead:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
query = term.includes('@')
|
|
83
|
+
? query.startsWith('loginEmail', term)
|
|
84
|
+
: query.startsWith('contact.firstName', term); // a surname matches nothing, ever
|
|
85
|
+
```
|
|
85
86
|
|
|
86
|
-
|
|
87
|
+
`startsWith` is prefix-only too — "Smith" never finds "John Smith" — so prefer the containment operator when the endpoint declares one, and say which you used in `noResultsState`.
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
with the same field-controller patterns as the entity page.
|
|
89
|
+
**Whatever the shape, prove it narrows.** Run one term you expect to hit a known row and one you expect to hit nothing, and check the row count changes for both.
|
|
90
90
|
|
|
91
|
-
## What
|
|
91
|
+
## 5. What this skill adds to every template
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
| Detail fields, form field types, columns | The drill-in being a route, and the absence of a `SummaryBar` the request never asked for |
|
|
97
|
-
| Real data source (SDK-first per [SDK-First Rule](../../SKILL.md#sdk-first-rule-existing-wix-app-data-is-never-cms)) vs CMS | B/D wiring (provider/router nesting, `parentPath`, `location`): [DRAFT_TEMPLATE_ROUTER.md](DRAFT_TEMPLATE_ROUTER.md) |
|
|
93
|
+
- **No `SummaryBar` unless the request asked for one** — a named total, count or "how many / how much" figure. The templates ship without one on purpose ([SKILL.md § Step 2](../../SKILL.md)).
|
|
94
|
+
- **The state is MobX.** Deriving anything from the collection state in your own component — a header figure, a badge — goes through `useSelector` ([TABLE_STATE.md](TABLE_STATE.md#reading-state-outside-the-table-it-is-mobx)).
|
|
95
|
+
- **Anything the template does not show** — another filter type, a column renderer, a component the request needs — goes through [The Discovery Chain](../WIX_PATTERNS_DOCS.md#the-discovery-chain). A template replaces composing the shell, never the lookup for a symbol it does not contain.
|
|
@@ -136,49 +136,35 @@ This dashboard page manages dynamic parameters for an embedded script. The param
|
|
|
136
136
|
- Display the preview alongside the settings form using Layout and Cell components
|
|
137
137
|
- The preview should react to parameter changes in real-time
|
|
138
138
|
|
|
139
|
-
##
|
|
139
|
+
## Files to Generate
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
- src/extensions/dashboard/withProviders.tsx - Provider wrapper with WDS
|
|
143
|
-
- src/extensions/dashboard/pages/page.tsx - Dashboard page with parameter management (wrapped with withProviders)
|
|
144
|
-
- src/extensions/dashboard/components/site-popup-settings.tsx - Settings form component
|
|
145
|
-
- src/extensions/dashboard/types.ts - Type definitions
|
|
141
|
+
When dynamic parameters are present, generate all of these — the two wrapper files are not optional:
|
|
146
142
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
143
|
+
| File | Role |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| `dashboard/BusinessManagerTheme.tsx` | Theme wrapper — [BUSINESS_MANAGER_THEME.md § 2](../BUSINESS_MANAGER_THEME.md#2-the-wrapper--write-this-file-once-per-app) |
|
|
146
|
+
| `dashboard/withProviders.tsx` | Provider wrapper (below) |
|
|
147
|
+
| `dashboard/pages/page.tsx` | The page, exported wrapped in `withProviders` |
|
|
148
|
+
| `dashboard/types.ts` | Parameter type definitions |
|
|
149
|
+
| Component files | Settings forms, previews |
|
|
153
150
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
When dynamic parameters are present, you MUST generate these files:
|
|
157
|
-
1. src/extensions/dashboard/withProviders.tsx - Provider wrapper (REQUIRED for WDS)
|
|
158
|
-
2. src/extensions/dashboard/pages/page.tsx - The main dashboard page component
|
|
159
|
-
3. src/extensions/dashboard/types.ts - Type definitions for the parameters (if needed)
|
|
160
|
-
4. Any additional component files (settings forms, previews, etc.)
|
|
161
|
-
|
|
162
|
-
The withProviders.tsx is NOT optional - it must always be generated when there are dynamic parameters.
|
|
151
|
+
Parameters are saved as individual string fields, never as one JSON string, and converted back to their real types on load. Use `embeddedScripts` directly from `@wix/app-management`.
|
|
163
152
|
|
|
164
153
|
## Provider Wrapper Implementation
|
|
165
154
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
This file is REQUIRED to wrap dashboard components with the Wix Design System provider.
|
|
155
|
+
Generate `src/extensions/dashboard/withProviders.tsx`:
|
|
169
156
|
|
|
170
157
|
```typescript
|
|
171
158
|
import React from 'react';
|
|
172
|
-
import { WixDesignSystemProvider } from '@wix/design-system';
|
|
173
159
|
import { i18n } from '@wix/essentials';
|
|
160
|
+
import { BusinessManagerTheme } from './BusinessManagerTheme';
|
|
174
161
|
|
|
175
162
|
export default function withProviders<P extends {} = {}>(Component: React.FC<P>) {
|
|
176
163
|
return function DashboardProviders(props: P) {
|
|
177
|
-
const locale = i18n.getLocale();
|
|
178
164
|
return (
|
|
179
|
-
<
|
|
165
|
+
<BusinessManagerTheme locale={i18n.getLocale()}>
|
|
180
166
|
<Component {...props} />
|
|
181
|
-
</
|
|
167
|
+
</BusinessManagerTheme>
|
|
182
168
|
);
|
|
183
169
|
};
|
|
184
170
|
}
|
|
@@ -187,16 +173,16 @@ export default function withProviders<P extends {} = {}>(Component: React.FC<P>)
|
|
|
187
173
|
export { withProviders };
|
|
188
174
|
```
|
|
189
175
|
|
|
190
|
-
|
|
176
|
+
Business Manager passes none of the redesign through the extension's iframe, so a wrapper holding `WixDesignSystemProvider` alone renders the pre-redesign look while compiling and previewing cleanly. `features={{ newColorsBranding: true }}` predates the theme and does not substitute for it.
|
|
191
177
|
|
|
192
178
|
## Using Provider Wrapper
|
|
193
179
|
|
|
194
180
|
In your dashboard page component (page.tsx):
|
|
195
|
-
1.
|
|
181
|
+
1. `import withProviders from '../../withProviders';`
|
|
196
182
|
2. Import embeddedScripts from '@wix/app-management'
|
|
197
|
-
3.
|
|
198
|
-
4. Export
|
|
199
|
-
5.
|
|
183
|
+
3. Add no design-system providers in the page — `withProviders` owns them
|
|
184
|
+
4. Export wrapped: `export default withProviders(MyComponent);`
|
|
185
|
+
5. The component holds the Page and its content, not providers
|
|
200
186
|
|
|
201
187
|
Example structure:
|
|
202
188
|
```typescript
|
|
@@ -204,8 +190,7 @@ import { useEffect, useState, type FC } from 'react';
|
|
|
204
190
|
import { dashboard } from '@wix/dashboard';
|
|
205
191
|
import { embeddedScripts } from '@wix/app-management';
|
|
206
192
|
import { Page, Card, Button, ... } from '@wix/design-system';
|
|
207
|
-
import '
|
|
208
|
-
import withProviders from '../../withProviders';
|
|
193
|
+
import withProviders from '../../withProviders'; // owns the stylesheets and providers
|
|
209
194
|
|
|
210
195
|
const MyDashboardPage: FC = () => {
|
|
211
196
|
const [options, setOptions] = useState<MyScriptOptions>(defaultOptions);
|
|
@@ -253,9 +238,7 @@ export default withProviders(MyDashboardPage);
|
|
|
253
238
|
## Critical Notes
|
|
254
239
|
|
|
255
240
|
- Only implement UI for parameters that are relevant to your specific use case - ignore parameters that don't apply
|
|
256
|
-
- ALWAYS generate withProviders.tsx
|
|
257
|
-
- ALWAYS wrap the dashboard page export with withProviders()
|
|
258
|
-
- DO NOT use WixDesignSystemProvider directly in the dashboard page component - use withProviders instead
|
|
241
|
+
- ALWAYS generate `BusinessManagerTheme.tsx` and `withProviders.tsx`, and wrap the page export with `withProviders()` — no design-system providers in the page itself
|
|
259
242
|
- ALWAYS use embeddedScripts directly from '@wix/app-management'
|
|
260
243
|
- ALWAYS convert parameter values to strings when saving (embeddedScripts.embedScript must receive all string values in the parameters object)
|
|
261
244
|
- ALWAYS convert string parameters back to proper types when loading (e.g., 'true' -> true for booleans, string to number for numbers)
|
|
@@ -17,10 +17,12 @@ about tooling, not evidence about the collection.
|
|
|
17
17
|
|
|
18
18
|
## Reading the collection from a dashboard page
|
|
19
19
|
|
|
20
|
-
A page over a CMS collection
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
A page over a CMS collection uses the package's **CMS Collection and Entity Template**, not the
|
|
21
|
+
hand-wired one — the CMS already owns the field list, so `useCmsSchemaSource` supplies fetch,
|
|
22
|
+
filters, columns and the entity form from it. See
|
|
23
|
+
[DRAFT_TEMPLATE.md](../dashboard-page/DRAFT_TEMPLATE.md). Wiring
|
|
24
|
+
`items.query()` and hand-written columns by hand still compiles, and quietly gives up everything the
|
|
25
|
+
schema would have provided.
|
|
24
26
|
|
|
25
27
|
## The site must have CMS, or nothing is created at all
|
|
26
28
|
|
|
@@ -67,7 +67,7 @@ The verticals the skill operates end-to-end today: **stores · blog · cms · fo
|
|
|
67
67
|
|
|
68
68
|
### bookings — appointments and classes
|
|
69
69
|
- **Intent:** book / appointment / schedule / class / session / reserve a slot — a **service or appointment with a provider** (a stylist, trainer, tutor, clinic, studio).
|
|
70
|
-
- **Not bookings — route to `restaurants` instead:** a **table at a restaurant** is a Table Reservations concern, not a bookable service; and a **special dining occasion guests reserve** — a
|
|
70
|
+
- **Not bookings — route to `restaurants` instead:** a **table at a restaurant** is a Table Reservations concern, not a bookable service; and a **special dining occasion guests reserve** — a chef's table, cheese pairing, or tasting-menu evening at a restaurant — is a **restaurants → Table Reservations *experience*** (see the restaurants entry), **not** a bookings service. Reach for `bookings` only when what's booked is a standalone service/class with a provider, never a seat at a restaurant.
|
|
71
71
|
- **Not bookings — route to `rentals` instead:** when the **customer chooses how long** they want something, and what's booked is a **thing rather than a person** — a room by the hour, a desk for three days, a van for the weekend. The tell is a duration *range* the customer picks within. A 60-minute haircut is `bookings`; a meeting room booked for 1–8 hours is `rentals`.
|
|
72
72
|
- **Required site features:** a list of services; a page per service; a way to pick a time and book it.
|
|
73
73
|
- **Implementation checklist:** show each service's name, duration, and price; show the staff or provider; show the available time slots; a book action; a confirmation after booking.
|
|
@@ -85,8 +85,8 @@ The verticals the skill operates end-to-end today: **stores · blog · cms · fo
|
|
|
85
85
|
- **Implementation checklist:** show each plan's name, price, and billing cycle; list what each plan includes (the perks); a clear "choose plan" action; highlight a recommended tier where it makes sense.
|
|
86
86
|
|
|
87
87
|
### restaurants — menus and food
|
|
88
|
-
- **Intent:** menu / restaurant / cafe / food / dish list / order food / dine-in / **reserve a table** / a **special dining occasion guests reserve** (
|
|
89
|
-
- **Required site features:** a menu organized into sections; each item with a name, description, and price. **Add-ons, each on demand (separate apps/features; see `SETUP.md`):** online ordering, table reservations, and — **when the brief names special dining occasions** — **experiences** (a reservation that *is* a curated occasion at the restaurant, e.g. a
|
|
88
|
+
- **Intent:** menu / restaurant / cafe / food / dish list / order food / dine-in / **reserve a table** / a **special dining occasion guests reserve** (chef's table, cheese pairing, tasting-menu evening).
|
|
89
|
+
- **Required site features:** a menu organized into sections; each item with a name, description, and price. **Add-ons, each on demand (separate apps/features; see `SETUP.md`):** online ordering, table reservations, and — **when the brief names special dining occasions** — **experiences** (a reservation that *is* a curated occasion at the restaurant, e.g. a chef's table), which ride on the Table Reservations app.
|
|
90
90
|
- **Experiences vs bookings — decide here:** an **experience** is a **reservation that is itself a special dining occasion at the restaurant** — it books seats at the restaurant's own location and carries its own name, per-guest price, schedule, and booking form. Use it for pairing sessions, tastings, and chef's tables. Use the separate **`bookings`** vertical only for a **service/appointment/class with a provider** that isn't a seat at the restaurant. For anything a restaurant hosts and seats, prefer an experience.
|
|
91
91
|
- **Implementation checklist:** show the menu grouped into sections in order; each item's name, description, price, and labels (vegan, spicy…) and modifiers / variants where they exist; an order action if online ordering is wired; a reserve-a-table action if reservations are wired; **if experiences are wired, list each experience with its name, description, per-guest price, and schedule, and a reserve-seats action.**
|
|
92
92
|
|
|
@@ -52,7 +52,7 @@ For each capability, build its `intent.<cap>` block — the inputs the seed step
|
|
|
52
52
|
| bookings | `{ serviceCount, servicesNamed: [] }` | `serviceCount: 2`, brand-derived service names |
|
|
53
53
|
| rentals | `{ unitType, serviceCount, resourceCount, servicesNamed: [] }` | `unitType: "HOUR"` (`"DAY"` if the brief rents by the day), `serviceCount: 2`, `resourceCount: 2`, brand-derived item names |
|
|
54
54
|
| pricing-plans | `{ planCount, tiersNamed: [] }` | `planCount: 2` (e.g. Basic / Pro), monthly billing |
|
|
55
|
-
| restaurants | `{ menuName, sections: [{ name, itemCount }], ordering?, reservations?, experiences?: [{ name }] }` | one menu, 2 sections, `itemCount: 3` each; add-ons only when the brief names them. **`experiences[]`** = special dining occasions guests reserve (
|
|
55
|
+
| restaurants | `{ menuName, sections: [{ name, itemCount }], ordering?, reservations?, experiences?: [{ name }] }` | one menu, 2 sections, `itemCount: 3` each; add-ons only when the brief names them. **`experiences[]`** = special dining occasions guests reserve (chef's table, tasting menu) — a restaurant *reservation that is an experience*, **not** the `bookings` vertical (see `CAPABILITIES.md`). |
|
|
56
56
|
| portfolio | `{ collections: [{ name }], projectCount }` | one brand-derived collection, `projectCount: 3` |
|
|
57
57
|
|
|
58
58
|
Counts are deliberately small (the seed shows the shape, not a full catalog).
|
|
@@ -48,7 +48,7 @@ Before implementing a capability, Read the local recipe linked in its row.
|
|
|
48
48
|
| restaurants — online ordering (add-on; only when the Orders app is in the run) | add `@wix/ecom` + `@wix/redirects` to the row above | `how-to-code-restaurant-orders.md` — ordering cart/checkout on top of the menu display. |
|
|
49
49
|
| portfolio | `@wix/portfolio` (+ `media` from `@wix/sdk` to resolve image strings; **no** `@wix/ecom`/`@wix/redirects` — display-only) | `how-to-code-portfolio.md` — Portfolio v1 display-only read. |
|
|
50
50
|
| restaurants — table reservations (add-on; only when the Table Reservations app is in the run) | `@wix/table-reservations` (a **distinct** package from `@wix/restaurants`; **no ecom/redirects** — a reservation is a hold, not a purchase) | `how-to-code-restaurant-reservations.md` — book-a-table hold→reserve. |
|
|
51
|
-
| restaurants — experiences (add-on; special dining occasions guests reserve —
|
|
51
|
+
| restaurants — experiences (add-on; special dining occasions guests reserve — chef's table, tasting menu) | `@wix/table-reservations` (same package; the **`experiences`** namespace + `timeSlots`/`reservations`) | `how-to-code-restaurant-reservations.md` — "Booking an experience" (query experiences → scheduled slots → reserve with `experienceId`). |
|
|
52
52
|
|
|
53
53
|
> **Cross-cutting packages** (`CAPABILITIES.md` § "Cross-cutting capabilities"): these aren't per-vertical rows but get added to the package list when the run used them. If **coupons** were seeded, add `@wix/marketing`. The eCommerce checkout packages (`@wix/ecom`, `@wix/redirects`) are already folded into the stores row above — include them once when any purchase-flow vertical is present.
|
|
54
54
|
|
|
@@ -39,7 +39,7 @@ Each entry states only the entities, where their count/content comes from, the p
|
|
|
39
39
|
- **bookings** — *Bookable services.* Recipe: **`setup-bookings.md`**. `intent.bookings.serviceCount` services (name + short description fitting `brand`, a simple duration and price); keep the schedule minimal. **Keep:** `serviceIds[]` as **seed-time state** (pricing-plans' coverage step keys on them, below); nothing for the handoff — services are discovered **live** (`queryServices`).
|
|
40
40
|
- **rentals** — *Rentable resources.* Recipe: **`setup-rentals.md`**. A resource **type** per kind of thing rented (rooms, vans, cameras), then `intent.rentals.resourceCount` **resources** inside it (Room A / Room B — parallel capacity comes from more resources, not higher capacity), then `intent.rentals.serviceCount` **rental services**, each carrying the Wix Rentals `appId`, `serviceResources` naming its resource type, a `primaryResourceType`, and a `durationRange` (`HOUR` or `DAY`) with the min/max the request implies — defaulting to **60/480 minutes** hourly and **1/5 days** daily when the brief doesn't say — and a **per-unit** price. **No category** — unlike bookings, rental services don't use one; don't create or assign one. **Order is load-bearing: resource type → resources → services** — a service whose resource type holds no resources has permanently empty availability. Seed resources **24/7** (no working-hours schedule) unless the request names opening hours; that keeps a multi-day rental to a single booking. **Keep:** `resourceTypeIds[]` as seed-time state (services key on them); nothing for the handoff — rentals are discovered **live** (`queryServicesByFilters` filtered by the rentals `appId`).
|
|
41
41
|
- **pricing-plans** — *Membership tiers.* Recipe: **`setup-pricing-plans.md`**. `intent.pricing-plans.planCount` recurring plans (name, price, a monthly billing cycle) fitting `brand`. **When bookings is also in this run and the intent is a membership that covers services** (a studio/gym/class pass), also **attach the covered bookings services to the plan** — seed the bookings services first, since coverage keys on their service ids (see the recipe). **Keep:** the bookings coverage only transiently, to wire it during seeding; nothing for the handoff — plans are discovered **live** (`queryPlans`) and plan→service coverage is read **live** at checkout, never from a frozen map (see `how-to-code-pricing-plans.md`).
|
|
42
|
-
- **restaurants** — *A menu.* Recipe: **`setup-restaurants.md`** (add-ons have their own recipes, below). Create the `itemCount` items per section first (name, description, price fitting `brand`), then the `intent.restaurants.sections` referencing those item ids, then the menu referencing the section ids — **items → sections → menu** (build bottom-up: a section is created with its `itemIds`, a menu with its `sectionIds`, so each child must exist before its parent — see `setup-restaurants.md` STEP 1–3). Text-only. **Keep (seed-time only):** `menuId`, `sectionIds[]`, `itemIds[]` to build the tree; nothing goes to the handoff — the frontend reads menus **live** (`listMenus`/`listSections`/`listItems`). **Online ordering (add-on, on demand)** — only when the request calls for ordering (not just a displayed menu): install the Orders app (per `SETUP.md` §2) and follow **`setup-restaurant-orders.md`**; **seed the menu FIRST, then ordering, in the same unit** (ordering auto-provisions per menu either way — see the concurrency note above — but keeping them one unit gives the ordering verify a menu to confirm against). **Configure the business-location address (`setup-restaurant-orders.md` STEP 0) — required for ordering to work end-to-end; without it Wix limits ordering to "testing only" and checkout breaks.** If the brief gives no address, set a placeholder and flag the owner in the handoff. Completing a *paid* order additionally needs premium + a payment method (dashboard/premium — surface, don't fail). **Keep:** nothing for the handoff — read **live** (`listOperations`/`listFulfillmentMethods`); track `operationId`/`fulfillmentMethodIds[]` transiently. **Table reservations (add-on, on demand, INDEPENDENT of ordering/menu)** — only when the request calls for reservations: install the Table Reservations app (per `SETUP.md` §2) and follow **`setup-restaurant-reservations.md`**; **no menu dependency** (reservations bind to a location, not a menu — do NOT apply the menu-first rule) and **nothing to bulk-seed** (visitors create reservations at runtime); **configure the business-location address (`setup-restaurant-reservations.md` STEP 0)** — the reservation location is the site's business location, so set a real address (placeholder + owner flag if the brief names none; shared with ordering if both are present); enabling online reservations is **premium-gated** (record the precondition, don't fail). **Keep:** nothing for the handoff — read **live** (`listReservationLocations`); track `reservationLocationId` transiently. **Experiences (add-on within Table Reservations, on demand)** — only when the request names **special dining occasions guests reserve** (
|
|
42
|
+
- **restaurants** — *A menu.* Recipe: **`setup-restaurants.md`** (add-ons have their own recipes, below). Create the `itemCount` items per section first (name, description, price fitting `brand`), then the `intent.restaurants.sections` referencing those item ids, then the menu referencing the section ids — **items → sections → menu** (build bottom-up: a section is created with its `itemIds`, a menu with its `sectionIds`, so each child must exist before its parent — see `setup-restaurants.md` STEP 1–3). Text-only. **Keep (seed-time only):** `menuId`, `sectionIds[]`, `itemIds[]` to build the tree; nothing goes to the handoff — the frontend reads menus **live** (`listMenus`/`listSections`/`listItems`). **Online ordering (add-on, on demand)** — only when the request calls for ordering (not just a displayed menu): install the Orders app (per `SETUP.md` §2) and follow **`setup-restaurant-orders.md`**; **seed the menu FIRST, then ordering, in the same unit** (ordering auto-provisions per menu either way — see the concurrency note above — but keeping them one unit gives the ordering verify a menu to confirm against). **Configure the business-location address (`setup-restaurant-orders.md` STEP 0) — required for ordering to work end-to-end; without it Wix limits ordering to "testing only" and checkout breaks.** If the brief gives no address, set a placeholder and flag the owner in the handoff. Completing a *paid* order additionally needs premium + a payment method (dashboard/premium — surface, don't fail). **Keep:** nothing for the handoff — read **live** (`listOperations`/`listFulfillmentMethods`); track `operationId`/`fulfillmentMethodIds[]` transiently. **Table reservations (add-on, on demand, INDEPENDENT of ordering/menu)** — only when the request calls for reservations: install the Table Reservations app (per `SETUP.md` §2) and follow **`setup-restaurant-reservations.md`**; **no menu dependency** (reservations bind to a location, not a menu — do NOT apply the menu-first rule) and **nothing to bulk-seed** (visitors create reservations at runtime); **configure the business-location address (`setup-restaurant-reservations.md` STEP 0)** — the reservation location is the site's business location, so set a real address (placeholder + owner flag if the brief names none; shared with ordering if both are present); enabling online reservations is **premium-gated** (record the precondition, don't fail). **Keep:** nothing for the handoff — read **live** (`listReservationLocations`); track `reservationLocationId` transiently. **Experiences (add-on within Table Reservations, on demand)** — only when the request names **special dining occasions guests reserve** (chef's table, tasting menu, tasting-menu evening — an *experience*, not a `bookings` service; see `CAPABILITIES.md`): they need the **Table Reservations app** (no extra install) and a configured **business-location address** (`setup-restaurant-reservations.md` STEP 0, same as reservations) and, unlike plain reservations, they **are** seeded — create one Experience per named occasion on the default reservation location, following **`setup-restaurant-experiences.md`**. Booking an experience is **premium-gated** like online reservations (record the precondition, don't fail). **Keep:** nothing for the handoff — experiences are read **live** (`queryExperiences`); track `experienceId`(s) transiently.
|
|
43
43
|
- **portfolio** — *A project showcase.* Recipe: **`setup-portfolio.md`**. Create the `intent.portfolio.collections` (title + short description fitting `brand`), then `intent.portfolio.projectCount` projects assigned to them — **collections before projects** (a project's `collectionIds` must hold real collection ids; see the recipe). Text-only by default (omit `coverImage`; images only when `imagery` is on — §1, §4). **Keep (seed-time only):** `collectionIds{<name>}` to assign projects into their collections; nothing goes to the handoff — the frontend lists collections and projects **live** (`collections.queryCollections` / `projects.queryProjects`), so owner-added content appears with no code change.
|
|
44
44
|
|
|
45
45
|
> **Cross-cutting (on demand).** `coupons` is not a standalone capability (`CAPABILITIES.md` § "Cross-cutting capabilities") — there's no app to install and it's not in `verticals[]`. If intent calls for discounts **and** a parent vertical (stores / bookings / events / pricing-plans) is in this run, create coupons scoped to that parent and add the coupon to the `seeded` map (`seeded.coupons = { couponIds[] }`). **Coupons has no inline recipe** — read the create shape from the docs (`DOC_DISCOVERY.md` is the fallback): every coupon needs a scope with a namespace and its parent vertical's app installed (<https://dev.wix.com/docs/api-reference/business-solutions/coupons/about-wix-coupons.md>), and the create-coupon spec needs name/code/start + a scope namespace + exactly one coupon-type field (<https://dev.wix.com/docs/api-reference/business-solutions/coupons/coupons/create-a-coupon.md>). eCommerce needs no seeding — it's the runtime checkout layer that rides along.
|
|
@@ -25,7 +25,7 @@ For each capability in `verticals[]`, install its app by `appDefId` (these are t
|
|
|
25
25
|
- **bookings** → `13d21c63-b5ec-5912-8397-c3a5ddb27a97`
|
|
26
26
|
- **rentals** → `ff5d6eb1-65e4-4f9a-8b14-64d34c12cc2e` (Wix Rentals). Rentals provisions the Bookings infrastructure it runs on, so a Rentals-only install is enough — its availability comes back without adding Wix Bookings separately. Rentals has **no APIs of its own**: it is Services V2 with rentals-specific field values (`setup-rentals.md`), and its frontend package is `@wix/bookings` — there is no `@wix/rentals`. Rentals uses no categories; to also offer plain fixed-duration services, install Wix Bookings (`13d21c63-b5ec-5912-8397-c3a5ddb27a97`) as well, seed those with `setup-bookings.md`, and filter every catalog read by `appId` so the two sets stay separate.
|
|
27
27
|
- **pricing-plans** → `1522827f-c56c-a5c9-2ac9-00f9e6ae12d3`
|
|
28
|
-
- **restaurants** → `b278a256-2757-4f19-9313-c05c783bec92` (Wix Restaurants **Menus** — the seedable core). Online ordering and table reservations are **separate optional apps**, install only if intent calls for them: Orders (New) → `9a5d83fd-8570-482e-81ab-cfa88942ee60`, Table Reservations → `f9c07de2-5341-40c6-b096-8eb39de391fb`. **Experiences** (special dining occasions guests reserve —
|
|
28
|
+
- **restaurants** → `b278a256-2757-4f19-9313-c05c783bec92` (Wix Restaurants **Menus** — the seedable core). Online ordering and table reservations are **separate optional apps**, install only if intent calls for them: Orders (New) → `9a5d83fd-8570-482e-81ab-cfa88942ee60`, Table Reservations → `f9c07de2-5341-40c6-b096-8eb39de391fb`. **Experiences** (special dining occasions guests reserve — chef's tables, tasting menus; see `CAPABILITIES.md`) are a **feature of the Table Reservations app, not a separate install** — installing Table Reservations is all that's needed to create and book them (`setup-restaurant-experiences.md`).
|
|
29
29
|
- **portfolio** → `d90652a2-f5a1-4c7c-84c4-d4cdcc41f130` (Wix Portfolio; the install ships a default sample collection + projects — `setup-portfolio.md` STEP 0 cleans them)
|
|
30
30
|
- **cms** → **no install** (Wix Data is core) — skip
|
|
31
31
|
|
package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md
CHANGED
|
@@ -166,7 +166,7 @@ Doc: <https://dev.wix.com/docs/api-reference/business-solutions/restaurants/rese
|
|
|
166
166
|
|
|
167
167
|
### Booking an experience (only when experiences are in the run)
|
|
168
168
|
|
|
169
|
-
An **experience** is a reservation that *is* a curated dining occasion (
|
|
169
|
+
An **experience** is a reservation that *is* a curated dining occasion (chef's table, tasting menu). It uses the **same** booking mechanism as a table, with two differences: you **list experiences** to show and choose from, and you offer bookable times **projected from the experience's own schedule** (there is *no* experience-scoped slot API — see Gotcha C) rather than from `getScheduledTimeSlots`, then stamp the chosen `experienceId` onto the reservation. Read the shapes from the docs (`.md?apiView=SDK`); the earned drift gotchas below are what the docs won't tell you.
|
|
170
170
|
|
|
171
171
|
Flow (mirrors the docs' sample flow — <https://dev.wix.com/docs/api-reference/business-solutions/restaurants/reservations/experiences/sample-flows.md>):
|
|
172
172
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "Setup Restaurant Experiences"
|
|
3
|
-
description: Seeds Wix Table Reservations **Experiences** — a reservation that IS a special dining occasion at the restaurant (
|
|
3
|
+
description: Seeds Wix Table Reservations **Experiences** — a reservation that IS a special dining occasion at the restaurant (chef's table, cheese pairing, tasting-menu evening), as opposed to a plain table booking or a Bookings service. Points to the live docs for the full create payload and carries only the earned gotchas the docs don't state (field-shape drift, payment policy, premium gating, when-to-use). The occasions/prices/schedule come from the request.
|
|
4
4
|
---
|
|
5
5
|
**RECIPE**: Business Recipe – Experiences Setup for Wix Table Reservations (Experiences API)
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ description: Seeds Wix Table Reservations **Experiences** — a reservation that
|
|
|
8
8
|
|
|
9
9
|
## When to use experiences (and when NOT to)
|
|
10
10
|
|
|
11
|
-
An **experience** is a **reservation that is itself a curated dining occasion at the restaurant** — it books seats at the restaurant's own reservation location but overrides the location's defaults with its own name, description, per-guest payment policy, party-size, schedule, and booking form. Reach for it when the brief names a **
|
|
11
|
+
An **experience** is a **reservation that is itself a curated dining occasion at the restaurant** — it books seats at the restaurant's own reservation location but overrides the location's defaults with its own name, description, per-guest payment policy, party-size, schedule, and booking form. Reach for it when the brief names a **chef's table, cheese pairing, or tasting-menu evening**.
|
|
12
12
|
|
|
13
13
|
- **Experience vs plain reservation:** a plain reservation just books a table; an experience books a *named, scheduled, often paid occasion*. Same booking mechanism, different intent.
|
|
14
14
|
- **Experience vs `bookings`:** the separate `bookings` vertical is for a **service/appointment/class with a provider** (spa, tutor, studio). If a restaurant *hosts and seats* the occasion, it's an experience — not a booking. (See `CAPABILITIES.md` — "Experiences vs bookings".)
|
|
@@ -16,7 +16,7 @@ npx @wix/cli@latest whoami # exits 0 when logged in; non-zero when logged out
|
|
|
16
16
|
If it's non-zero, **log in yourself** — don't punt to the user and stop. A foreground command that exits in seconds, one JSON event per line:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
node ../../
|
|
19
|
+
node ../../scripts/bootstrap.mjs # path relative to this file
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
| Event | Do |
|
|
@@ -25,20 +25,9 @@ node ../../entry/bootstrap.mjs # path relative to this file
|
|
|
25
25
|
| `awaiting_user` (`verificationUri`, `userCode`, `message`) | Send `message` verbatim, then stop. Re-run the script when the user says they're done → `logged_in`. Re-running early returns the **same** code, not a new one. |
|
|
26
26
|
| `cli_unreachable` / `login_failed` (`detail`) | Show `detail` and stop. |
|
|
27
27
|
|
|
28
|
-
###
|
|
28
|
+
### What the script does
|
|
29
29
|
|
|
30
|
-
Read `../../
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
# AI_AGENT must be set, or the CLI renders an interactive Ink TUI and emits no JSON.
|
|
34
|
-
# Detach, redirecting to a FILE — a pipe dies with your process and the CLI gets EPIPE.
|
|
35
|
-
AI_AGENT=my-agent nohup npx -y @wix/cli@latest login > /tmp/wix-login.log 2>&1 &
|
|
36
|
-
|
|
37
|
-
grep -m1 awaiting_user /tmp/wix-login.log
|
|
38
|
-
# {"event":"awaiting_user","expiresInSeconds":600,"userCode":"…","verificationUri":"…"}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Send the user that URL + code, then stop — nothing moves until they act. The detached login lands the session on its own; resume with `whoami` (exit 0). Codes last ~10 min; after that, start a new login and surface the new code.
|
|
30
|
+
Read `../../scripts/bootstrap.mjs` if you want to see it: it sets `AI_AGENT` so the CLI emits JSON events instead of an interactive TUI, starts `wix login` detached with its output in a file under the OS temp dir (a pipe would die with the parent), and prints the device code. It is the one login path; there is no manual variant. Codes last ~10 min; after that, run it again and surface the new code.
|
|
42
31
|
|
|
43
32
|
## 2 · Mint the token
|
|
44
33
|
|