@rahul_ur/devlink 1.0.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 +168 -0
- package/bin/cli.mjs +285 -0
- package/index.d.ts +5 -0
- package/index.js +6 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# devlink
|
|
2
|
+
|
|
3
|
+
Click any element in your browser → jump to its source code → edit it → UI updates live.
|
|
4
|
+
|
|
5
|
+
Works with **Vite**, **Next.js**, and **CRA**. Fully local — no cloud, no API keys.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @rahul_ur/devlink
|
|
13
|
+
npm install -D @rahul_ur/devlink-babel-plugin @rahul_ur/devlink-vite-plugin
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Setup (one command)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx devlink setup
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This automatically:
|
|
25
|
+
- Detects your framework (Vite / Next.js / CRA)
|
|
26
|
+
- Patches your `vite.config.ts` or `.babelrc`
|
|
27
|
+
- Creates `devlink.config.ts` with your project paths
|
|
28
|
+
- Adds `devlink:bridge` script to `package.json`
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Add to your app entry
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// src/main.tsx (Vite) or pages/_app.tsx (Next.js)
|
|
36
|
+
import { DevlinkBridge } from '@rahul_ur/devlink-bridge'
|
|
37
|
+
import { DevlinkStudio } from '@rahul_ur/devlink-studio'
|
|
38
|
+
import { devlinkConfig } from '../devlink.config'
|
|
39
|
+
|
|
40
|
+
const bridge = new DevlinkBridge()
|
|
41
|
+
|
|
42
|
+
function Root() {
|
|
43
|
+
return (
|
|
44
|
+
<DevlinkStudio bridge={bridge} {...devlinkConfig}>
|
|
45
|
+
<App />
|
|
46
|
+
</DevlinkStudio>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Start the bridge server
|
|
54
|
+
|
|
55
|
+
Open a separate terminal and keep it running:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npm run devlink:bridge
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Use it
|
|
64
|
+
|
|
65
|
+
Start your app normally (`npm run dev`) then:
|
|
66
|
+
|
|
67
|
+
| Action | How |
|
|
68
|
+
|--------|-----|
|
|
69
|
+
| Toggle inspect mode | `Alt+D` |
|
|
70
|
+
| Click element → open source | Click any element |
|
|
71
|
+
| Box select multiple | `⬚ Box` button then drag |
|
|
72
|
+
| Area capture | Hold `+` and drag |
|
|
73
|
+
| Save file | `Ctrl+S` |
|
|
74
|
+
| Exit inspect mode | `Esc` or right-click |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Vite config (manual)
|
|
79
|
+
|
|
80
|
+
If auto-setup didn't patch your config:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// vite.config.ts
|
|
84
|
+
import { defineConfig } from 'vite'
|
|
85
|
+
import react from '@vitejs/plugin-react'
|
|
86
|
+
import { devlinkBabelConfig } from '@rahul_ur/devlink-vite-plugin'
|
|
87
|
+
|
|
88
|
+
export default defineConfig({
|
|
89
|
+
plugins: [
|
|
90
|
+
react({
|
|
91
|
+
babel: {
|
|
92
|
+
plugins: [
|
|
93
|
+
devlinkBabelConfig({ root: process.cwd() }),
|
|
94
|
+
].filter(Boolean),
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
],
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Next.js config (manual)
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
// .babelrc
|
|
107
|
+
{
|
|
108
|
+
"presets": ["next/babel"],
|
|
109
|
+
"env": {
|
|
110
|
+
"development": {
|
|
111
|
+
"plugins": [
|
|
112
|
+
["@rahul_ur/devlink-babel-plugin", { "root": ".", "envs": ["development"] }]
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## DevlinkStudio props
|
|
122
|
+
|
|
123
|
+
| Prop | Type | Default | Description |
|
|
124
|
+
|------|------|---------|-------------|
|
|
125
|
+
| `bridge` | `DevlinkBridge` | required | Bridge instance |
|
|
126
|
+
| `projectRoot` | `string` | required | Absolute path to your project root |
|
|
127
|
+
| `rootPath` | `string` | required | Path shown in file tree (usually `projectRoot/src`) |
|
|
128
|
+
| `defaultDocked` | `boolean` | `false` | Start editor docked to the right |
|
|
129
|
+
| `dockedWidth` | `number` | `460` | Width of docked panel in px |
|
|
130
|
+
| `enabled` | `boolean` | `NODE_ENV=development` | Disable entirely in production |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Packages
|
|
135
|
+
|
|
136
|
+
This package installs all of these automatically:
|
|
137
|
+
|
|
138
|
+
| Package | Purpose |
|
|
139
|
+
|---------|---------|
|
|
140
|
+
| `@rahul_ur/devlink-bridge` | WebSocket tunnel between browser and local filesystem |
|
|
141
|
+
| `@rahul_ur/devlink-studio` | Floating Monaco editor + inspector + terminal + AI bar |
|
|
142
|
+
| `@rahul_ur/devlink-babel-plugin` | Stamps `data-source` on every JSX element at build time |
|
|
143
|
+
| `@rahul_ur/devlink-vite-plugin` | Wires babel plugin into Vite + React automatically |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## How it works
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
Your browser app
|
|
151
|
+
→ clicks element
|
|
152
|
+
→ reads data-source="src/Button.tsx:9:4" (stamped by babel plugin)
|
|
153
|
+
→ sends to bridge over local WebSocket
|
|
154
|
+
→ bridge reads file from disk
|
|
155
|
+
→ editor opens file, highlights lines
|
|
156
|
+
→ you edit + Ctrl+S
|
|
157
|
+
→ bridge writes to disk
|
|
158
|
+
→ HMR reloads your app
|
|
159
|
+
→ UI updates
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Everything stays on your machine. No cloud. No uploads.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
const projectRoot = process.cwd();
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const command = args[0] || 'setup';
|
|
9
|
+
|
|
10
|
+
const log = (msg) => console.log(`\x1b[36m[devlink]\x1b[0m ${msg}`);
|
|
11
|
+
const ok = (msg) => console.log(`\x1b[32m[devlink] ✓\x1b[0m ${msg}`);
|
|
12
|
+
const warn = (msg) => console.warn(`\x1b[33m[devlink] ⚠\x1b[0m ${msg}`);
|
|
13
|
+
const err = (msg) => console.error(`\x1b[31m[devlink] ✗\x1b[0m ${msg}`);
|
|
14
|
+
|
|
15
|
+
function exists(p) { return fs.existsSync(p); }
|
|
16
|
+
function readJson(p) { return JSON.parse(fs.readFileSync(p, 'utf8')); }
|
|
17
|
+
function writeJson(p, v) { fs.writeFileSync(p, `${JSON.stringify(v, null, 2)}\n`); }
|
|
18
|
+
|
|
19
|
+
// ─── Detect framework ─────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
function detectFramework() {
|
|
22
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
23
|
+
if (!exists(pkgPath)) return 'unknown';
|
|
24
|
+
const pkg = readJson(pkgPath);
|
|
25
|
+
const all = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
26
|
+
if (all['react-scripts']) return 'cra';
|
|
27
|
+
if (all['next']) return 'next';
|
|
28
|
+
if (all['vite'] || all['@vitejs/plugin-react']) return 'vite';
|
|
29
|
+
return 'unknown';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ─── Add npm scripts ──────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
function addScripts() {
|
|
35
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
36
|
+
if (!exists(pkgPath)) return;
|
|
37
|
+
const pkg = readJson(pkgPath);
|
|
38
|
+
pkg.scripts = pkg.scripts || {};
|
|
39
|
+
let changed = false;
|
|
40
|
+
if (!pkg.scripts['devlink:bridge']) {
|
|
41
|
+
pkg.scripts['devlink:bridge'] = 'node node_modules/@rahul_ur/devlink-bridge/server.mjs';
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
if (changed) { writeJson(pkgPath, pkg); ok('added devlink:bridge script to package.json'); }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─── Setup Vite ───────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
function setupVite() {
|
|
50
|
+
const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mts', 'vite.config.mjs'];
|
|
51
|
+
const configFile = candidates.find(f => exists(path.join(projectRoot, f)));
|
|
52
|
+
|
|
53
|
+
if (!configFile) {
|
|
54
|
+
// Create vite.config.ts from scratch
|
|
55
|
+
const content = `import { defineConfig } from 'vite';
|
|
56
|
+
import react from '@vitejs/plugin-react';
|
|
57
|
+
import { devlinkBabelConfig } from '@rahul_ur/devlink-vite-plugin';
|
|
58
|
+
|
|
59
|
+
export default defineConfig({
|
|
60
|
+
plugins: [
|
|
61
|
+
react({
|
|
62
|
+
babel: {
|
|
63
|
+
plugins: [
|
|
64
|
+
devlinkBabelConfig({ root: process.cwd() }),
|
|
65
|
+
].filter(Boolean),
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
`;
|
|
71
|
+
fs.writeFileSync(path.join(projectRoot, 'vite.config.ts'), content);
|
|
72
|
+
ok('created vite.config.ts with devlink config');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const configPath = path.join(projectRoot, configFile);
|
|
77
|
+
let src = fs.readFileSync(configPath, 'utf8');
|
|
78
|
+
|
|
79
|
+
if (src.includes('@rahul_ur/devlink-vite-plugin') || src.includes('@rahul_ur/devlink-babel-plugin')) {
|
|
80
|
+
ok(`${configFile} already has devlink config`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Add import line after last import
|
|
85
|
+
const importLine = `import { devlinkBabelConfig } from '@rahul_ur/devlink-vite-plugin';\n`;
|
|
86
|
+
const lastImport = src.lastIndexOf('\nimport ');
|
|
87
|
+
const insertAt = lastImport === -1 ? 0 : src.indexOf('\n', lastImport) + 1;
|
|
88
|
+
src = src.slice(0, insertAt) + importLine + src.slice(insertAt);
|
|
89
|
+
|
|
90
|
+
// Patch react() call
|
|
91
|
+
if (src.includes('react()')) {
|
|
92
|
+
src = src.replace(
|
|
93
|
+
'react()',
|
|
94
|
+
`react({\n babel: {\n plugins: [devlinkBabelConfig({ root: process.cwd() })].filter(Boolean),\n },\n })`
|
|
95
|
+
);
|
|
96
|
+
ok(`patched ${configFile} — react() updated`);
|
|
97
|
+
} else if (src.match(/react\s*\(\s*\{/)) {
|
|
98
|
+
warn(`Could not auto-patch ${configFile}. Add manually:\n\n react({ babel: { plugins: [devlinkBabelConfig({ root: process.cwd() })] } })\n`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fs.writeFileSync(configPath, src);
|
|
102
|
+
ok(`updated ${configFile}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ─── Setup Next.js ────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
function setupNext() {
|
|
108
|
+
const babelRcPath = path.join(projectRoot, '.babelrc');
|
|
109
|
+
const plugin = ['@rahul_ur/devlink-babel-plugin', { root: '.', envs: ['development'] }];
|
|
110
|
+
|
|
111
|
+
if (exists(babelRcPath)) {
|
|
112
|
+
const babelRc = readJson(babelRcPath);
|
|
113
|
+
babelRc.env = babelRc.env || {};
|
|
114
|
+
babelRc.env.development = babelRc.env.development || {};
|
|
115
|
+
babelRc.env.development.plugins = babelRc.env.development.plugins || [];
|
|
116
|
+
const already = babelRc.env.development.plugins.some(p =>
|
|
117
|
+
(Array.isArray(p) ? p[0] : p) === '@rahul_ur/devlink-babel-plugin'
|
|
118
|
+
);
|
|
119
|
+
if (!already) {
|
|
120
|
+
babelRc.env.development.plugins.push(plugin);
|
|
121
|
+
writeJson(babelRcPath, babelRc);
|
|
122
|
+
ok('patched .babelrc for Next.js');
|
|
123
|
+
} else {
|
|
124
|
+
ok('.babelrc already has devlink config');
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
writeJson(babelRcPath, {
|
|
128
|
+
presets: ['next/babel'],
|
|
129
|
+
env: { development: { plugins: [plugin] } }
|
|
130
|
+
});
|
|
131
|
+
ok('created .babelrc for Next.js');
|
|
132
|
+
warn('Adding .babelrc disables Next.js SWC compiler in development.');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ─── Setup CRA ────────────────────────────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
function setupCra() {
|
|
139
|
+
const configPath = path.join(projectRoot, 'node_modules', 'react-scripts', 'config', 'webpack.config.js');
|
|
140
|
+
if (!exists(configPath)) {
|
|
141
|
+
warn('CRA webpack config not found. Run npm install first then run devlink setup again.');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
let src = fs.readFileSync(configPath, 'utf8');
|
|
145
|
+
if (src.includes('@rahul_ur/devlink-babel-plugin')) { ok('CRA already patched'); return; }
|
|
146
|
+
|
|
147
|
+
const marker = "const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash');";
|
|
148
|
+
if (src.includes(marker)) {
|
|
149
|
+
src = src.replace(marker, `${marker}\nconst devlinkPlugin = require.resolve('@rahul_ur/devlink-babel-plugin');`);
|
|
150
|
+
}
|
|
151
|
+
const refreshLine = "isEnvDevelopment &&\n shouldUseReactRefresh &&\n require.resolve('react-refresh/babel'),";
|
|
152
|
+
if (src.includes(refreshLine)) {
|
|
153
|
+
src = src.replace(refreshLine,
|
|
154
|
+
`isEnvDevelopment && [devlinkPlugin, { root: paths.appPath, envs: ['development'] }],\n ${refreshLine}`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
fs.writeFileSync(configPath, src);
|
|
158
|
+
ok('patched CRA webpack config');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ─── Generate devlink.config.ts ───────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
function generateConfig() {
|
|
164
|
+
const configPath = path.join(projectRoot, 'devlink.config.ts');
|
|
165
|
+
if (exists(configPath)) { ok('devlink.config.ts already exists'); return; }
|
|
166
|
+
|
|
167
|
+
const root = projectRoot.replace(/\\/g, '/');
|
|
168
|
+
const srcDir = exists(path.join(projectRoot, 'src')) ? `${root}/src` : root;
|
|
169
|
+
|
|
170
|
+
fs.writeFileSync(configPath, `// devlink.config.ts — edit projectRoot and rootPath for your project
|
|
171
|
+
export const devlinkConfig = {
|
|
172
|
+
projectRoot: '${root}',
|
|
173
|
+
rootPath: '${srcDir}',
|
|
174
|
+
defaultDocked: true,
|
|
175
|
+
dockedWidth: 460,
|
|
176
|
+
};
|
|
177
|
+
`);
|
|
178
|
+
ok('created devlink.config.ts');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ─── Print main.tsx instructions ──────────────────────────────────────────────
|
|
182
|
+
|
|
183
|
+
function printInstructions(framework) {
|
|
184
|
+
const isNext = framework === 'next';
|
|
185
|
+
console.log('\n\x1b[36m─────────────────────────────────────────────────\x1b[0m');
|
|
186
|
+
console.log('\x1b[36m devlink setup complete — final step:\x1b[0m');
|
|
187
|
+
console.log('\x1b[36m─────────────────────────────────────────────────\x1b[0m\n');
|
|
188
|
+
|
|
189
|
+
if (isNext) {
|
|
190
|
+
console.log('Add to pages/_app.tsx:\n');
|
|
191
|
+
console.log(` import { DevlinkBridge } from '@rahul_ur/devlink-bridge'
|
|
192
|
+
import { DevlinkStudio } from '@rahul_ur/devlink-studio'
|
|
193
|
+
import { devlinkConfig } from '../devlink.config'
|
|
194
|
+
|
|
195
|
+
const bridge = new DevlinkBridge()
|
|
196
|
+
|
|
197
|
+
export default function App({ Component, pageProps }) {
|
|
198
|
+
return (
|
|
199
|
+
<DevlinkStudio bridge={bridge} {...devlinkConfig}>
|
|
200
|
+
<Component {...pageProps} />
|
|
201
|
+
</DevlinkStudio>
|
|
202
|
+
)
|
|
203
|
+
}`);
|
|
204
|
+
} else {
|
|
205
|
+
console.log('Add to src/main.tsx:\n');
|
|
206
|
+
console.log(` import { DevlinkBridge } from '@rahul_ur/devlink-bridge'
|
|
207
|
+
import { DevlinkStudio } from '@rahul_ur/devlink-studio'
|
|
208
|
+
import { devlinkConfig } from '../devlink.config'
|
|
209
|
+
|
|
210
|
+
const bridge = new DevlinkBridge()
|
|
211
|
+
|
|
212
|
+
function Root() {
|
|
213
|
+
return (
|
|
214
|
+
<DevlinkStudio bridge={bridge} {...devlinkConfig}>
|
|
215
|
+
<App />
|
|
216
|
+
</DevlinkStudio>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
221
|
+
<React.StrictMode><Root /></React.StrictMode>
|
|
222
|
+
)`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
console.log('\nThen start the bridge server:\n');
|
|
226
|
+
console.log(' npm run devlink:bridge\n');
|
|
227
|
+
console.log('Press \x1b[36mAlt+D\x1b[0m in the browser to activate inspect mode.\n');
|
|
228
|
+
console.log('\x1b[36m─────────────────────────────────────────────────\x1b[0m\n');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ─── Commands ─────────────────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
function runSetup() {
|
|
234
|
+
log(`setting up devlink in ${projectRoot}`);
|
|
235
|
+
const framework = detectFramework();
|
|
236
|
+
log(`detected framework: ${framework}`);
|
|
237
|
+
|
|
238
|
+
addScripts();
|
|
239
|
+
|
|
240
|
+
if (framework === 'vite') setupVite();
|
|
241
|
+
else if (framework === 'next') setupNext();
|
|
242
|
+
else if (framework === 'cra') setupCra();
|
|
243
|
+
else {
|
|
244
|
+
warn('Could not detect framework. Supported: Vite, Next.js, CRA.');
|
|
245
|
+
warn('Add @rahul_ur/devlink-babel-plugin manually to your build config.');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
generateConfig();
|
|
249
|
+
printInstructions(framework);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function runHelp() {
|
|
253
|
+
console.log(`
|
|
254
|
+
\x1b[36mdevlink\x1b[0m — click any element in your browser, jump to source, edit, UI updates live.
|
|
255
|
+
|
|
256
|
+
\x1b[1mCommands:\x1b[0m
|
|
257
|
+
devlink setup Auto-configure your project (Vite / Next.js / CRA)
|
|
258
|
+
devlink help Show this help message
|
|
259
|
+
|
|
260
|
+
\x1b[1mQuick start:\x1b[0m
|
|
261
|
+
npm install @rahul_ur/devlink
|
|
262
|
+
npx devlink setup
|
|
263
|
+
npm run devlink:bridge
|
|
264
|
+
|
|
265
|
+
\x1b[1mKeyboard shortcuts:\x1b[0m
|
|
266
|
+
Alt+D Toggle inspect mode
|
|
267
|
+
Esc Exit inspect mode
|
|
268
|
+
+ drag Area selection
|
|
269
|
+
Ctrl+S Save + format
|
|
270
|
+
|
|
271
|
+
\x1b[1mPackages installed:\x1b[0m
|
|
272
|
+
@rahul_ur/devlink-bridge WebSocket tunnel
|
|
273
|
+
@rahul_ur/devlink-studio Floating editor + inspector
|
|
274
|
+
@rahul_ur/devlink-babel-plugin Stamps data-source at build time
|
|
275
|
+
@rahul_ur/devlink-vite-plugin Wires plugin into Vite automatically
|
|
276
|
+
|
|
277
|
+
\x1b[1mDocs:\x1b[0m https://github.com/rahul_ur/devlink
|
|
278
|
+
`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ─── Run ──────────────────────────────────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
if (command === 'setup' || command === '') runSetup();
|
|
284
|
+
else if (command === 'help' || command === '--help' || command === '-h') runHelp();
|
|
285
|
+
else { err(`Unknown command: ${command}`); runHelp(); }
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @rahul_ur/devlink — type declarations
|
|
2
|
+
|
|
3
|
+
export { DevlinkBridge } from '@rahul_ur/devlink-bridge';
|
|
4
|
+
export { DevlinkStudio, FloatingWindow, useDeleteElement, useScreenCapture } from '@rahul_ur/devlink-studio';
|
|
5
|
+
export { devlinkVitePlugin, devlinkBabelConfig } from '@rahul_ur/devlink-vite-plugin';
|
package/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @rahul_ur/devlink
|
|
2
|
+
// Convenience re-exports — import from here or directly from each package
|
|
3
|
+
|
|
4
|
+
export { DevlinkBridge } from '@rahul_ur/devlink-bridge';
|
|
5
|
+
export { DevlinkStudio, FloatingWindow, useDeleteElement, useScreenCapture } from '@rahul_ur/devlink-studio';
|
|
6
|
+
export { devlinkVitePlugin, devlinkBabelConfig } from '@rahul_ur/devlink-vite-plugin';
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rahul_ur/devlink",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Click any element in your browser → jump to source code → edit → UI updates live. One command setup for Vite, Next.js and CRA.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"devlink": "./bin/cli.mjs",
|
|
8
|
+
"devlink-setup": "./bin/cli.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"templates",
|
|
13
|
+
"index.js",
|
|
14
|
+
"index.d.ts",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"prepublishOnly": "npm pack --dry-run"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"devlink",
|
|
22
|
+
"devtools",
|
|
23
|
+
"react",
|
|
24
|
+
"vite",
|
|
25
|
+
"nextjs",
|
|
26
|
+
"inspector",
|
|
27
|
+
"source-map",
|
|
28
|
+
"live-reload",
|
|
29
|
+
"monaco",
|
|
30
|
+
"editor",
|
|
31
|
+
"babel-plugin"
|
|
32
|
+
],
|
|
33
|
+
"author": "Rahul <your@email.com>",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/rahul_ur/devlink"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/rahul_ur/devlink/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/rahul_ur/devlink#readme",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@rahul_ur/devlink-bridge": "^1.0.0",
|
|
45
|
+
"@rahul_ur/devlink-studio": "^1.0.0",
|
|
46
|
+
"@rahul_ur/devlink-babel-plugin": "^1.0.0",
|
|
47
|
+
"@rahul_ur/devlink-vite-plugin": "^1.0.0"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=18.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|