@tanstack/devtools 0.10.13 → 0.10.14
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/bin/intent.js +20 -0
- package/package.json +7 -2
- package/skills/devtools-app-setup/SKILL.md +359 -0
- package/skills/devtools-marketplace/SKILL.md +390 -0
- package/skills/devtools-plugin-panel/SKILL.md +429 -0
- package/skills/devtools-plugin-panel/references/panel-api.md +136 -0
- package/skills/devtools-production/SKILL.md +459 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools-marketplace
|
|
3
|
+
description: >
|
|
4
|
+
Publish plugin to npm and submit to TanStack Devtools Marketplace.
|
|
5
|
+
PluginMetadata registry format, plugin-registry.ts, pluginImport (importName, type),
|
|
6
|
+
requires (packageName, minVersion), framework tagging, multi-framework submissions,
|
|
7
|
+
featured plugins.
|
|
8
|
+
type: lifecycle
|
|
9
|
+
library: '@tanstack/devtools'
|
|
10
|
+
library_version: '0.10.12'
|
|
11
|
+
requires:
|
|
12
|
+
- devtools-plugin-panel
|
|
13
|
+
sources:
|
|
14
|
+
- docs/third-party-plugins.md
|
|
15
|
+
- packages/devtools/src/tabs/plugin-registry.ts
|
|
16
|
+
- packages/devtools/src/tabs/marketplace/types.ts
|
|
17
|
+
- packages/devtools/src/tabs/marketplace/plugin-utils.ts
|
|
18
|
+
- packages/devtools-vite/src/inject-plugin.ts
|
|
19
|
+
- packages/devtools-client/src/index.ts
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# TanStack Devtools Marketplace
|
|
23
|
+
|
|
24
|
+
> **Prerequisite:** Build a working plugin first using the **devtools-plugin-panel** skill. The marketplace submission assumes you already have a published npm package that exports either a JSX panel component or a function-based plugin.
|
|
25
|
+
|
|
26
|
+
## Overview
|
|
27
|
+
|
|
28
|
+
The TanStack Devtools Marketplace is a built-in registry inside the devtools shell. Users browse it from the Marketplace tab, and can install plugins with a single click. Submission is a PR to the `packages/devtools/src/tabs/plugin-registry.ts` file in the [TanStack/devtools](https://github.com/TanStack/devtools) repository.
|
|
29
|
+
|
|
30
|
+
## PluginMetadata Interface
|
|
31
|
+
|
|
32
|
+
Every marketplace entry conforms to the `PluginMetadata` interface exported from `packages/devtools/src/tabs/plugin-registry.ts`:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
export interface PluginMetadata {
|
|
36
|
+
/** Package name on npm (e.g., '@acme/react-analytics-devtools') */
|
|
37
|
+
packageName: string
|
|
38
|
+
|
|
39
|
+
/** Display title shown on the marketplace card */
|
|
40
|
+
title: string
|
|
41
|
+
|
|
42
|
+
/** Short description of what the plugin does */
|
|
43
|
+
description?: string
|
|
44
|
+
|
|
45
|
+
/** URL to a logo image (SVG, PNG, etc.) */
|
|
46
|
+
logoUrl?: string
|
|
47
|
+
|
|
48
|
+
/** Required base package dependency */
|
|
49
|
+
requires?: {
|
|
50
|
+
/** Required package name (e.g., '@tanstack/react-query') */
|
|
51
|
+
packageName: string
|
|
52
|
+
/** Minimum required version (semver) */
|
|
53
|
+
minVersion: string
|
|
54
|
+
/** Maximum version (if there's a known breaking change) */
|
|
55
|
+
maxVersion?: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Plugin import configuration -- enables one-click auto-install */
|
|
59
|
+
pluginImport?: {
|
|
60
|
+
/** The exact export name to import from the package
|
|
61
|
+
* (e.g., 'FormDevtoolsPlugin' or 'ReactQueryDevtoolsPanel') */
|
|
62
|
+
importName: string
|
|
63
|
+
/** 'jsx' = component rendered via { name, render: <Component /> }
|
|
64
|
+
* 'function' = called directly as FnName() in the plugins array */
|
|
65
|
+
type: 'jsx' | 'function'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Custom plugin ID for matching against registered plugins.
|
|
69
|
+
* The default behavior lowercases the package name and replaces
|
|
70
|
+
* non-alphanumeric characters with '-'.
|
|
71
|
+
* Example: pluginId: 'tanstack-form' matches 'tanstack-form-4'. */
|
|
72
|
+
pluginId?: string
|
|
73
|
+
|
|
74
|
+
/** URL to the plugin's documentation */
|
|
75
|
+
docsUrl?: string
|
|
76
|
+
|
|
77
|
+
/** Plugin author/maintainer */
|
|
78
|
+
author?: string
|
|
79
|
+
|
|
80
|
+
/** Repository URL */
|
|
81
|
+
repoUrl?: string
|
|
82
|
+
|
|
83
|
+
/** Framework this plugin supports */
|
|
84
|
+
framework: 'react' | 'solid' | 'vue' | 'svelte' | 'angular' | 'other'
|
|
85
|
+
|
|
86
|
+
/** Mark as featured -- appears in the Featured section with animated border.
|
|
87
|
+
* Reserved for official TanStack partners. */
|
|
88
|
+
featured?: boolean
|
|
89
|
+
|
|
90
|
+
/** Mark as new -- shows a "New" banner on the card */
|
|
91
|
+
isNew?: boolean
|
|
92
|
+
|
|
93
|
+
/** Tags for filtering and categorization */
|
|
94
|
+
tags?: Array<string>
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Required vs Optional Fields
|
|
99
|
+
|
|
100
|
+
Only two fields are strictly required by the TypeScript interface: `packageName`, `title`, and `framework`. In practice, always provide `requires`, `pluginImport`, and `description` -- without them the marketplace card is functional but auto-install cannot wire up the plugin.
|
|
101
|
+
|
|
102
|
+
## Registry Entry Examples
|
|
103
|
+
|
|
104
|
+
### React Plugin (function-based)
|
|
105
|
+
|
|
106
|
+
A function-based plugin exports a factory function that returns a plugin object. The auto-injector calls it as `FormDevtoolsPlugin()` inside the `plugins` array:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// In packages/devtools/src/tabs/plugin-registry.ts
|
|
110
|
+
|
|
111
|
+
'@acme/react-analytics-devtools': {
|
|
112
|
+
packageName: '@acme/react-analytics-devtools',
|
|
113
|
+
title: 'Acme Analytics Devtools',
|
|
114
|
+
description: 'Inspect analytics events, funnels, and session data',
|
|
115
|
+
requires: {
|
|
116
|
+
packageName: '@acme/react-analytics',
|
|
117
|
+
minVersion: '2.0.0',
|
|
118
|
+
},
|
|
119
|
+
pluginImport: {
|
|
120
|
+
importName: 'AnalyticsDevtoolsPlugin',
|
|
121
|
+
type: 'function',
|
|
122
|
+
},
|
|
123
|
+
pluginId: 'acme-analytics',
|
|
124
|
+
docsUrl: 'https://acme.dev/analytics/devtools',
|
|
125
|
+
repoUrl: 'https://github.com/acme/analytics',
|
|
126
|
+
author: 'Acme Corp',
|
|
127
|
+
framework: 'react',
|
|
128
|
+
isNew: true,
|
|
129
|
+
tags: ['Analytics', 'Tracking'],
|
|
130
|
+
},
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
When a user clicks "Install" in the marketplace, the Vite plugin:
|
|
134
|
+
|
|
135
|
+
1. Runs the package manager to install `@acme/react-analytics-devtools`
|
|
136
|
+
2. Finds the file containing `<TanStackDevtools />`
|
|
137
|
+
3. Adds `import { AnalyticsDevtoolsPlugin } from '@acme/react-analytics-devtools'`
|
|
138
|
+
4. Injects `AnalyticsDevtoolsPlugin()` into the `plugins` array
|
|
139
|
+
|
|
140
|
+
### React Plugin (JSX-based)
|
|
141
|
+
|
|
142
|
+
A JSX-based plugin exports a React component. The auto-injector wraps it in `{ name, render: <Component /> }`:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
'@acme/react-state-devtools': {
|
|
146
|
+
packageName: '@acme/react-state-devtools',
|
|
147
|
+
title: 'Acme State Inspector',
|
|
148
|
+
description: 'Real-time state tree visualization',
|
|
149
|
+
requires: {
|
|
150
|
+
packageName: '@acme/react-state',
|
|
151
|
+
minVersion: '1.5.0',
|
|
152
|
+
},
|
|
153
|
+
pluginImport: {
|
|
154
|
+
importName: 'AcmeStateDevtoolsPanel',
|
|
155
|
+
type: 'jsx',
|
|
156
|
+
},
|
|
157
|
+
author: 'Acme Corp',
|
|
158
|
+
framework: 'react',
|
|
159
|
+
tags: ['State Management'],
|
|
160
|
+
},
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The injected code looks like:
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import { AcmeStateDevtoolsPanel } from '@acme/react-state-devtools'
|
|
167
|
+
;<TanStackDevtools
|
|
168
|
+
plugins={[
|
|
169
|
+
{ name: 'Acme State Inspector', render: <AcmeStateDevtoolsPanel /> },
|
|
170
|
+
]}
|
|
171
|
+
/>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Multi-Framework Submission (React + Solid)
|
|
175
|
+
|
|
176
|
+
When your devtools package supports multiple frameworks, add one entry per framework. Each entry is keyed by its own npm package name:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
'@acme/react-analytics-devtools': {
|
|
180
|
+
packageName: '@acme/react-analytics-devtools',
|
|
181
|
+
title: 'Acme Analytics Devtools',
|
|
182
|
+
description: 'Inspect analytics events, funnels, and session data',
|
|
183
|
+
requires: {
|
|
184
|
+
packageName: '@acme/react-analytics',
|
|
185
|
+
minVersion: '2.0.0',
|
|
186
|
+
},
|
|
187
|
+
pluginImport: {
|
|
188
|
+
importName: 'AnalyticsDevtoolsPlugin',
|
|
189
|
+
type: 'function',
|
|
190
|
+
},
|
|
191
|
+
pluginId: 'acme-analytics',
|
|
192
|
+
author: 'Acme Corp',
|
|
193
|
+
framework: 'react',
|
|
194
|
+
isNew: true,
|
|
195
|
+
tags: ['Analytics', 'Tracking'],
|
|
196
|
+
},
|
|
197
|
+
'@acme/solid-analytics-devtools': {
|
|
198
|
+
packageName: '@acme/solid-analytics-devtools',
|
|
199
|
+
title: 'Acme Analytics Devtools',
|
|
200
|
+
description: 'Inspect analytics events, funnels, and session data',
|
|
201
|
+
requires: {
|
|
202
|
+
packageName: '@acme/solid-analytics',
|
|
203
|
+
minVersion: '2.0.0',
|
|
204
|
+
},
|
|
205
|
+
pluginImport: {
|
|
206
|
+
importName: 'AnalyticsDevtoolsPlugin',
|
|
207
|
+
type: 'function',
|
|
208
|
+
},
|
|
209
|
+
pluginId: 'acme-analytics',
|
|
210
|
+
author: 'Acme Corp',
|
|
211
|
+
framework: 'solid',
|
|
212
|
+
isNew: true,
|
|
213
|
+
tags: ['Analytics', 'Tracking'],
|
|
214
|
+
},
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The marketplace auto-detects the user's framework from their `package.json` dependencies and shows only matching entries. Users can still browse other frameworks via the filter controls.
|
|
218
|
+
|
|
219
|
+
## How Auto-Install Works
|
|
220
|
+
|
|
221
|
+
The auto-install pipeline lives in `packages/devtools-vite/src/inject-plugin.ts`. Understanding it clarifies why `pluginImport` matters:
|
|
222
|
+
|
|
223
|
+
1. **Package installation** -- The Vite plugin detects the project's package manager and runs the appropriate install command.
|
|
224
|
+
2. **File detection** -- It scans project files for imports from `@tanstack/react-devtools`, `@tanstack/solid-devtools`, `@tanstack/vue-devtools`, etc.
|
|
225
|
+
3. **AST transformation** -- It parses the file with Babel, finds the `<TanStackDevtools />` JSX element, and modifies the `plugins` prop.
|
|
226
|
+
4. **Import insertion** -- It adds `import { <importName> } from '<packageName>'` after the last existing import.
|
|
227
|
+
5. **Plugin injection** -- Based on `pluginImport.type`:
|
|
228
|
+
- `'function'`: Appends `ImportName()` directly to the plugins array
|
|
229
|
+
- `'jsx'`: Appends `{ name: '<title>', render: <ImportName /> }` to the plugins array
|
|
230
|
+
|
|
231
|
+
If `pluginImport` is missing, step 3-5 are skipped entirely. The package gets installed but the user must manually wire it into the `plugins` prop.
|
|
232
|
+
|
|
233
|
+
## PR Submission Process
|
|
234
|
+
|
|
235
|
+
1. **Publish your package to npm.** The marketplace links to npm for installation; the package must be publicly available.
|
|
236
|
+
|
|
237
|
+
2. **Fork and clone** the [TanStack/devtools](https://github.com/TanStack/devtools) repository.
|
|
238
|
+
|
|
239
|
+
3. **Edit `packages/devtools/src/tabs/plugin-registry.ts`.** Add your entry to the `PLUGIN_REGISTRY` object under the `THIRD-PARTY PLUGINS` comment section:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
// ==========================================
|
|
243
|
+
// THIRD-PARTY PLUGINS - Examples
|
|
244
|
+
// ==========================================
|
|
245
|
+
// External contributors can add their plugins below!
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
4. **Open a PR** against the `main` branch. Title format: `feat(marketplace): add <your-plugin-name>`.
|
|
249
|
+
|
|
250
|
+
5. **The PR will be reviewed** by TanStack maintainers. Common review feedback:
|
|
251
|
+
- Missing `pluginImport` -- reviewers will ask you to add it
|
|
252
|
+
- Missing `framework` -- required for marketplace filtering
|
|
253
|
+
- Missing `requires.minVersion` -- avoids runtime errors for users on older versions
|
|
254
|
+
- Incorrect `importName` -- must match the exact named export from your package
|
|
255
|
+
|
|
256
|
+
## Framework Detection
|
|
257
|
+
|
|
258
|
+
The marketplace determines the user's current framework by scanning their `package.json` dependencies for known framework packages:
|
|
259
|
+
|
|
260
|
+
| Framework | Detected packages |
|
|
261
|
+
| --------- | -------------------- |
|
|
262
|
+
| react | `react`, `react-dom` |
|
|
263
|
+
| solid | `solid-js` |
|
|
264
|
+
| vue | `vue`, `@vue/core` |
|
|
265
|
+
| svelte | `svelte` |
|
|
266
|
+
| angular | `@angular/core` |
|
|
267
|
+
|
|
268
|
+
Plugins with `framework: 'other'` are shown regardless of the detected framework.
|
|
269
|
+
|
|
270
|
+
## Featured Plugins
|
|
271
|
+
|
|
272
|
+
The `featured` field is reserved for official TanStack partners and select library authors. Featured plugins appear in a dedicated section at the top of the marketplace with an animated border.
|
|
273
|
+
|
|
274
|
+
To request featured status, email <partners+devtools@tanstack.com>.
|
|
275
|
+
|
|
276
|
+
Do not set `featured: true` in your PR submission -- it will be rejected. The TanStack team sets this flag.
|
|
277
|
+
|
|
278
|
+
## Plugin ID Matching
|
|
279
|
+
|
|
280
|
+
When the marketplace checks if a plugin is already active, it uses `pluginId` for matching. The matching logic in `packages/devtools/src/tabs/marketplace/plugin-utils.ts` does:
|
|
281
|
+
|
|
282
|
+
1. If `pluginId` is set, checks whether any registered plugin's ID starts with or contains the `pluginId` (case-insensitive).
|
|
283
|
+
2. Otherwise falls back to matching on `packageName` and extracting keyword segments.
|
|
284
|
+
|
|
285
|
+
Set a custom `pluginId` when your plugin registers with an ID that differs from the default (lowercased package name with non-alphanumeric characters replaced by `-`). For example, `@tanstack/react-form-devtools` registers as `tanstack-form-4` at runtime, so the registry entry uses `pluginId: 'tanstack-form'` to match it.
|
|
286
|
+
|
|
287
|
+
## Common Mistakes
|
|
288
|
+
|
|
289
|
+
### HIGH: Missing pluginImport metadata for auto-install
|
|
290
|
+
|
|
291
|
+
Without `pluginImport.importName` and `pluginImport.type`, the marketplace auto-install pipeline installs the npm package but cannot inject the plugin into the user's code. The user sees a successful install but the plugin tab never appears -- they must manually add the import and wire it into the `plugins` prop.
|
|
292
|
+
|
|
293
|
+
Wrong -- no pluginImport:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
'@acme/react-analytics-devtools': {
|
|
297
|
+
packageName: '@acme/react-analytics-devtools',
|
|
298
|
+
title: 'Acme Analytics Devtools',
|
|
299
|
+
requires: {
|
|
300
|
+
packageName: '@acme/react-analytics',
|
|
301
|
+
minVersion: '2.0.0',
|
|
302
|
+
},
|
|
303
|
+
author: 'Acme Corp',
|
|
304
|
+
framework: 'react',
|
|
305
|
+
},
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Correct -- pluginImport provided:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
'@acme/react-analytics-devtools': {
|
|
312
|
+
packageName: '@acme/react-analytics-devtools',
|
|
313
|
+
title: 'Acme Analytics Devtools',
|
|
314
|
+
requires: {
|
|
315
|
+
packageName: '@acme/react-analytics',
|
|
316
|
+
minVersion: '2.0.0',
|
|
317
|
+
},
|
|
318
|
+
pluginImport: {
|
|
319
|
+
importName: 'AnalyticsDevtoolsPlugin',
|
|
320
|
+
type: 'function',
|
|
321
|
+
},
|
|
322
|
+
author: 'Acme Corp',
|
|
323
|
+
framework: 'react',
|
|
324
|
+
},
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The `importName` must be the exact named export from your package. The `type` must match how the export is consumed:
|
|
328
|
+
|
|
329
|
+
- `'function'` if your export is a factory like `export function AnalyticsDevtoolsPlugin() { return { name: '...', ... } }`
|
|
330
|
+
- `'jsx'` if your export is a component like `export function AnalyticsDevtoolsPanel() { return <div>...</div> }`
|
|
331
|
+
|
|
332
|
+
### MEDIUM: Not specifying requires.minVersion
|
|
333
|
+
|
|
334
|
+
When `requires` is present but `minVersion` is omitted or set too low, users running older versions of the base package get runtime errors when the devtools plugin tries to access APIs that do not exist in their version.
|
|
335
|
+
|
|
336
|
+
Wrong -- missing minVersion:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
requires: {
|
|
340
|
+
packageName: '@acme/react-analytics',
|
|
341
|
+
},
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
This does not type-check -- `minVersion` is a required field inside `requires`. But setting it to `'0.0.0'` or an arbitrarily low version has the same practical effect: the marketplace shows the plugin as installable even when the user's version lacks the APIs your devtools plugin depends on.
|
|
345
|
+
|
|
346
|
+
Correct -- specify the actual minimum version your plugin is tested against:
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
requires: {
|
|
350
|
+
packageName: '@acme/react-analytics',
|
|
351
|
+
minVersion: '2.0.0',
|
|
352
|
+
},
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
If there is a known breaking change in a later version, also set `maxVersion`:
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
requires: {
|
|
359
|
+
packageName: '@acme/react-analytics',
|
|
360
|
+
minVersion: '2.0.0',
|
|
361
|
+
maxVersion: '3.0.0',
|
|
362
|
+
},
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
The marketplace uses semver comparison (`packages/devtools/src/tabs/semver-utils.ts`) to determine if the user's installed version satisfies the range. When it does not, the card shows a "Bump Version" action instead of "Install".
|
|
366
|
+
|
|
367
|
+
### MEDIUM: Submitting without framework field
|
|
368
|
+
|
|
369
|
+
The `framework` field enables marketplace filtering. Without it (or with it set incorrectly), users cannot find your plugin when browsing by framework, and the marketplace cannot determine whether to show it for the current project.
|
|
370
|
+
|
|
371
|
+
The framework is required by the TypeScript interface, so omitting it is a compile error. The real mistake is setting it to `'other'` when the plugin is framework-specific. A React-only plugin tagged `'other'` will appear for Solid, Vue, and Angular users who cannot use it.
|
|
372
|
+
|
|
373
|
+
Wrong:
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
framework: 'other', // but the plugin only works with React
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Correct:
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
framework: 'react',
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Use `'other'` only for truly framework-agnostic plugins that work in any environment.
|
|
386
|
+
|
|
387
|
+
## See Also
|
|
388
|
+
|
|
389
|
+
- **devtools-plugin-panel** -- Build a working devtools plugin panel before submitting to the marketplace
|
|
390
|
+
- **devtools-app-setup** -- TanStackDevtools component setup, plugins prop format, framework adapters
|