handoff-app 2.0.0-5 → 2.0.0-7
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 +174 -41
- package/UPGRADE.md +198 -0
- package/config/config.template.js +1 -4
- package/config/config.template.ts +1 -2
- package/dist/app-builder/build.js +11 -6
- package/dist/app-builder/client-config.js +1 -0
- package/dist/app-builder/config-diff/strategies/pattern.js +3 -3
- package/dist/app-builder/watchers/component.js +5 -5
- package/dist/app-builder/watchers/utils.d.ts +2 -3
- package/dist/app-builder/watchers.d.ts +8 -15
- package/dist/app-builder/watchers.js +53 -54
- package/dist/cache/build-cache.js +18 -22
- package/dist/catalog/define.d.ts +6 -0
- package/dist/catalog/define.js +72 -0
- package/dist/catalog/implementation.d.ts +27 -0
- package/dist/catalog/implementation.js +133 -0
- package/dist/catalog/index.d.ts +6 -0
- package/dist/catalog/index.js +22 -0
- package/dist/catalog/normalize.d.ts +16 -0
- package/dist/catalog/normalize.js +115 -0
- package/dist/catalog/previews.d.ts +18 -0
- package/dist/catalog/previews.js +106 -0
- package/dist/catalog/renderers.d.ts +43 -0
- package/dist/catalog/renderers.js +62 -0
- package/dist/catalog/types.d.ts +63 -0
- package/dist/cli/make.d.ts +0 -5
- package/dist/cli/make.js +22 -67
- package/dist/cli/scaffold.js +25 -33
- package/dist/commands/checkout/index.d.ts +7 -4
- package/dist/commands/checkout/index.js +9 -6
- package/dist/commands/compat/push-args.d.ts +2 -2
- package/dist/commands/index.js +0 -2
- package/dist/commands/publish/index.d.ts +9 -6
- package/dist/commands/publish/index.js +11 -8
- package/dist/commands/pull/index.js +1 -1
- package/dist/commands/push/index.js +1 -1
- package/dist/commands/utils.d.ts +15 -4
- package/dist/commands/utils.js +19 -6
- package/dist/config/catalog-include.d.ts +43 -0
- package/dist/config/catalog-include.js +203 -0
- package/dist/config/defaults.d.ts +2 -0
- package/dist/config/defaults.js +4 -1
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +6 -5
- package/dist/config/loader.js +9 -1
- package/dist/config/runtime.d.ts +5 -6
- package/dist/config/runtime.js +154 -154
- package/dist/handlebars.d.ts +9 -0
- package/dist/handlebars.js +16 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.js +29 -15
- package/dist/pattern.d.ts +7 -0
- package/dist/pattern.js +13 -0
- package/dist/react.d.ts +43 -0
- package/dist/react.js +11 -0
- package/dist/registry/asset-storage/define.d.ts +1 -1
- package/dist/registry/asset-storage/define.js +1 -1
- package/dist/registry/checkout/index.d.ts +9 -0
- package/dist/registry/checkout/index.js +335 -149
- package/dist/registry/db/schema.d.ts +34 -0
- package/dist/registry/db/schema.js +2 -0
- package/dist/registry/publish/index.d.ts +13 -2
- package/dist/registry/publish/index.js +109 -25
- package/dist/registry/publish/package.js +14 -1
- package/dist/registry/selection.d.ts +20 -0
- package/dist/registry/selection.js +37 -1
- package/dist/store/filesystem.d.ts +1 -1
- package/dist/store/filesystem.js +7 -7
- package/dist/store/registry.js +24 -3
- package/dist/transformers/plugins/csf-render.js +4 -2
- package/dist/transformers/plugins/ssr-render.js +14 -5
- package/dist/transformers/preview/component/api.d.ts +8 -0
- package/dist/transformers/preview/component/api.js +11 -15
- package/dist/transformers/preview/component/artifacts.d.ts +1 -1
- package/dist/transformers/preview/component/artifacts.js +11 -7
- package/dist/transformers/preview/component/builder.js +15 -18
- package/dist/transformers/preview/component/css.d.ts +2 -0
- package/dist/transformers/preview/component/css.js +8 -11
- package/dist/transformers/preview/component/html.js +18 -16
- package/dist/transformers/preview/component/javascript.js +2 -4
- package/dist/transformers/preview/pattern/builder.js +31 -18
- package/dist/transformers/preview/types.d.ts +15 -1
- package/dist/types/config.d.ts +36 -11
- package/docs/api.md +3 -0
- package/docs/cli.md +1 -1
- package/drizzle/0006_add_component_source_format.sql +3 -0
- package/drizzle/meta/0006_snapshot.json +1941 -0
- package/drizzle/meta/_journal.json +8 -1
- package/package.json +37 -2
- package/src/app/components/Component/Preview.tsx +36 -50
- package/src/app/components/CopyToClipboard.tsx +27 -26
- package/src/app/components/Layout/Header.tsx +4 -12
- package/src/app/components/Layout/RuntimeModeBadge.tsx +18 -0
- package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
- package/src/app/components/McpIntegration/McpConfigDialog.tsx +349 -0
- package/src/app/components/McpIntegration/McpIcon.tsx +10 -0
- package/src/app/components/Navigation/MobileNav.tsx +3 -1
- package/src/app/components/context/PreviewContext.tsx +5 -5
- package/src/app/components/ui/dialog.tsx +73 -0
- package/src/app/components/util/index.ts +7 -15
- package/src/app/lib/docs-api/backend.ts +5 -1
- package/src/app/lib/docs-api/page-discovery.ts +1 -6
- package/src/app/lib/docs-api/page-rendering.ts +21 -1
- package/src/app/lib/docs-api/records.ts +25 -10
- package/src/app/lib/docs-api/registry.ts +4 -2
- package/src/app/lib/docs-api/runtime-config.ts +5 -0
- package/src/app/lib/docs-api/search.ts +7 -2
- package/src/app/lib/mcp/auth.ts +64 -0
- package/src/app/lib/mcp/index.ts +2 -0
- package/src/app/lib/mcp/server.ts +343 -0
- package/src/app/lib/mcp/shape.ts +596 -0
- package/src/app/lib/registry-api/transfer.ts +7 -5
- package/src/app/next.config.mjs +3 -0
- package/src/app/pages/[...slug]/index.tsx +16 -30
- package/src/app/pages/api/mcp.ts +56 -0
- package/src/app/pages/index.tsx +10 -9
- package/src/app-builder/build.ts +12 -8
- package/src/app-builder/client-config.ts +2 -1
- package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
- package/src/app-builder/watchers/component.ts +3 -3
- package/src/app-builder/watchers/utils.ts +2 -3
- package/src/app-builder/watchers.ts +46 -50
- package/src/cache/build-cache.ts +11 -14
- package/src/catalog/README.md +92 -0
- package/src/catalog/define.ts +79 -0
- package/src/catalog/implementation.ts +145 -0
- package/src/catalog/index.ts +31 -0
- package/src/catalog/normalize.ts +143 -0
- package/src/catalog/previews.ts +111 -0
- package/src/catalog/renderers.ts +94 -0
- package/src/catalog/types.ts +74 -0
- package/src/cli/README.md +1 -1
- package/src/cli/make.ts +20 -72
- package/src/cli/scaffold.ts +25 -31
- package/src/commands/README.md +1 -1
- package/src/commands/checkout/index.ts +17 -7
- package/src/commands/compat/push-args.ts +2 -2
- package/src/commands/index.ts +0 -2
- package/src/commands/publish/index.ts +19 -9
- package/src/commands/pull/index.ts +2 -2
- package/src/commands/push/index.ts +2 -2
- package/src/commands/utils.ts +22 -7
- package/src/config/README.md +2 -1
- package/src/config/catalog-include.ts +227 -0
- package/src/config/defaults.ts +3 -0
- package/src/config/index.ts +4 -4
- package/src/config/loader.ts +12 -0
- package/src/config/runtime.ts +186 -191
- package/src/handlebars.ts +18 -0
- package/src/index.ts +39 -26
- package/src/pattern.ts +14 -0
- package/src/react.ts +52 -0
- package/src/registry/asset-storage/define.ts +1 -1
- package/src/registry/checkout/index.ts +416 -152
- package/src/registry/db/schema.ts +2 -0
- package/src/registry/publish/index.ts +123 -26
- package/src/registry/publish/package.ts +14 -1
- package/src/registry/selection.ts +44 -0
- package/src/store/filesystem.ts +4 -4
- package/src/store/registry.ts +13 -2
- package/src/transformers/plugins/csf-render.ts +4 -2
- package/src/transformers/plugins/ssr-render.ts +15 -5
- package/src/transformers/preview/component/api.ts +13 -1
- package/src/transformers/preview/component/artifacts.ts +8 -4
- package/src/transformers/preview/component/builder.ts +17 -4
- package/src/transformers/preview/component/css.ts +6 -10
- package/src/transformers/preview/component/html.ts +30 -19
- package/src/transformers/preview/component/javascript.ts +1 -3
- package/src/transformers/preview/pattern/builder.ts +33 -20
- package/src/transformers/preview/types.ts +15 -1
- package/src/types/config.ts +38 -11
- package/templates/default/README.md.tpl +10 -0
- package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
- package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
- package/templates/default/handoff.config.js.tpl +11 -18
- package/templates/default/handoff.config.ts.tpl +11 -18
- package/templates/default/handoff.config.with-examples.js.tpl +12 -16
- package/templates/default/handoff.config.with-examples.ts.tpl +12 -16
- package/config/templates/component/template.json +0 -49
- package/config/templates/template.html +0 -7
- package/dist/commands/make/template.d.ts +0 -8
- package/dist/commands/make/template.js +0 -43
- package/dist/config/entries.d.ts +0 -47
- package/dist/config/entries.js +0 -162
- package/dist/config/normalizers/declaration.d.ts +0 -11
- package/dist/config/normalizers/declaration.js +0 -122
- package/dist/config/normalizers/pattern.d.ts +0 -8
- package/dist/config/normalizers/pattern.js +0 -41
- package/dist/declarations/helpers.d.ts +0 -6
- package/dist/declarations/helpers.js +0 -19
- package/dist/declarations/index.d.ts +0 -2
- package/dist/declarations/index.js +0 -9
- package/dist/declarations/types.d.ts +0 -60
- package/src/commands/make/template.ts +0 -46
- package/src/config/entries.ts +0 -175
- package/src/config/normalizers/declaration.ts +0 -179
- package/src/config/normalizers/pattern.ts +0 -59
- package/src/declarations/helpers.ts +0 -36
- package/src/declarations/index.ts +0 -19
- package/src/declarations/types.ts +0 -70
- /package/dist/{declarations → catalog}/types.js +0 -0
package/README.md
CHANGED
|
@@ -66,11 +66,16 @@ my-handoff-project/
|
|
|
66
66
|
└─ out/ # build output; gitignored
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
##
|
|
69
|
+
## Catalog items
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
Every documented UI entry is a catalog item. Each item declares either an implementation or a composition of other items.
|
|
72
|
+
An implementation names its renderer. `defineCatalogItem` comes from the module for that renderer.
|
|
73
|
+
The declaration supplies stable identity, documentation metadata, source entries, and previews.
|
|
74
|
+
|
|
75
|
+
### React
|
|
76
|
+
|
|
77
|
+
Handoff finds the implementation file from its import, so you do not need to repeat the path.
|
|
78
|
+
Previews are named exports. `Preview<typeof item>` gives them the implementation's argument type.
|
|
74
79
|
|
|
75
80
|
```tsx
|
|
76
81
|
// components/example/Component.tsx
|
|
@@ -83,61 +88,136 @@ export default function Component({ label }: ComponentProps) {
|
|
|
83
88
|
}
|
|
84
89
|
```
|
|
85
90
|
|
|
86
|
-
```
|
|
87
|
-
// components/example/
|
|
88
|
-
import {
|
|
91
|
+
```tsx
|
|
92
|
+
// components/example/example.handoff.ts
|
|
93
|
+
import { defineCatalogItem, type Preview } from 'handoff-app/react';
|
|
89
94
|
import Component from './Component';
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
const item = defineCatalogItem({
|
|
92
97
|
id: 'component-id',
|
|
93
98
|
name: 'Component name',
|
|
94
99
|
description: 'Usage guidance for the component.',
|
|
95
100
|
group: 'Group name',
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
},
|
|
101
|
+
implementation: Component,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export default item;
|
|
105
|
+
|
|
106
|
+
type ComponentPreview = Preview<typeof item>;
|
|
107
|
+
|
|
108
|
+
export const Default = {
|
|
109
|
+
args: { label: 'Example' },
|
|
110
|
+
} satisfies ComponentPreview;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The export name is the preview name. Use `name` to set a different display title.
|
|
114
|
+
|
|
115
|
+
### Handlebars
|
|
116
|
+
|
|
117
|
+
The implementation is the path to the template. Arguments are `Record<string, unknown>` by default;
|
|
118
|
+
an explicit argument type is supplied through `defineCatalogItem<BadgeArgs>`.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
// components/badge/badge.handoff.ts
|
|
122
|
+
import { defineCatalogItem, type Preview } from 'handoff-app/handlebars';
|
|
123
|
+
|
|
124
|
+
const item = defineCatalogItem({
|
|
125
|
+
id: 'badge',
|
|
126
|
+
name: 'Badge',
|
|
127
|
+
implementation: './Badge.hbs',
|
|
105
128
|
});
|
|
129
|
+
|
|
130
|
+
export default item;
|
|
131
|
+
|
|
132
|
+
type BadgePreview = Preview<typeof item>;
|
|
133
|
+
|
|
134
|
+
export const Primary = {
|
|
135
|
+
args: { variant: 'primary', children: 'New' },
|
|
136
|
+
} satisfies BadgePreview;
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### CSF
|
|
140
|
+
|
|
141
|
+
CSF is a source format. A story file uses the renderer from the module that declares it. A React item references an existing CSF file with `fromCSF`.
|
|
142
|
+
The CSF file stays unchanged and defines its previews through named exports. Each story's `args` merge with and override `meta.args`.
|
|
143
|
+
Handoff preserves story names, `argTypes`, and `render` functions.
|
|
144
|
+
It finds the React component through `meta.component`, then documents and publishes it with the story file.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// components/card/card.handoff.ts
|
|
148
|
+
import { defineCatalogItem, fromCSF } from 'handoff-app/react';
|
|
149
|
+
|
|
150
|
+
export default defineCatalogItem({
|
|
151
|
+
id: 'card',
|
|
152
|
+
name: 'Card',
|
|
153
|
+
implementation: fromCSF('./Card.stories.tsx'),
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`Meta` and `StoryObj` are exported from `handoff-app/react`, so a story file type-checks without a
|
|
158
|
+
Storybook dependency. A project that already has Storybook keeps using its own types.
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
// components/card/Card.stories.tsx
|
|
162
|
+
import { type Meta, type StoryObj } from 'handoff-app/react';
|
|
163
|
+
import Card from './Card';
|
|
164
|
+
|
|
165
|
+
const meta = { component: Card } satisfies Meta<typeof Card>;
|
|
166
|
+
export default meta;
|
|
167
|
+
|
|
168
|
+
export const Primary: StoryObj<typeof meta> = {
|
|
169
|
+
args: { title: 'Example' },
|
|
170
|
+
};
|
|
106
171
|
```
|
|
107
172
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
173
|
+
A CSF preview is rendered on the server and is not hydrated. A direct React implementation is
|
|
174
|
+
hydrated in the browser.
|
|
175
|
+
|
|
176
|
+
### Compositions
|
|
177
|
+
|
|
178
|
+
A composition references other items by stable id. A named preview can be selected and its arguments
|
|
179
|
+
can be overridden by each reference. A composition needs no renderer, so it is declared with
|
|
180
|
+
`defineCatalogItem` from `handoff-app/pattern`.
|
|
111
181
|
|
|
112
182
|
```ts
|
|
113
|
-
// patterns/example/
|
|
114
|
-
import {
|
|
183
|
+
// patterns/example/example.handoff.ts
|
|
184
|
+
import { defineCatalogItem } from 'handoff-app/pattern';
|
|
115
185
|
|
|
116
|
-
export default
|
|
186
|
+
export default defineCatalogItem({
|
|
117
187
|
id: 'pattern-id',
|
|
118
188
|
name: 'Pattern name',
|
|
119
189
|
description: 'Purpose and usage of the composition.',
|
|
120
190
|
group: 'Group name',
|
|
121
|
-
|
|
122
|
-
{
|
|
123
|
-
|
|
124
|
-
preview: 'default',
|
|
125
|
-
args: { label: 'Pattern example' },
|
|
126
|
-
},
|
|
191
|
+
composition: [
|
|
192
|
+
{ ref: 'component-id', preview: 'Default' },
|
|
193
|
+
{ ref: 'badge', args: { children: 'Send' } },
|
|
127
194
|
],
|
|
128
195
|
});
|
|
129
196
|
```
|
|
130
197
|
|
|
131
|
-
|
|
198
|
+
An item declares `implementation` or `composition`, never both. Terms such as atom, element, and
|
|
199
|
+
block stay optional classification metadata on `type` and `categories`.
|
|
200
|
+
|
|
201
|
+
The `id` addresses the item everywhere: its artifacts, its documentation URL, and its publish and
|
|
202
|
+
checkout commands. Components and patterns share one namespace, so each id must be unique across
|
|
203
|
+
both.
|
|
204
|
+
|
|
205
|
+
If two declarations claim one id, Handoff keeps the first and skips the second. The warning names
|
|
206
|
+
both files. `publish` refuses to run until each id is unique.
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
### Registration
|
|
210
|
+
|
|
211
|
+
Catalog directories are registered in one place. A path is either an item directory or a collection
|
|
212
|
+
directory whose subdirectories are each treated as an item.
|
|
132
213
|
|
|
133
214
|
```ts
|
|
134
215
|
// handoff.config.ts
|
|
135
216
|
import { defineConfig } from 'handoff-app';
|
|
136
217
|
|
|
137
218
|
export default defineConfig({
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
patterns: ['patterns'],
|
|
219
|
+
catalog: {
|
|
220
|
+
include: ['components', 'patterns'],
|
|
141
221
|
},
|
|
142
222
|
runtime: {
|
|
143
223
|
workspace: {
|
|
@@ -147,6 +227,11 @@ export default defineConfig({
|
|
|
147
227
|
});
|
|
148
228
|
```
|
|
149
229
|
|
|
230
|
+
### Upgrade from version 1.x.x to version 2.x.x
|
|
231
|
+
|
|
232
|
+
See the [version 1.x.x to version 2.x.x migration guide](UPGRADE.md#version-1xx-to-version-2xx)
|
|
233
|
+
for breaking changes, migration steps, and upgrade verification.
|
|
234
|
+
|
|
150
235
|
Custom documentation pages are Markdown files under `pages/`. Their relative
|
|
151
236
|
paths become their routes and registry IDs.
|
|
152
237
|
|
|
@@ -340,20 +425,23 @@ npm run publish -- all
|
|
|
340
425
|
A single kind is published on its own:
|
|
341
426
|
|
|
342
427
|
```bash
|
|
343
|
-
npm run publish --
|
|
344
|
-
npm run publish -- patterns
|
|
428
|
+
npm run publish -- catalog
|
|
345
429
|
npm run publish -- pages
|
|
346
430
|
npm run publish -- tokens
|
|
347
431
|
npm run publish -- assets
|
|
348
432
|
```
|
|
349
433
|
|
|
434
|
+
`catalog` covers every catalog item. An item is stored as a component or as a
|
|
435
|
+
pattern, and its declaration decides which. The command names items and never a
|
|
436
|
+
kind.
|
|
437
|
+
|
|
350
438
|
Publishing tokens or assets runs the Figma data pipeline before upload, so the
|
|
351
439
|
documented Figma credentials must be available.
|
|
352
440
|
|
|
353
441
|
One or more IDs can be appended to narrow a publish to those entities:
|
|
354
442
|
|
|
355
443
|
```bash
|
|
356
|
-
npm run publish --
|
|
444
|
+
npm run publish -- catalog item-id another-id
|
|
357
445
|
```
|
|
358
446
|
|
|
359
447
|
`--dry-run` reports what would be uploaded and contacts no registry at all, so
|
|
@@ -363,16 +451,16 @@ the existing output, and the two combine to leave the workspace untouched:
|
|
|
363
451
|
|
|
364
452
|
```bash
|
|
365
453
|
npm run publish -- all --dry-run
|
|
366
|
-
npm run publish --
|
|
454
|
+
npm run publish -- catalog --no-build
|
|
367
455
|
```
|
|
368
456
|
|
|
369
457
|
`checkout` takes the same `all`, multi-ID, and `--dry-run` forms. A dry-run
|
|
370
458
|
checkout reads from the registry, lists the files it would create or overwrite,
|
|
371
459
|
and writes nothing.
|
|
372
460
|
|
|
373
|
-
After the registry is reloaded, the published
|
|
374
|
-
|
|
375
|
-
|
|
461
|
+
After the registry is reloaded, the published catalog items and foundations are
|
|
462
|
+
visible. Published database records are read by registry pages; the local
|
|
463
|
+
workspace is never read directly.
|
|
376
464
|
|
|
377
465
|
For CI, a registry connection and user-issued token are configured:
|
|
378
466
|
|
|
@@ -385,6 +473,51 @@ runtime: {
|
|
|
385
473
|
},
|
|
386
474
|
```
|
|
387
475
|
|
|
476
|
+
## MCP
|
|
477
|
+
|
|
478
|
+
The documentation app serves a Model Context Protocol endpoint at `/api/mcp/`, so
|
|
479
|
+
coding agents can look up the pages, components and tokens that already exist instead
|
|
480
|
+
of inventing markup and values. It is stateless Streamable HTTP over `POST`;
|
|
481
|
+
there is nothing to start and no extra port. Keep the trailing slash: the app
|
|
482
|
+
sets `trailingSlash: true`, so `/api/mcp` answers with a 308 redirect.
|
|
483
|
+
|
|
484
|
+
| Target | Endpoint | Credential |
|
|
485
|
+
| --- | --- | --- |
|
|
486
|
+
| Workspace (`dev` / `start`) | `http://localhost:3000/api/mcp/` | none, as with `/api/docs/*` |
|
|
487
|
+
| Registry (standalone or Vercel) | `<registry url>/api/mcp/` | an access token, read-only is enough |
|
|
488
|
+
| Static export | not available, a static site has no API routes | n/a |
|
|
489
|
+
|
|
490
|
+
Registry tokens come from `handoff-app login` or Account settings in the
|
|
491
|
+
registry itself, and are the same credentials the rest of the registry API takes.
|
|
492
|
+
|
|
493
|
+
The endpoint is served unless a project turns it off:
|
|
494
|
+
|
|
495
|
+
```ts
|
|
496
|
+
runtime: {
|
|
497
|
+
mcp: false,
|
|
498
|
+
},
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
Like `runtime.mode`, this is config-only and baked at build time, so changing it
|
|
502
|
+
in a deployed registry means a rebuild. A disabled build answers 404 on the route,
|
|
503
|
+
drops the MCP SDK from the packaged bundle, and shows no connect affordance at all
|
|
504
|
+
rather than one that fails.
|
|
505
|
+
|
|
506
|
+
The documentation app carries its own endpoint and a ready-made client config
|
|
507
|
+
for Claude Code, Cursor and VS Code behind the plug icon in the header. By hand:
|
|
508
|
+
|
|
509
|
+
```json
|
|
510
|
+
{
|
|
511
|
+
"mcpServers": {
|
|
512
|
+
"handoff": {
|
|
513
|
+
"type": "http",
|
|
514
|
+
"url": "https://registry.example.com/api/mcp/",
|
|
515
|
+
"headers": { "Authorization": "Bearer hnd_..." }
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
388
521
|
## Configuration
|
|
389
522
|
|
|
390
523
|
Configuration is read from `handoff.config.ts`, `.js`, `.cjs`, or `.json`, in
|
|
@@ -428,7 +561,7 @@ both.
|
|
|
428
561
|
| `npm run build -- [--target static\|registry]` | The static site or standalone registry bundle is built |
|
|
429
562
|
| `npm run db:migrate` | Registry database migrations are applied |
|
|
430
563
|
| `npm run validate` | Configured components are validated |
|
|
431
|
-
| `npm run publish -- <kind\|all> [id...]` |
|
|
564
|
+
| `npm run publish -- <kind\|all> [id...]` | Catalog items, pages, tokens, or assets are published |
|
|
432
565
|
| `npm run checkout -- <kind\|all> [id...]` | Published content is pulled into a workspace |
|
|
433
566
|
| `npm run login -- --url <url>` | The CLI is authorized through the registry device flow |
|
|
434
567
|
| `npm run logout -- [--url <url>]` | A saved CLI credential is revoked and removed |
|
package/UPGRADE.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Upgrade Handoff
|
|
2
|
+
|
|
3
|
+
This document contains migration steps for each major version upgrade.
|
|
4
|
+
|
|
5
|
+
## Version 1.x.x to version 2.x.x
|
|
6
|
+
|
|
7
|
+
This guide describes how to upgrade a Handoff project from version 1.x.x to version 2.x.x.
|
|
8
|
+
Each feature section identifies the affected projects and the required changes.
|
|
9
|
+
|
|
10
|
+
### Before you start
|
|
11
|
+
|
|
12
|
+
1. Verify that the project builds with its current Handoff version.
|
|
13
|
+
2. Save the project files, package version, and lockfile in version control.
|
|
14
|
+
3. Install the version 2.x.x package that you plan to use.
|
|
15
|
+
4. Apply the migration sections that affect your project.
|
|
16
|
+
|
|
17
|
+
### Breaking changes
|
|
18
|
+
|
|
19
|
+
| Change | Affected projects |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| [Catalog items](#catalog-items) | Projects with component or pattern declarations |
|
|
22
|
+
|
|
23
|
+
<!-- Add future breaking changes as feature sections before "Verify the upgrade". Add each section to this table. -->
|
|
24
|
+
|
|
25
|
+
### Catalog items
|
|
26
|
+
|
|
27
|
+
#### Affected projects
|
|
28
|
+
|
|
29
|
+
This change affects projects that use the old component or pattern registration API.
|
|
30
|
+
It also affects projects that use the deprecated API from an earlier version 2.x.x prerelease.
|
|
31
|
+
Version 2.x.x requires `defineCatalogItem` for implementations and compositions.
|
|
32
|
+
|
|
33
|
+
#### Register catalog directories
|
|
34
|
+
|
|
35
|
+
Move component and pattern directories from `entries` to `catalog.include`.
|
|
36
|
+
|
|
37
|
+
Version 1.x.x:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
entries: { components: ['components'], patterns: ['patterns'], scss: 'styles/main.scss' }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Version 2.x.x:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
catalog: { include: ['components', 'patterns'] },
|
|
47
|
+
entries: { scss: 'styles/main.scss' }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Each path can name one item directory or a collection of item directories. Global `entries.js` and `entries.scss` still work.
|
|
51
|
+
|
|
52
|
+
#### Convert declaration files
|
|
53
|
+
|
|
54
|
+
Use `<name>.handoff.ts`, `<name>.handoff.js`, or `<name>.handoff.cjs`.
|
|
55
|
+
Replace legacy filenames such as `button.json` or `button.js`.
|
|
56
|
+
|
|
57
|
+
Version 2.x.x does not support JSON item declarations, including `.handoff.json`.
|
|
58
|
+
JSON project config (`handoff.config.json`) remains supported.
|
|
59
|
+
|
|
60
|
+
If `runtime.workspace.declarationFormat` is `json`, change it to `ts`, `js`, or `cjs`. The default remains `ts`.
|
|
61
|
+
|
|
62
|
+
#### Replace declaration helpers
|
|
63
|
+
|
|
64
|
+
| Removed API | Replacement |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `defineReactComponent(Component, config)` | `defineCatalogItem({ ...config, implementation: Component })` from `handoff-app/react` |
|
|
67
|
+
| `defineHandlebarsComponent(config)` | `defineCatalogItem({ ...config, implementation: './Button.hbs' })` from `handoff-app/handlebars` |
|
|
68
|
+
| `defineCsfComponent(config)` | `defineCatalogItem({ ...config, implementation: fromCSF('./Button.stories.tsx') })` from `handoff-app/react` |
|
|
69
|
+
| `defineComponent(config)` | `defineCatalogItem({ ...config, implementation: './Button.tsx' })` from the module for its renderer |
|
|
70
|
+
| `definePattern({ components })` | `defineCatalogItem({ composition })` from `handoff-app/pattern` |
|
|
71
|
+
|
|
72
|
+
Remove the old `renderer`, `entries.component`, `entries.template`, and `entries.story` fields.
|
|
73
|
+
The implementation supplies the renderer and source file.
|
|
74
|
+
Keep the supporting `entries.js`, `entries.scss`, `entries.schema`, and `entries.templates` paths that your item uses.
|
|
75
|
+
Rename the metadata fields:
|
|
76
|
+
|
|
77
|
+
| Old field | Version 2.x.x field |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `title` | `name` |
|
|
80
|
+
| `should_do` | `shouldDo` |
|
|
81
|
+
| `should_not_do` | `shouldNotDo` |
|
|
82
|
+
|
|
83
|
+
##### React
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { defineCatalogItem, type Preview } from 'handoff-app/react';
|
|
87
|
+
import Button from './Button';
|
|
88
|
+
|
|
89
|
+
const item = defineCatalogItem({
|
|
90
|
+
name: 'Button',
|
|
91
|
+
implementation: Button,
|
|
92
|
+
entries: { scss: './button.scss' },
|
|
93
|
+
});
|
|
94
|
+
export default item;
|
|
95
|
+
export const Primary = { args: { children: 'Save' } } satisfies Preview<typeof item>;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Imported components retain their prop types. A file path also works: `implementation: './Button.tsx'`.
|
|
99
|
+
Keep implementation files inside the item directory to publish them.
|
|
100
|
+
|
|
101
|
+
##### Handlebars and CommonJS
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
const { defineCatalogItem } = require('handoff-app/handlebars');
|
|
105
|
+
|
|
106
|
+
exports.default = defineCatalogItem({
|
|
107
|
+
name: 'Badge',
|
|
108
|
+
implementation: './Badge.hbs',
|
|
109
|
+
});
|
|
110
|
+
exports.Primary = { args: { children: 'New' } };
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Use this form in `.handoff.js` or `.handoff.cjs`. JavaScript declarations can also use `import` and `export`.
|
|
114
|
+
|
|
115
|
+
##### CSF
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { defineCatalogItem, fromCSF } from 'handoff-app/react';
|
|
119
|
+
|
|
120
|
+
export default defineCatalogItem({
|
|
121
|
+
name: 'Button',
|
|
122
|
+
implementation: fromCSF('./Button.stories.tsx'),
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
CSF is a React source format. The story file supplies the previews.
|
|
127
|
+
The filename does not select CSF automatically.
|
|
128
|
+
|
|
129
|
+
##### Compositions
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { defineCatalogItem } from 'handoff-app/pattern';
|
|
133
|
+
|
|
134
|
+
export default defineCatalogItem({
|
|
135
|
+
name: 'Toolbar',
|
|
136
|
+
composition: [{ ref: 'button', preview: 'Primary', args: { children: 'Save' } }],
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Rename `components` to `composition`.
|
|
141
|
+
Rename each member's `id` to `ref`.
|
|
142
|
+
Keep item IDs stable.
|
|
143
|
+
|
|
144
|
+
#### Export previews
|
|
145
|
+
|
|
146
|
+
Remove the inline `previews` map.
|
|
147
|
+
Export each preview beside the default catalog item.
|
|
148
|
+
Rename preview `title` to `name`.
|
|
149
|
+
Rename `values` to `args`:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
export const Primary = { name: 'Primary action', args: { children: 'Save' } };
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If a preview key is a valid export name, preserve its spelling and capitalization.
|
|
156
|
+
If a key is not a valid export name, rename it.
|
|
157
|
+
Update composition references to each renamed preview.
|
|
158
|
+
|
|
159
|
+
Previews appear in source export order.
|
|
160
|
+
|
|
161
|
+
For CommonJS declarations, use `exports.default` for the item.
|
|
162
|
+
Use a named export such as `exports.Primary` for each preview.
|
|
163
|
+
|
|
164
|
+
#### Replace declaration types
|
|
165
|
+
|
|
166
|
+
Replace imports of the removed types:
|
|
167
|
+
|
|
168
|
+
| Removed type | Replacement |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `Component` | `CatalogItem` |
|
|
171
|
+
| `DeclarationPreview` | `CatalogPreview` or `Preview<typeof item>` |
|
|
172
|
+
| `PatternComponentRef` | `CompositionRef` |
|
|
173
|
+
| `ReactDeclarationConfig`, `HandlebarsDeclarationConfig`, `CsfDeclarationConfig` | The catalog helper's input type |
|
|
174
|
+
| `GenericDeclarationConfig`, `GenericPatternDeclarationConfig` | The catalog helper's input type, or `CatalogItemMeta` for shared metadata |
|
|
175
|
+
|
|
176
|
+
`RendererKind` comes from the catalog API and contains `react` and `handlebars`.
|
|
177
|
+
CSF uses `renderer: 'react'` with `format: 'csf'` inside `implementation`.
|
|
178
|
+
|
|
179
|
+
#### Registry projects
|
|
180
|
+
|
|
181
|
+
Checkout writes only catalog declarations.
|
|
182
|
+
Registry records require explicit renderer and source-format metadata where applicable.
|
|
183
|
+
|
|
184
|
+
### Verify the upgrade
|
|
185
|
+
|
|
186
|
+
After you apply the required migrations, verify the project:
|
|
187
|
+
|
|
188
|
+
1. Build the project with version 2.x.x.
|
|
189
|
+
2. Verify that all expected catalog items appear in the documentation.
|
|
190
|
+
3. Verify the preview order, arguments, and composition references.
|
|
191
|
+
4. Start the workspace with file watchers.
|
|
192
|
+
5. Edit a declaration to verify that its previews update.
|
|
193
|
+
|
|
194
|
+
If the project uses a registry, verify the published items:
|
|
195
|
+
|
|
196
|
+
1. Publish the migrated items.
|
|
197
|
+
2. Verify that checkout produces valid declarations.
|
|
198
|
+
3. Rebuild the checked-out items.
|
|
@@ -54,13 +54,10 @@ const config = {
|
|
|
54
54
|
ports: { app: 3000, websocket: 3001 },
|
|
55
55
|
},
|
|
56
56
|
// These are the entry points used to compile the target application
|
|
57
|
+
catalog: { include: ['./components'] },
|
|
57
58
|
entries: {
|
|
58
59
|
scss: './sass/main.scss',
|
|
59
60
|
js: './js/main.js',
|
|
60
|
-
components: ['./components'],
|
|
61
|
-
// Uncomment to enable pattern documentation pages.
|
|
62
|
-
// Patterns compose component previews into single-page views.
|
|
63
|
-
// patterns: ['./patterns'],
|
|
64
61
|
},
|
|
65
62
|
// These are the asset zip file download links
|
|
66
63
|
assetsZipLinks: {
|
|
@@ -34,11 +34,10 @@ export default defineConfig({
|
|
|
34
34
|
},
|
|
35
35
|
ports: { app: 3000, websocket: 3001 },
|
|
36
36
|
},
|
|
37
|
+
catalog: { include: ['./components'] },
|
|
37
38
|
entries: {
|
|
38
39
|
scss: './sass/main.scss',
|
|
39
40
|
js: './js/main.js',
|
|
40
|
-
components: ['./components'],
|
|
41
|
-
// patterns: ['./patterns'],
|
|
42
41
|
},
|
|
43
42
|
assetsZipLinks: {
|
|
44
43
|
icons: null,
|
|
@@ -40,6 +40,7 @@ const p = __importStar(require("@clack/prompts"));
|
|
|
40
40
|
const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
|
41
41
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
42
42
|
const path_1 = __importDefault(require("path"));
|
|
43
|
+
const config_1 = require("../config");
|
|
43
44
|
const components_1 = require("../pipeline/components");
|
|
44
45
|
const patterns_1 = require("../pipeline/patterns");
|
|
45
46
|
const resolve_1 = require("../registry/asset-storage/resolve");
|
|
@@ -216,6 +217,7 @@ const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handof
|
|
|
216
217
|
// Resolved runtime mode + registry connection inputs (names only) baked into the Next bundle so the
|
|
217
218
|
// deployed registry app resolves its mode/DB env-var name without any build-machine filesystem.
|
|
218
219
|
const escapedRuntimeMode = escapeForSingleQuotedJsString(runtimeMode);
|
|
220
|
+
const escapedMcpEnabled = escapeForSingleQuotedJsString(String((0, config_1.isMcpEnabled)(handoff.config)));
|
|
219
221
|
const escapedRegistryDriver = escapeForSingleQuotedJsString((0, driver_1.resolveRegistryDriver)(handoff.config));
|
|
220
222
|
const escapedDatabaseUrlEnv = escapeForSingleQuotedJsString((0, driver_1.resolveDatabaseUrlEnv)(handoff.config));
|
|
221
223
|
// Asset storage selection baked (provider + module + env-var names + non-secret options JSON).
|
|
@@ -233,6 +235,7 @@ const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handof
|
|
|
233
235
|
'%HANDOFF_EXPORT_PATH%': escapedExportPath,
|
|
234
236
|
'%HANDOFF_WEBSOCKET_PORT%': escapedWebsocketPort,
|
|
235
237
|
'%HANDOFF_RUNTIME_MODE%': escapedRuntimeMode,
|
|
238
|
+
'%HANDOFF_MCP_ENABLED%': escapedMcpEnabled,
|
|
236
239
|
'%HANDOFF_REGISTRY_DRIVER%': escapedRegistryDriver,
|
|
237
240
|
'%HANDOFF_REGISTRY_DATABASE_URL_ENV%': escapedDatabaseUrlEnv,
|
|
238
241
|
'%HANDOFF_ASSET_STORAGE_ADAPTER%': escapedAssetStorageAdapter,
|
|
@@ -426,12 +429,16 @@ containers, custom Node servers, and other non-Vercel hosts.
|
|
|
426
429
|
/**
|
|
427
430
|
* Resolve the set of npm packages the packaged registry app must be able to `require`/`import` at
|
|
428
431
|
* runtime, given the configured database driver. `next`/`react`/`react-dom` run the server and React
|
|
429
|
-
* runtime; `drizzle-orm` backs both the request-time DB client and the migration runner; the
|
|
430
|
-
*
|
|
432
|
+
* runtime; `drizzle-orm` backs both the request-time DB client and the migration runner; the MCP SDK
|
|
433
|
+
* (and its `zod` peer) is only needed when `/api/mcp/` is enabled; the driver package is
|
|
434
|
+
* driver-specific (the Neon serverless driver also needs `ws` for its Node WebSocket transport).
|
|
431
435
|
*/
|
|
432
436
|
const getRequiredRegistryRuntimeModules = (handoff) => {
|
|
433
437
|
var _a;
|
|
434
438
|
const base = ['next', 'next-auth', 'react', 'react-dom', 'drizzle-orm'];
|
|
439
|
+
if ((0, config_1.isMcpEnabled)(handoff.config)) {
|
|
440
|
+
base.push('@modelcontextprotocol/sdk', 'zod');
|
|
441
|
+
}
|
|
435
442
|
const driver = (0, driver_1.resolveRegistryDriver)(handoff.config);
|
|
436
443
|
const driverModules = driver === 'neon' ? ['@neondatabase/serverless', 'ws'] : ['pg'];
|
|
437
444
|
// Asset-storage SDKs the deployed registry must be able to load at request time. The pre-packaged
|
|
@@ -688,14 +695,12 @@ const watchApp = (handoff) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
688
695
|
pendingHandlers: new Map(),
|
|
689
696
|
runtimeComponentsWatcher: null,
|
|
690
697
|
runtimeConfigurationWatcher: null,
|
|
691
|
-
|
|
692
|
-
patternDirectoriesWatcher: null,
|
|
698
|
+
catalogDirectoriesWatcher: null,
|
|
693
699
|
};
|
|
694
700
|
(0, watchers_1.watchPublicDirectory)(handoff, wss, state, chokidarConfig);
|
|
695
701
|
(0, watchers_1.watchRuntimeComponents)(handoff, state, (0, watchers_1.getRuntimeComponentsPathsToWatch)(handoff));
|
|
696
702
|
(0, watchers_1.watchRuntimeConfiguration)(handoff, state);
|
|
697
|
-
(0, watchers_1.
|
|
698
|
-
(0, watchers_1.watchPatternDirectories)(handoff, state, chokidarConfig);
|
|
703
|
+
(0, watchers_1.watchCatalogDirectories)(handoff, state, chokidarConfig);
|
|
699
704
|
(0, watchers_1.watchGlobalEntries)(handoff, state, chokidarConfig);
|
|
700
705
|
(0, watchers_1.watchPages)(handoff, chokidarConfig);
|
|
701
706
|
});
|
|
@@ -65,6 +65,7 @@ const buildServerRuntimeConfig = (config, modeOverride) => {
|
|
|
65
65
|
const assetStorage = (0, resolve_1.resolveAssetStorageFromConfig)(config);
|
|
66
66
|
return {
|
|
67
67
|
mode: (_b = modeOverride !== null && modeOverride !== void 0 ? modeOverride : (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'workspace',
|
|
68
|
+
mcp: (0, config_1.isMcpEnabled)(config),
|
|
68
69
|
registry: {
|
|
69
70
|
driver: (0, driver_1.resolveRegistryDriver)(config),
|
|
70
71
|
databaseUrlEnv: (0, driver_1.resolveDatabaseUrlEnv)(config),
|
|
@@ -43,12 +43,12 @@ const snapshot_1 = require("../snapshot");
|
|
|
43
43
|
* components. Outer key is component id, inner key is synthetic preview key.
|
|
44
44
|
*/
|
|
45
45
|
const snapshotPatternSynthetics = (handoff, patternId) => {
|
|
46
|
-
var _a, _b, _c
|
|
47
|
-
const components = (
|
|
46
|
+
var _a, _b, _c;
|
|
47
|
+
const components = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
|
|
48
48
|
const prefix = `__pattern_${patternId}_`;
|
|
49
49
|
const result = new Map();
|
|
50
50
|
for (const [componentId, component] of Object.entries(components)) {
|
|
51
|
-
const previews = (
|
|
51
|
+
const previews = (_c = component.internalPatternPreviews) !== null && _c !== void 0 ? _c : {};
|
|
52
52
|
const entries = new Map();
|
|
53
53
|
for (const [key, preview] of Object.entries(previews)) {
|
|
54
54
|
if (key.startsWith(prefix)) {
|
|
@@ -23,11 +23,11 @@ const mapEntryTypeToSegment = (type) => {
|
|
|
23
23
|
};
|
|
24
24
|
exports.mapEntryTypeToSegment = mapEntryTypeToSegment;
|
|
25
25
|
const resolveComponentIdForChangedFile = (handoff, changedFilePath) => {
|
|
26
|
-
var _a, _b, _c
|
|
26
|
+
var _a, _b, _c;
|
|
27
27
|
const normalizedChangedPath = (0, path_2.normalizePathForCompare)(changedFilePath);
|
|
28
|
-
const runtimeComponents = (
|
|
28
|
+
const runtimeComponents = (_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {};
|
|
29
29
|
for (const [componentId, componentDef] of Object.entries(runtimeComponents)) {
|
|
30
|
-
const entries = (
|
|
30
|
+
const entries = (_c = componentDef.entries) !== null && _c !== void 0 ? _c : {};
|
|
31
31
|
for (const entryPath of Object.values(entries)) {
|
|
32
32
|
if (!entryPath)
|
|
33
33
|
continue;
|
|
@@ -49,8 +49,8 @@ exports.resolveComponentIdForChangedFile = resolveComponentIdForChangedFile;
|
|
|
49
49
|
const getRuntimeComponentsPathsToWatch = (handoff) => {
|
|
50
50
|
var _a, _b, _c;
|
|
51
51
|
const result = new Map();
|
|
52
|
-
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.
|
|
53
|
-
const runtimeComponent = handoff.runtimeConfig.
|
|
52
|
+
for (const runtimeComponentId of Object.keys((_b = (_a = handoff.runtimeConfig) === null || _a === void 0 ? void 0 : _a.entities.components) !== null && _b !== void 0 ? _b : {})) {
|
|
53
|
+
const runtimeComponent = handoff.runtimeConfig.entities.components[runtimeComponentId];
|
|
54
54
|
for (const [runtimeComponentEntryType, runtimeComponentEntryPath] of Object.entries((_c = runtimeComponent.entries) !== null && _c !== void 0 ? _c : {})) {
|
|
55
55
|
const normalizedComponentEntryPath = runtimeComponentEntryPath;
|
|
56
56
|
if (fs_extra_1.default.existsSync(normalizedComponentEntryPath)) {
|
|
@@ -4,9 +4,8 @@ export interface WatcherState {
|
|
|
4
4
|
pendingHandlers: Map<string, () => Promise<void>>;
|
|
5
5
|
runtimeComponentsWatcher: chokidar.FSWatcher | null;
|
|
6
6
|
runtimeConfigurationWatcher: chokidar.FSWatcher | null;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
patternDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
7
|
+
/** Watches every registered catalog directory for newly created item subdirectories. */
|
|
8
|
+
catalogDirectoriesWatcher: chokidar.FSWatcher | null;
|
|
10
9
|
}
|
|
11
10
|
/**
|
|
12
11
|
* Schedules a handler for execution with mutual exclusion and per-source
|