@nuxt/devtools-nightly 0.0.0 → 2.0.0-beta.0-28940205.5b566fb
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/LICENSE +21 -0
- package/README.md +129 -0
- package/cli.mjs +2 -0
- package/dist/chunks/analyze-build.mjs +58 -0
- package/dist/chunks/module-main.mjs +2044 -0
- package/dist/chunks/plugin-metrics.mjs +68 -0
- package/dist/chunks/timeline.mjs +73 -0
- package/dist/chunks/vite-inspect.mjs +61 -0
- package/dist/chunks/vscode.mjs +195 -0
- package/dist/chunks/vue-devtools.mjs +30 -0
- package/dist/chunks/vue-inspector.mjs +15 -0
- package/dist/client/200.html +20 -0
- package/dist/client/404.html +20 -0
- package/dist/client/_nuxt/__blank-n15vnpb5.js +1 -0
- package/dist/client/_nuxt/analyze-build-kcwmvlyl.js +1 -0
- package/dist/client/_nuxt/assets-ivvrbi3q.js +16 -0
- package/dist/client/_nuxt/assets.css-hmxl533k.css +1 -0
- package/dist/client/_nuxt/b6bfxrb8.js +17 -0
- package/dist/client/_nuxt/builds/latest.json +1 -0
- package/dist/client/_nuxt/builds/meta/b8bbfd27-5704-4be8-a606-01af93c734ef.json +1 -0
- package/dist/client/_nuxt/client-c9f80qsp.js +1 -0
- package/dist/client/_nuxt/code-diff.vue-bhijg81q.js +8 -0
- package/dist/client/_nuxt/code-snippets.vue-i4e657wf.js +1 -0
- package/dist/client/_nuxt/components-krpx1826.js +1 -0
- package/dist/client/_nuxt/composable-item.vue-kwpzi9u7.js +1 -0
- package/dist/client/_nuxt/constants-b32h69zq.js +1 -0
- package/dist/client/_nuxt/custom-_name_-cepykbos.js +1 -0
- package/dist/client/_nuxt/default-mk5axw1k.js +1 -0
- package/dist/client/_nuxt/duration-display.vue-kqe6a4wx.js +1 -0
- package/dist/client/_nuxt/entry.css-nqz5coc9.css +1 -0
- package/dist/client/_nuxt/error-404-lp8coab3.js +1 -0
- package/dist/client/_nuxt/error-404.css-b3x40x40.css +1 -0
- package/dist/client/_nuxt/error-500-d4b6gi3u.js +1 -0
- package/dist/client/_nuxt/error-500.css-hilpkhd4.css +1 -0
- package/dist/client/_nuxt/error-ojb7cn7v.js +9 -0
- package/dist/client/_nuxt/filepath-item.vue-b829sn9l.js +1 -0
- package/dist/client/_nuxt/full-j8mngb76.js +1 -0
- package/dist/client/_nuxt/help-fab.css-ms50khsu.css +1 -0
- package/dist/client/_nuxt/help-fab.vue-gtlaa6k2.js +1 -0
- package/dist/client/_nuxt/hooks-htmew7il.js +1 -0
- package/dist/client/_nuxt/imports-18kqq3am.js +1 -0
- package/dist/client/_nuxt/index-dl6nn7ct.js +2 -0
- package/dist/client/_nuxt/index-e7wrzeix.js +1 -0
- package/dist/client/_nuxt/launch-page.vue-iyi310zf.js +1 -0
- package/dist/client/_nuxt/modules-hdu1ikfi.js +1 -0
- package/dist/client/_nuxt/nbadge-fktngirm.js +1 -0
- package/dist/client/_nuxt/ncheckbox.vue-fs1yhvat.js +1 -0
- package/dist/client/_nuxt/ncode-block.css-c9cb29at.css +1 -0
- package/dist/client/_nuxt/ncode-block.vue-gy1ero5j.js +2 -0
- package/dist/client/_nuxt/ndrawer.vue-cjxfdzsk.js +1 -0
- package/dist/client/_nuxt/ndropdown.vue-fe8ybtb0.js +1 -0
- package/dist/client/_nuxt/nicon-title.vue-ouqsubn7.js +1 -0
- package/dist/client/_nuxt/nlink.vue-jafnipxp.js +1 -0
- package/dist/client/_nuxt/nmarkdown.vue-hygash5x.js +1 -0
- package/dist/client/_nuxt/nnavbar.vue-d5x8tq5w.js +1 -0
- package/dist/client/_nuxt/none-i3w61o4x.js +1 -0
- package/dist/client/_nuxt/nsection-block-ivkmhmn9.js +1 -0
- package/dist/client/_nuxt/nsection-block.css-e7kbjm7k.css +1 -0
- package/dist/client/_nuxt/nselect-tabs.vue-sw71szzx.js +1 -0
- package/dist/client/_nuxt/nselect.vue-mkp3umn0.js +1 -0
- package/dist/client/_nuxt/open-graph-i5rptgvl.js +3 -0
- package/dist/client/_nuxt/open-graph.css-e21qzmvj.css +1 -0
- package/dist/client/_nuxt/overview-jzek603r.js +1 -0
- package/dist/client/_nuxt/pages-mhjzw1eo.js +1 -0
- package/dist/client/_nuxt/payload-kjhui3c5.js +1 -0
- package/dist/client/_nuxt/pinia-jy0feqo2.js +1 -0
- package/dist/client/_nuxt/plugins-d2vnj57a.js +1 -0
- package/dist/client/_nuxt/render-tree-malxu5t7.js +1 -0
- package/dist/client/_nuxt/runtime-configs-c8u0cuv7.js +1 -0
- package/dist/client/_nuxt/server-route-inputs.vue-dfs3eezs.js +1 -0
- package/dist/client/_nuxt/server-routes-ea89bftg.js +9 -0
- package/dist/client/_nuxt/server-tasks-guw0x7eh.js +1 -0
- package/dist/client/_nuxt/settings-nr7x6wel.js +1 -0
- package/dist/client/_nuxt/stacktrace-list.vue-cfyme80n.js +1 -0
- package/dist/client/_nuxt/state-components-f29eyhzi.js +1 -0
- package/dist/client/_nuxt/state-editor.vue-nd6tb0dn.js +1 -0
- package/dist/client/_nuxt/state-modules-gh2s62ky.js +1 -0
- package/dist/client/_nuxt/storage-d1qa6fff.js +1 -0
- package/dist/client/_nuxt/terminals-igsxvm6w.js +1 -0
- package/dist/client/_nuxt/terminals.css-mejv43xm.css +1 -0
- package/dist/client/_nuxt/timeline-lm6kcwsd.js +31 -0
- package/dist/client/_nuxt/timeline.css-lhkpu01p.css +1 -0
- package/dist/client/_nuxt/unocss-runtime-jzfgcoxk.js +1 -0
- package/dist/client/_nuxt/vendor/json-editor-vue-gi2fewby.js +3818 -0
- package/dist/client/_nuxt/vendor/json-editor-vue.css-mqq5uooj.css +1 -0
- package/dist/client/_nuxt/vendor/markdown-it-fvu08dbs.js +16 -0
- package/dist/client/_nuxt/vendor/shiki-bnvxb5wv.js +147 -0
- package/dist/client/_nuxt/vendor/unocss-3uirpnla.js +2 -0
- package/dist/client/_nuxt/vendor/unocss.css-mhvipxpl.css +1 -0
- package/dist/client/_nuxt/vendor/vis-dlwijd5n.js +98 -0
- package/dist/client/_nuxt/vendor/xterm-dbpzgj7s.js +9 -0
- package/dist/client/_nuxt/vendor/xterm.css-egmhki83.css +32 -0
- package/dist/client/_nuxt/virtual-files-jzsbborg.js +1 -0
- package/dist/client/_nuxt/virtual-files.css-gqpg2wnb.css +1 -0
- package/dist/client/_nuxt/vue-virtual-scroller.esm-hx1s7s1b.js +2 -0
- package/dist/client/index.html +20 -0
- package/dist/client/nuxt.svg +3 -0
- package/dist/dirs.d.mts +7 -0
- package/dist/dirs.d.ts +7 -0
- package/dist/dirs.mjs +28 -0
- package/dist/module.cjs +5 -0
- package/dist/module.d.mts +9 -0
- package/dist/module.d.ts +9 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +6 -0
- package/dist/runtime/auth/index.html +76 -0
- package/dist/runtime/function-metrics-helpers.d.ts +3 -0
- package/dist/runtime/function-metrics-helpers.js +69 -0
- package/dist/runtime/nitro/inline.d.ts +3 -0
- package/dist/runtime/nitro/inline.js +6 -0
- package/dist/runtime/plugins/devtools.client.d.ts +2 -0
- package/dist/runtime/plugins/devtools.client.js +56 -0
- package/dist/runtime/plugins/devtools.server.d.ts +2 -0
- package/dist/runtime/plugins/devtools.server.js +7 -0
- package/dist/runtime/plugins/view/FrameBox.vue +167 -0
- package/dist/runtime/plugins/view/Main.vue +422 -0
- package/dist/runtime/plugins/view/client.d.ts +12 -0
- package/dist/runtime/plugins/view/client.js +332 -0
- package/dist/runtime/plugins/view/state.d.ts +5 -0
- package/dist/runtime/plugins/view/state.js +17 -0
- package/dist/runtime/plugins/view/utils.d.ts +31 -0
- package/dist/runtime/plugins/view/utils.js +156 -0
- package/dist/runtime/settings.d.ts +4 -0
- package/dist/runtime/settings.js +2 -0
- package/dist/runtime/shared/hooks.d.ts +2 -0
- package/dist/runtime/shared/hooks.js +33 -0
- package/dist/runtime/use-nuxt-devtools.d.ts +8 -0
- package/dist/runtime/use-nuxt-devtools.js +23 -0
- package/dist/runtime/vue-devtools/overlay.d.ts +1 -0
- package/dist/runtime/vue-devtools/overlay.js +8 -0
- package/dist/shared/devtools-nightly.2a48a9e5.d.mts +62 -0
- package/dist/shared/devtools-nightly.2a48a9e5.d.ts +62 -0
- package/dist/shared/devtools-nightly.5ac54dae.mjs +121 -0
- package/dist/types.d.mts +42 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.mjs +1 -0
- package/package.json +123 -2
- package/types.d.ts +1 -0
|
@@ -0,0 +1,2044 @@
|
|
|
1
|
+
import fs$1, { existsSync } from 'node:fs';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os, { homedir } from 'node:os';
|
|
4
|
+
import { logger, useNuxt, addPlugin, addTemplate, addVitePlugin } from '@nuxt/kit';
|
|
5
|
+
import { colors } from 'consola/utils';
|
|
6
|
+
import { join, dirname as dirname$1, resolve } from 'pathe';
|
|
7
|
+
import sirv from 'sirv';
|
|
8
|
+
import { searchForWorkspaceRoot } from 'vite';
|
|
9
|
+
import { d as defaultAllowedExtensions, a as defaultTabOptions, W as WS_EVENT_NAME } from '../shared/devtools-nightly.5ac54dae.mjs';
|
|
10
|
+
import { dirname, join as join$1, relative, parse } from 'node:path';
|
|
11
|
+
import { randomStr } from '@antfu/utils';
|
|
12
|
+
import { hash } from 'ohash';
|
|
13
|
+
import { runtimeDir, clientDir, packageDir, isGlobalInstall } from '../dirs.mjs';
|
|
14
|
+
import { createBirpcGroup } from 'birpc';
|
|
15
|
+
import { stringify, parse as parse$1 } from 'flatted';
|
|
16
|
+
import { startSubprocess } from '@nuxt/devtools-kit';
|
|
17
|
+
import Git from 'simple-git';
|
|
18
|
+
import { glob } from 'tinyglobby';
|
|
19
|
+
import { imageMeta } from 'image-meta';
|
|
20
|
+
import { debounce } from 'perfect-debounce';
|
|
21
|
+
import destr from 'destr';
|
|
22
|
+
import { snakeCase } from 'scule';
|
|
23
|
+
import { resolveBuiltinPresets } from 'unimport';
|
|
24
|
+
import { setupHooksDebug } from '../../dist/runtime/shared/hooks.js';
|
|
25
|
+
import isInstalledGlobally from 'is-installed-globally';
|
|
26
|
+
import { parseModule } from 'magicast';
|
|
27
|
+
import { addNuxtModule, getDefaultExportOptions } from 'magicast/helpers';
|
|
28
|
+
import { detectPackageManager } from 'nypm';
|
|
29
|
+
import { createRequire } from 'node:module';
|
|
30
|
+
import { getPackageInfo } from 'local-pkg';
|
|
31
|
+
import 'pkg-types';
|
|
32
|
+
import semver from 'semver';
|
|
33
|
+
|
|
34
|
+
const version = "2.0.0-beta.0-28940205.5b566fb";
|
|
35
|
+
|
|
36
|
+
function getHomeDir() {
|
|
37
|
+
return process.env.XDG_CONFIG_HOME || homedir();
|
|
38
|
+
}
|
|
39
|
+
async function readLocalOptions(defaults, options) {
|
|
40
|
+
const { filePath } = getOptionsFilepath(options);
|
|
41
|
+
if (existsSync(filePath)) {
|
|
42
|
+
try {
|
|
43
|
+
const options2 = {
|
|
44
|
+
...defaults,
|
|
45
|
+
...JSON.parse(await fs.readFile(filePath, "utf-8")).settings || {}
|
|
46
|
+
};
|
|
47
|
+
return options2;
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.error(`[DevTools] failed to parse local options file: ${filePath}, fallback to defaults`);
|
|
50
|
+
console.error(e);
|
|
51
|
+
return { ...defaults };
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
return { ...defaults };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function getOptionsFilepath(options) {
|
|
58
|
+
let hashedKey;
|
|
59
|
+
if (options.key)
|
|
60
|
+
hashedKey = hash(`${options.root}:${options.key}`);
|
|
61
|
+
else
|
|
62
|
+
hashedKey = hash(options.root);
|
|
63
|
+
const home = getHomeDir();
|
|
64
|
+
const filePath = join(home, ".nuxt/devtools", `${hashedKey}.json`);
|
|
65
|
+
return {
|
|
66
|
+
filePath,
|
|
67
|
+
hashedKey
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async function clearLocalOptions(options) {
|
|
71
|
+
const { filePath } = getOptionsFilepath(options);
|
|
72
|
+
if (existsSync(filePath))
|
|
73
|
+
await fs.unlink(filePath);
|
|
74
|
+
}
|
|
75
|
+
async function writeLocalOptions(settings, options) {
|
|
76
|
+
const { filePath, hashedKey } = getOptionsFilepath(options);
|
|
77
|
+
await fs.mkdir(dirname(filePath), { recursive: true });
|
|
78
|
+
await fs.writeFile(
|
|
79
|
+
filePath,
|
|
80
|
+
JSON.stringify(
|
|
81
|
+
{
|
|
82
|
+
root: options.root,
|
|
83
|
+
hash: hashedKey,
|
|
84
|
+
settings
|
|
85
|
+
},
|
|
86
|
+
null,
|
|
87
|
+
2
|
|
88
|
+
),
|
|
89
|
+
"utf-8"
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let token;
|
|
94
|
+
async function getDevAuthToken() {
|
|
95
|
+
if (token)
|
|
96
|
+
return token;
|
|
97
|
+
const home = getHomeDir();
|
|
98
|
+
const dir = join$1(home, ".nuxt/devtools");
|
|
99
|
+
const filepath = join$1(dir, "dev-auth-token.txt");
|
|
100
|
+
if (existsSync(filepath))
|
|
101
|
+
token = (await fs.readFile(filepath, "utf-8")).trim();
|
|
102
|
+
if (!token)
|
|
103
|
+
token = randomStr(16);
|
|
104
|
+
await fs.mkdir(dir, { recursive: true });
|
|
105
|
+
await fs.writeFile(filepath, token, "utf-8");
|
|
106
|
+
return token;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function setupAnalyzeBuildRPC({ nuxt, refresh, ensureDevAuthToken }) {
|
|
110
|
+
let builds = [];
|
|
111
|
+
let promise;
|
|
112
|
+
let initalized;
|
|
113
|
+
const processId = "devtools:analyze-build";
|
|
114
|
+
const analyzeDir = join(nuxt.options.rootDir, ".nuxt/analyze");
|
|
115
|
+
async function startAnalyzeBuild(name) {
|
|
116
|
+
if (promise)
|
|
117
|
+
throw new Error("Already building");
|
|
118
|
+
const result = startSubprocess({
|
|
119
|
+
command: "npx",
|
|
120
|
+
args: ["nuxi", "analyze", "--no-serve", "--name", name],
|
|
121
|
+
cwd: nuxt.options.rootDir
|
|
122
|
+
}, {
|
|
123
|
+
id: processId,
|
|
124
|
+
name: "Analyze Build",
|
|
125
|
+
icon: "logos-nuxt-icon"
|
|
126
|
+
}, nuxt);
|
|
127
|
+
refresh("getAnalyzeBuildInfo");
|
|
128
|
+
promise = result.getProcess().then(() => {
|
|
129
|
+
refresh("getAnalyzeBuildInfo");
|
|
130
|
+
return readBuildInfo();
|
|
131
|
+
}).finally(() => {
|
|
132
|
+
promise = void 0;
|
|
133
|
+
initalized = void 0;
|
|
134
|
+
refresh("getAnalyzeBuildInfo");
|
|
135
|
+
});
|
|
136
|
+
return processId;
|
|
137
|
+
}
|
|
138
|
+
async function readBuildInfo() {
|
|
139
|
+
const files = await glob(["*/meta.json"], { cwd: analyzeDir, onlyFiles: true, absolute: true });
|
|
140
|
+
builds = await Promise.all(files.map(async (file) => {
|
|
141
|
+
const dir = dirname$1(file);
|
|
142
|
+
const json = JSON.parse(await fs.readFile(file, "utf-8"));
|
|
143
|
+
return {
|
|
144
|
+
...json,
|
|
145
|
+
features: {
|
|
146
|
+
bundleClient: fs$1.existsSync(join(dir, "client.html")),
|
|
147
|
+
bundleNitro: fs$1.existsSync(join(dir, "nitro.html")),
|
|
148
|
+
viteInspect: fs$1.existsSync(join(dir, ".vite-inspect"))
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}));
|
|
152
|
+
return builds.sort((a, b) => b.endTime - a.endTime);
|
|
153
|
+
}
|
|
154
|
+
async function generateAnalyzeBuildName() {
|
|
155
|
+
try {
|
|
156
|
+
const git = Git(nuxt.options.rootDir);
|
|
157
|
+
const branch = await git.branch();
|
|
158
|
+
const branchName = branch.current || "head";
|
|
159
|
+
const sha = await git.revparse(["--short", "HEAD"]);
|
|
160
|
+
const isWorkingTreeClean = (await git.status()).isClean();
|
|
161
|
+
if (isWorkingTreeClean)
|
|
162
|
+
return `${branchName}#${sha}`;
|
|
163
|
+
return `${branchName}#${sha}-dirty`;
|
|
164
|
+
} catch {
|
|
165
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
async getAnalyzeBuildInfo() {
|
|
170
|
+
if (!initalized)
|
|
171
|
+
initalized = readBuildInfo();
|
|
172
|
+
await initalized;
|
|
173
|
+
return {
|
|
174
|
+
isBuilding: !!promise,
|
|
175
|
+
builds
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
async clearAnalyzeBuilds(token, names) {
|
|
179
|
+
await ensureDevAuthToken(token);
|
|
180
|
+
if (!names) {
|
|
181
|
+
await fs.rm(analyzeDir, { recursive: true, force: true });
|
|
182
|
+
} else {
|
|
183
|
+
const targets = builds.filter((build) => names.includes(build.name));
|
|
184
|
+
await Promise.all(targets.map((target) => fs.rm(join(analyzeDir, target.slug), { recursive: true, force: true })));
|
|
185
|
+
}
|
|
186
|
+
initalized = readBuildInfo();
|
|
187
|
+
refresh("getAnalyzeBuildInfo");
|
|
188
|
+
},
|
|
189
|
+
generateAnalyzeBuildName,
|
|
190
|
+
async startAnalyzeBuild(token, ...args) {
|
|
191
|
+
await ensureDevAuthToken(token);
|
|
192
|
+
return startAnalyzeBuild(...args);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function setupAssetsRPC({ nuxt, ensureDevAuthToken, refresh, options }) {
|
|
198
|
+
const _imageMetaCache = /* @__PURE__ */ new Map();
|
|
199
|
+
let cache = null;
|
|
200
|
+
const extensions = options.assets?.uploadExtensions || defaultAllowedExtensions;
|
|
201
|
+
const publicDir = resolve(nuxt.options.srcDir, nuxt.options.dir.public);
|
|
202
|
+
const layerDirs = [publicDir, ...nuxt.options._layers.map((layer) => resolve(layer.cwd, "public"))];
|
|
203
|
+
const refreshDebounced = debounce(() => {
|
|
204
|
+
cache = null;
|
|
205
|
+
refresh("getStaticAssets");
|
|
206
|
+
}, 500);
|
|
207
|
+
nuxt.hook("builder:watch", (event, key) => {
|
|
208
|
+
key = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, key));
|
|
209
|
+
if (key.startsWith(nuxt.options.dir.public) && (event === "add" || event === "unlink"))
|
|
210
|
+
refreshDebounced();
|
|
211
|
+
});
|
|
212
|
+
async function scan() {
|
|
213
|
+
if (cache)
|
|
214
|
+
return cache;
|
|
215
|
+
const baseURL = nuxt.options.app.baseURL;
|
|
216
|
+
const dirs = [];
|
|
217
|
+
for (const layerDir of layerDirs) {
|
|
218
|
+
const files = await glob(["**/*"], {
|
|
219
|
+
cwd: layerDir,
|
|
220
|
+
onlyFiles: true
|
|
221
|
+
});
|
|
222
|
+
dirs.push({ layerDir, files });
|
|
223
|
+
}
|
|
224
|
+
const uniquePaths = /* @__PURE__ */ new Set();
|
|
225
|
+
cache = [];
|
|
226
|
+
for (const { layerDir, files } of dirs) {
|
|
227
|
+
for (const path of files) {
|
|
228
|
+
const filePath = resolve(layerDir, path);
|
|
229
|
+
const stat = await fs.lstat(filePath);
|
|
230
|
+
const fullPath = join(baseURL, path);
|
|
231
|
+
if (!uniquePaths.has(fullPath)) {
|
|
232
|
+
cache.push({
|
|
233
|
+
path,
|
|
234
|
+
publicPath: fullPath,
|
|
235
|
+
filePath,
|
|
236
|
+
type: guessType(path),
|
|
237
|
+
size: stat.size,
|
|
238
|
+
mtime: stat.mtimeMs,
|
|
239
|
+
layer: publicDir !== layerDir ? layerDir : void 0
|
|
240
|
+
});
|
|
241
|
+
uniquePaths.add(fullPath);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return cache.sort((a, b) => a.path.localeCompare(b.path));
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
async getStaticAssets() {
|
|
249
|
+
return await scan();
|
|
250
|
+
},
|
|
251
|
+
async getImageMeta(token, filepath) {
|
|
252
|
+
await ensureDevAuthToken(token);
|
|
253
|
+
if (_imageMetaCache.has(filepath))
|
|
254
|
+
return _imageMetaCache.get(filepath);
|
|
255
|
+
try {
|
|
256
|
+
const meta = imageMeta(await fs.readFile(filepath));
|
|
257
|
+
_imageMetaCache.set(filepath, meta);
|
|
258
|
+
return meta;
|
|
259
|
+
} catch (e) {
|
|
260
|
+
_imageMetaCache.set(filepath, void 0);
|
|
261
|
+
console.error(e);
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
async getTextAssetContent(token, filepath, limit = 300) {
|
|
266
|
+
await ensureDevAuthToken(token);
|
|
267
|
+
try {
|
|
268
|
+
const content = await fs.readFile(filepath, "utf-8");
|
|
269
|
+
return content.slice(0, limit);
|
|
270
|
+
} catch (e) {
|
|
271
|
+
console.error(e);
|
|
272
|
+
return void 0;
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
async writeStaticAssets(token, files, folder) {
|
|
276
|
+
await ensureDevAuthToken(token);
|
|
277
|
+
const baseDir = resolve(nuxt.options.srcDir, nuxt.options.dir.public + folder);
|
|
278
|
+
return await Promise.all(
|
|
279
|
+
files.map(async ({ path, content, encoding, override }) => {
|
|
280
|
+
let finalPath = resolve(baseDir, path);
|
|
281
|
+
const { ext } = parse(finalPath);
|
|
282
|
+
if (extensions !== "*") {
|
|
283
|
+
if (!extensions.includes(ext.toLowerCase().slice(1)))
|
|
284
|
+
throw new Error(`File extension ${ext} is not allowed to upload, allowed extensions are: ${extensions.join(", ")}
|
|
285
|
+
You can configure it in Nuxt config at \`devtools.assets.uploadExtensions\`.`);
|
|
286
|
+
}
|
|
287
|
+
if (!override) {
|
|
288
|
+
try {
|
|
289
|
+
await fs.stat(finalPath);
|
|
290
|
+
const base = finalPath.slice(0, finalPath.length - ext.length - 1);
|
|
291
|
+
let i = 1;
|
|
292
|
+
while (await fs.access(`${base}-${i}.${ext}`).then(() => true).catch(() => false))
|
|
293
|
+
i++;
|
|
294
|
+
finalPath = `${base}-${i}.${ext}`;
|
|
295
|
+
} catch {
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
await fs.writeFile(finalPath, content, {
|
|
299
|
+
encoding: encoding ?? "utf-8"
|
|
300
|
+
});
|
|
301
|
+
return finalPath;
|
|
302
|
+
})
|
|
303
|
+
);
|
|
304
|
+
},
|
|
305
|
+
async deleteStaticAsset(token, path) {
|
|
306
|
+
await ensureDevAuthToken(token);
|
|
307
|
+
return await fs.unlink(path);
|
|
308
|
+
},
|
|
309
|
+
async renameStaticAsset(token, oldPath, newPath) {
|
|
310
|
+
await ensureDevAuthToken(token);
|
|
311
|
+
const exist = cache?.find((asset) => asset.filePath === newPath);
|
|
312
|
+
if (exist)
|
|
313
|
+
throw new Error(`File ${newPath} already exists`);
|
|
314
|
+
return await fs.rename(oldPath, newPath);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const reImage = /\.(?:png|jpe?g|jxl|gif|svg|webp|avif|ico|bmp|tiff?)$/i;
|
|
319
|
+
const reVideo = /\.(?:mp4|webm|ogv|mov|avi|flv|wmv|mpg|mpeg|mkv|3gp|3g2|ts|mts|m2ts|vob|ogm|ogx|rm|rmvb|asf|amv|divx|m4v|svi|viv|f4v|f4p|f4a|f4b)$/i;
|
|
320
|
+
const reAudio = /\.(?:mp3|wav|ogg|flac|aac|wma|alac|ape|ac3|dts|tta|opus|amr|aiff|au|mid|midi|ra|rm|wv|weba|dss|spx|vox|tak|dsf|dff|dsd|cda)$/i;
|
|
321
|
+
const reFont = /\.(?:woff2?|eot|ttf|otf|ttc|pfa|pfb|pfm|afm)/i;
|
|
322
|
+
const reText = /\.(?:json[5c]?|te?xt|[mc]?[jt]sx?|md[cx]?|markdown)/i;
|
|
323
|
+
function guessType(path) {
|
|
324
|
+
if (reImage.test(path))
|
|
325
|
+
return "image";
|
|
326
|
+
if (reVideo.test(path))
|
|
327
|
+
return "video";
|
|
328
|
+
if (reAudio.test(path))
|
|
329
|
+
return "audio";
|
|
330
|
+
if (reFont.test(path))
|
|
331
|
+
return "font";
|
|
332
|
+
if (reText.test(path))
|
|
333
|
+
return "text";
|
|
334
|
+
return "other";
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function setupCustomTabRPC({ nuxt, options, refresh }) {
|
|
338
|
+
const iframeTabs = [];
|
|
339
|
+
const customTabs = [];
|
|
340
|
+
if (options.customTabs?.length)
|
|
341
|
+
customTabs.push(...options.customTabs);
|
|
342
|
+
async function initHooks() {
|
|
343
|
+
nuxt.hook("devtools:customTabs:refresh", initCustomTabs);
|
|
344
|
+
await initCustomTabs();
|
|
345
|
+
}
|
|
346
|
+
async function initCustomTabs() {
|
|
347
|
+
customTabs.length = 0;
|
|
348
|
+
if (options.customTabs?.length)
|
|
349
|
+
customTabs.push(...options.customTabs);
|
|
350
|
+
await nuxt.callHook("devtools:customTabs", customTabs);
|
|
351
|
+
refresh("getCustomTabs");
|
|
352
|
+
}
|
|
353
|
+
nuxt.hook("app:resolve", async () => {
|
|
354
|
+
await initHooks();
|
|
355
|
+
});
|
|
356
|
+
return {
|
|
357
|
+
getCustomTabs() {
|
|
358
|
+
return [
|
|
359
|
+
...iframeTabs,
|
|
360
|
+
...customTabs
|
|
361
|
+
].map((i) => {
|
|
362
|
+
i.category = i.category || "modules";
|
|
363
|
+
return i;
|
|
364
|
+
});
|
|
365
|
+
},
|
|
366
|
+
async customTabAction(name, actionIndex) {
|
|
367
|
+
const tab = customTabs.find((i) => i.name === name);
|
|
368
|
+
if (!tab)
|
|
369
|
+
return false;
|
|
370
|
+
const view = tab.view;
|
|
371
|
+
if (view.type !== "launch")
|
|
372
|
+
return false;
|
|
373
|
+
const action = view.actions?.[actionIndex];
|
|
374
|
+
if (!action)
|
|
375
|
+
return false;
|
|
376
|
+
Promise.resolve(action.handle?.()).catch((e) => {
|
|
377
|
+
console.error(e);
|
|
378
|
+
}).finally(() => {
|
|
379
|
+
nuxt.callHook("devtools:customTabs:refresh");
|
|
380
|
+
});
|
|
381
|
+
nuxt.callHook("devtools:customTabs:refresh");
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function setupGeneralRPC({
|
|
388
|
+
nuxt,
|
|
389
|
+
options,
|
|
390
|
+
refresh,
|
|
391
|
+
ensureDevAuthToken,
|
|
392
|
+
openInEditorHooks
|
|
393
|
+
}) {
|
|
394
|
+
const components = [];
|
|
395
|
+
const imports = [];
|
|
396
|
+
const importPresets = [];
|
|
397
|
+
let importDirs = [];
|
|
398
|
+
const serverPages = [];
|
|
399
|
+
let serverApp;
|
|
400
|
+
const serverHooks = setupHooksDebug(nuxt.hooks);
|
|
401
|
+
let unimport;
|
|
402
|
+
let app;
|
|
403
|
+
nuxt.hook("components:extend", (v) => {
|
|
404
|
+
components.length = 0;
|
|
405
|
+
components.push(...v);
|
|
406
|
+
components.sort((a, b) => a.pascalName.localeCompare(b.pascalName));
|
|
407
|
+
refresh("getComponents");
|
|
408
|
+
});
|
|
409
|
+
nuxt.hook("imports:extend", (v) => {
|
|
410
|
+
imports.length = 0;
|
|
411
|
+
imports.push(...v);
|
|
412
|
+
refresh("getAutoImports");
|
|
413
|
+
});
|
|
414
|
+
nuxt.hook("pages:extend", (v) => {
|
|
415
|
+
serverPages.length = 0;
|
|
416
|
+
const pagesSet = new Set(v);
|
|
417
|
+
function searchChildren(page) {
|
|
418
|
+
if (pagesSet.has(page))
|
|
419
|
+
return;
|
|
420
|
+
pagesSet.add(page);
|
|
421
|
+
page.children?.forEach(searchChildren);
|
|
422
|
+
}
|
|
423
|
+
v.forEach(searchChildren);
|
|
424
|
+
serverPages.push(...Array.from(pagesSet).sort((a, b) => a.path.localeCompare(b.path)));
|
|
425
|
+
refresh("getServerPages");
|
|
426
|
+
});
|
|
427
|
+
nuxt.hook("app:resolve", (app2) => {
|
|
428
|
+
serverApp = app2;
|
|
429
|
+
});
|
|
430
|
+
nuxt.hook("imports:sources", async (v) => {
|
|
431
|
+
const result = (await resolveBuiltinPresets(v)).flat();
|
|
432
|
+
importPresets.length = 0;
|
|
433
|
+
importPresets.push(...result);
|
|
434
|
+
refresh("getAutoImports");
|
|
435
|
+
});
|
|
436
|
+
nuxt.hook("imports:context", (_unimport) => {
|
|
437
|
+
unimport = _unimport;
|
|
438
|
+
});
|
|
439
|
+
nuxt.hook("imports:dirs", (dirs) => {
|
|
440
|
+
importDirs = dirs;
|
|
441
|
+
});
|
|
442
|
+
nuxt.hook("app:resolve", (v) => {
|
|
443
|
+
app = v;
|
|
444
|
+
});
|
|
445
|
+
return {
|
|
446
|
+
getServerConfig() {
|
|
447
|
+
return nuxt.options;
|
|
448
|
+
},
|
|
449
|
+
getServerRuntimeConfig() {
|
|
450
|
+
const ENV_PREFIX = "NITRO_";
|
|
451
|
+
const ENV_PREFIX_ALT = "NUXT_";
|
|
452
|
+
function _getEnv(key) {
|
|
453
|
+
const envKey = snakeCase(key).toUpperCase();
|
|
454
|
+
return destr(process.env[ENV_PREFIX + envKey] ?? process.env[ENV_PREFIX_ALT + envKey]);
|
|
455
|
+
}
|
|
456
|
+
function _isObject(input) {
|
|
457
|
+
return typeof input === "object" && !Array.isArray(input);
|
|
458
|
+
}
|
|
459
|
+
function _applyEnv(obj, parentKey = "") {
|
|
460
|
+
for (const key in obj) {
|
|
461
|
+
const subKey = parentKey ? `${parentKey}_${key}` : key;
|
|
462
|
+
const envValue = _getEnv(subKey);
|
|
463
|
+
if (_isObject(obj[key])) {
|
|
464
|
+
if (_isObject(envValue))
|
|
465
|
+
obj[key] = { ...obj[key], ...envValue };
|
|
466
|
+
_applyEnv(obj[key], subKey);
|
|
467
|
+
} else {
|
|
468
|
+
obj[key] = envValue ?? obj[key];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return obj;
|
|
472
|
+
}
|
|
473
|
+
const runtime = { ...nuxt.options.runtimeConfig };
|
|
474
|
+
_applyEnv(runtime);
|
|
475
|
+
return runtime;
|
|
476
|
+
},
|
|
477
|
+
getModuleOptions() {
|
|
478
|
+
return options;
|
|
479
|
+
},
|
|
480
|
+
getServerApp() {
|
|
481
|
+
return serverApp;
|
|
482
|
+
},
|
|
483
|
+
getComponents() {
|
|
484
|
+
return components;
|
|
485
|
+
},
|
|
486
|
+
async getComponentsRelationships() {
|
|
487
|
+
return [];
|
|
488
|
+
},
|
|
489
|
+
getServerPages() {
|
|
490
|
+
return serverPages;
|
|
491
|
+
},
|
|
492
|
+
getAutoImports() {
|
|
493
|
+
return {
|
|
494
|
+
imports: [
|
|
495
|
+
...imports,
|
|
496
|
+
...importPresets
|
|
497
|
+
],
|
|
498
|
+
metadata: unimport?.getMetadata(),
|
|
499
|
+
dirs: importDirs
|
|
500
|
+
};
|
|
501
|
+
},
|
|
502
|
+
getServerLayouts() {
|
|
503
|
+
return Object.values(app?.layouts || []);
|
|
504
|
+
},
|
|
505
|
+
getServerHooks() {
|
|
506
|
+
return Object.values(serverHooks);
|
|
507
|
+
},
|
|
508
|
+
async openInEditor(input) {
|
|
509
|
+
if (input.startsWith("./"))
|
|
510
|
+
input = resolve(process.cwd(), input);
|
|
511
|
+
const match = input.match(/^(.*?)(:[:\d]*)$/);
|
|
512
|
+
let suffix = "";
|
|
513
|
+
if (match) {
|
|
514
|
+
input = match[1];
|
|
515
|
+
suffix = match[2];
|
|
516
|
+
}
|
|
517
|
+
const path = [
|
|
518
|
+
input,
|
|
519
|
+
`${input}.js`,
|
|
520
|
+
`${input}.mjs`,
|
|
521
|
+
`${input}.ts`
|
|
522
|
+
].find((i) => existsSync(i));
|
|
523
|
+
if (!path) {
|
|
524
|
+
console.error("File not found:", input);
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
for (const hook of openInEditorHooks) {
|
|
529
|
+
const result = await hook(path + suffix);
|
|
530
|
+
if (result)
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
533
|
+
await import('launch-editor').then((r) => (r.default || r)(path + suffix));
|
|
534
|
+
return true;
|
|
535
|
+
} catch (e) {
|
|
536
|
+
console.error(e);
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
async restartNuxt(token, hard = true) {
|
|
541
|
+
await ensureDevAuthToken(token);
|
|
542
|
+
logger.info("Restarting Nuxt...");
|
|
543
|
+
return nuxt.callHook("restart", { hard });
|
|
544
|
+
},
|
|
545
|
+
async requestForAuth(info, origin) {
|
|
546
|
+
if (options.disableAuthorization)
|
|
547
|
+
return;
|
|
548
|
+
const token = await getDevAuthToken();
|
|
549
|
+
origin ||= `${nuxt.options.devServer.https ? "https" : "http"}://${nuxt.options.devServer.host === "::" ? "localhost" : nuxt.options.devServer.host || "localhost"}:${nuxt.options.devServer.port}`;
|
|
550
|
+
const ROUTE_AUTH = `${nuxt.options.app.baseURL || "/"}/__nuxt_devtools__/auth`.replace(/\/+/g, "/");
|
|
551
|
+
const message = [
|
|
552
|
+
`A browser is requesting permissions of ${colors.bold(colors.yellow("writing files and running commands"))} from the DevTools UI.`,
|
|
553
|
+
colors.bold(info || "Unknown"),
|
|
554
|
+
"",
|
|
555
|
+
"Please open the following URL in the browser:",
|
|
556
|
+
colors.bold(colors.green(`${origin}${ROUTE_AUTH}?token=${token}`)),
|
|
557
|
+
"",
|
|
558
|
+
"Or manually copy and paste the following token:",
|
|
559
|
+
colors.bold(colors.cyan(token))
|
|
560
|
+
];
|
|
561
|
+
logger.box({
|
|
562
|
+
message: message.join("\n"),
|
|
563
|
+
title: colors.bold(colors.yellow(" Permission Request ")),
|
|
564
|
+
style: {
|
|
565
|
+
borderColor: "yellow",
|
|
566
|
+
borderStyle: "rounded"
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
},
|
|
570
|
+
async verifyAuthToken(token) {
|
|
571
|
+
if (options.disableAuthorization)
|
|
572
|
+
return true;
|
|
573
|
+
return token === await getDevAuthToken();
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const HASH_RE = /#/g;
|
|
579
|
+
const AMPERSAND_RE = /&/g;
|
|
580
|
+
const SLASH_RE = /\//g;
|
|
581
|
+
const EQUAL_RE = /=/g;
|
|
582
|
+
const PLUS_RE = /\+/g;
|
|
583
|
+
const ENC_CARET_RE = /%5e/gi;
|
|
584
|
+
const ENC_BACKTICK_RE = /%60/gi;
|
|
585
|
+
const ENC_PIPE_RE = /%7c/gi;
|
|
586
|
+
const ENC_SPACE_RE = /%20/gi;
|
|
587
|
+
function encode(text) {
|
|
588
|
+
return encodeURI("" + text).replace(ENC_PIPE_RE, "|");
|
|
589
|
+
}
|
|
590
|
+
function encodeQueryValue(input) {
|
|
591
|
+
return encode(typeof input === "string" ? input : JSON.stringify(input)).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CARET_RE, "^").replace(SLASH_RE, "%2F");
|
|
592
|
+
}
|
|
593
|
+
function encodeQueryKey(text) {
|
|
594
|
+
return encodeQueryValue(text).replace(EQUAL_RE, "%3D");
|
|
595
|
+
}
|
|
596
|
+
function decode(text = "") {
|
|
597
|
+
try {
|
|
598
|
+
return decodeURIComponent("" + text);
|
|
599
|
+
} catch {
|
|
600
|
+
return "" + text;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function decodeQueryKey(text) {
|
|
604
|
+
return decode(text.replace(PLUS_RE, " "));
|
|
605
|
+
}
|
|
606
|
+
function decodeQueryValue(text) {
|
|
607
|
+
return decode(text.replace(PLUS_RE, " "));
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function parseQuery(parametersString = "") {
|
|
611
|
+
const object = {};
|
|
612
|
+
if (parametersString[0] === "?") {
|
|
613
|
+
parametersString = parametersString.slice(1);
|
|
614
|
+
}
|
|
615
|
+
for (const parameter of parametersString.split("&")) {
|
|
616
|
+
const s = parameter.match(/([^=]+)=?(.*)/) || [];
|
|
617
|
+
if (s.length < 2) {
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
const key = decodeQueryKey(s[1]);
|
|
621
|
+
if (key === "__proto__" || key === "constructor") {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
const value = decodeQueryValue(s[2] || "");
|
|
625
|
+
if (object[key] === void 0) {
|
|
626
|
+
object[key] = value;
|
|
627
|
+
} else if (Array.isArray(object[key])) {
|
|
628
|
+
object[key].push(value);
|
|
629
|
+
} else {
|
|
630
|
+
object[key] = [object[key], value];
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return object;
|
|
634
|
+
}
|
|
635
|
+
function encodeQueryItem(key, value) {
|
|
636
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
637
|
+
value = String(value);
|
|
638
|
+
}
|
|
639
|
+
if (!value) {
|
|
640
|
+
return encodeQueryKey(key);
|
|
641
|
+
}
|
|
642
|
+
if (Array.isArray(value)) {
|
|
643
|
+
return value.map((_value) => `${encodeQueryKey(key)}=${encodeQueryValue(_value)}`).join("&");
|
|
644
|
+
}
|
|
645
|
+
return `${encodeQueryKey(key)}=${encodeQueryValue(value)}`;
|
|
646
|
+
}
|
|
647
|
+
function stringifyQuery(query) {
|
|
648
|
+
return Object.keys(query).filter((k) => query[k] !== void 0).map((k) => encodeQueryItem(k, query[k])).filter(Boolean).join("&");
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const PROTOCOL_STRICT_REGEX = /^[\s\w\0+.-]{2,}:([/\\]{1,2})/;
|
|
652
|
+
const PROTOCOL_REGEX = /^[\s\w\0+.-]{2,}:([/\\]{2})?/;
|
|
653
|
+
const PROTOCOL_RELATIVE_REGEX = /^([/\\]\s*){2,}[^/\\]/;
|
|
654
|
+
const TRAILING_SLASH_RE = /\/$|\/\?|\/#/;
|
|
655
|
+
const JOIN_LEADING_SLASH_RE = /^\.?\//;
|
|
656
|
+
function hasProtocol(inputString, opts = {}) {
|
|
657
|
+
if (typeof opts === "boolean") {
|
|
658
|
+
opts = { acceptRelative: opts };
|
|
659
|
+
}
|
|
660
|
+
if (opts.strict) {
|
|
661
|
+
return PROTOCOL_STRICT_REGEX.test(inputString);
|
|
662
|
+
}
|
|
663
|
+
return PROTOCOL_REGEX.test(inputString) || (opts.acceptRelative ? PROTOCOL_RELATIVE_REGEX.test(inputString) : false);
|
|
664
|
+
}
|
|
665
|
+
function hasTrailingSlash(input = "", respectQueryAndFragment) {
|
|
666
|
+
if (!respectQueryAndFragment) {
|
|
667
|
+
return input.endsWith("/");
|
|
668
|
+
}
|
|
669
|
+
return TRAILING_SLASH_RE.test(input);
|
|
670
|
+
}
|
|
671
|
+
function withoutTrailingSlash(input = "", respectQueryAndFragment) {
|
|
672
|
+
if (!respectQueryAndFragment) {
|
|
673
|
+
return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || "/";
|
|
674
|
+
}
|
|
675
|
+
if (!hasTrailingSlash(input, true)) {
|
|
676
|
+
return input || "/";
|
|
677
|
+
}
|
|
678
|
+
let path = input;
|
|
679
|
+
let fragment = "";
|
|
680
|
+
const fragmentIndex = input.indexOf("#");
|
|
681
|
+
if (fragmentIndex >= 0) {
|
|
682
|
+
path = input.slice(0, fragmentIndex);
|
|
683
|
+
fragment = input.slice(fragmentIndex);
|
|
684
|
+
}
|
|
685
|
+
const [s0, ...s] = path.split("?");
|
|
686
|
+
const cleanPath = s0.endsWith("/") ? s0.slice(0, -1) : s0;
|
|
687
|
+
return (cleanPath || "/") + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
|
|
688
|
+
}
|
|
689
|
+
function withTrailingSlash(input = "", respectQueryAndFragment) {
|
|
690
|
+
if (!respectQueryAndFragment) {
|
|
691
|
+
return input.endsWith("/") ? input : input + "/";
|
|
692
|
+
}
|
|
693
|
+
if (hasTrailingSlash(input, true)) {
|
|
694
|
+
return input || "/";
|
|
695
|
+
}
|
|
696
|
+
let path = input;
|
|
697
|
+
let fragment = "";
|
|
698
|
+
const fragmentIndex = input.indexOf("#");
|
|
699
|
+
if (fragmentIndex >= 0) {
|
|
700
|
+
path = input.slice(0, fragmentIndex);
|
|
701
|
+
fragment = input.slice(fragmentIndex);
|
|
702
|
+
if (!path) {
|
|
703
|
+
return fragment;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
const [s0, ...s] = path.split("?");
|
|
707
|
+
return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
|
|
708
|
+
}
|
|
709
|
+
function withBase(input, base) {
|
|
710
|
+
if (isEmptyURL(base) || hasProtocol(input)) {
|
|
711
|
+
return input;
|
|
712
|
+
}
|
|
713
|
+
const _base = withoutTrailingSlash(base);
|
|
714
|
+
if (input.startsWith(_base)) {
|
|
715
|
+
return input;
|
|
716
|
+
}
|
|
717
|
+
return joinURL(_base, input);
|
|
718
|
+
}
|
|
719
|
+
function withQuery(input, query) {
|
|
720
|
+
const parsed = parseURL(input);
|
|
721
|
+
const mergedQuery = { ...parseQuery(parsed.search), ...query };
|
|
722
|
+
parsed.search = stringifyQuery(mergedQuery);
|
|
723
|
+
return stringifyParsedURL(parsed);
|
|
724
|
+
}
|
|
725
|
+
function isEmptyURL(url) {
|
|
726
|
+
return !url || url === "/";
|
|
727
|
+
}
|
|
728
|
+
function isNonEmptyURL(url) {
|
|
729
|
+
return url && url !== "/";
|
|
730
|
+
}
|
|
731
|
+
function joinURL(base, ...input) {
|
|
732
|
+
let url = base || "";
|
|
733
|
+
for (const segment of input.filter((url2) => isNonEmptyURL(url2))) {
|
|
734
|
+
if (url) {
|
|
735
|
+
const _segment = segment.replace(JOIN_LEADING_SLASH_RE, "");
|
|
736
|
+
url = withTrailingSlash(url) + _segment;
|
|
737
|
+
} else {
|
|
738
|
+
url = segment;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return url;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const protocolRelative = Symbol.for("ufo:protocolRelative");
|
|
745
|
+
function parseURL(input = "", defaultProto) {
|
|
746
|
+
const _specialProtoMatch = input.match(
|
|
747
|
+
/^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i
|
|
748
|
+
);
|
|
749
|
+
if (_specialProtoMatch) {
|
|
750
|
+
const [, _proto, _pathname = ""] = _specialProtoMatch;
|
|
751
|
+
return {
|
|
752
|
+
protocol: _proto.toLowerCase(),
|
|
753
|
+
pathname: _pathname,
|
|
754
|
+
href: _proto + _pathname,
|
|
755
|
+
auth: "",
|
|
756
|
+
host: "",
|
|
757
|
+
search: "",
|
|
758
|
+
hash: ""
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
if (!hasProtocol(input, { acceptRelative: true })) {
|
|
762
|
+
return defaultProto ? parseURL(defaultProto + input) : parsePath(input);
|
|
763
|
+
}
|
|
764
|
+
const [, protocol = "", auth, hostAndPath = ""] = input.replace(/\\/g, "/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/) || [];
|
|
765
|
+
let [, host = "", path = ""] = hostAndPath.match(/([^#/?]*)(.*)?/) || [];
|
|
766
|
+
if (protocol === "file:") {
|
|
767
|
+
path = path.replace(/\/(?=[A-Za-z]:)/, "");
|
|
768
|
+
}
|
|
769
|
+
const { pathname, search, hash } = parsePath(path);
|
|
770
|
+
return {
|
|
771
|
+
protocol: protocol.toLowerCase(),
|
|
772
|
+
auth: auth ? auth.slice(0, Math.max(0, auth.length - 1)) : "",
|
|
773
|
+
host,
|
|
774
|
+
pathname,
|
|
775
|
+
search,
|
|
776
|
+
hash,
|
|
777
|
+
[protocolRelative]: !protocol
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function parsePath(input = "") {
|
|
781
|
+
const [pathname = "", search = "", hash = ""] = (input.match(/([^#?]*)(\?[^#]*)?(#.*)?/) || []).splice(1);
|
|
782
|
+
return {
|
|
783
|
+
pathname,
|
|
784
|
+
search,
|
|
785
|
+
hash
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
function stringifyParsedURL(parsed) {
|
|
789
|
+
const pathname = parsed.pathname || "";
|
|
790
|
+
const search = parsed.search ? (parsed.search.startsWith("?") ? "" : "?") + parsed.search : "";
|
|
791
|
+
const hash = parsed.hash || "";
|
|
792
|
+
const auth = parsed.auth ? parsed.auth + "@" : "";
|
|
793
|
+
const host = parsed.host || "";
|
|
794
|
+
const proto = parsed.protocol || parsed[protocolRelative] ? (parsed.protocol || "") + "//" : "";
|
|
795
|
+
return proto + auth + host + pathname + search + hash;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
class FetchError extends Error {
|
|
799
|
+
constructor(message, opts) {
|
|
800
|
+
super(message, opts);
|
|
801
|
+
this.name = "FetchError";
|
|
802
|
+
if (opts?.cause && !this.cause) {
|
|
803
|
+
this.cause = opts.cause;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
function createFetchError(ctx) {
|
|
808
|
+
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
809
|
+
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
810
|
+
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
811
|
+
const requestStr = `[${method}] ${JSON.stringify(url)}`;
|
|
812
|
+
const statusStr = ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>";
|
|
813
|
+
const message = `${requestStr}: ${statusStr}${errorMessage ? ` ${errorMessage}` : ""}`;
|
|
814
|
+
const fetchError = new FetchError(
|
|
815
|
+
message,
|
|
816
|
+
ctx.error ? { cause: ctx.error } : void 0
|
|
817
|
+
);
|
|
818
|
+
for (const key of ["request", "options", "response"]) {
|
|
819
|
+
Object.defineProperty(fetchError, key, {
|
|
820
|
+
get() {
|
|
821
|
+
return ctx[key];
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
for (const [key, refKey] of [
|
|
826
|
+
["data", "_data"],
|
|
827
|
+
["status", "status"],
|
|
828
|
+
["statusCode", "status"],
|
|
829
|
+
["statusText", "statusText"],
|
|
830
|
+
["statusMessage", "statusText"]
|
|
831
|
+
]) {
|
|
832
|
+
Object.defineProperty(fetchError, key, {
|
|
833
|
+
get() {
|
|
834
|
+
return ctx.response && ctx.response[refKey];
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
return fetchError;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
const payloadMethods = new Set(
|
|
842
|
+
Object.freeze(["PATCH", "POST", "PUT", "DELETE"])
|
|
843
|
+
);
|
|
844
|
+
function isPayloadMethod(method = "GET") {
|
|
845
|
+
return payloadMethods.has(method.toUpperCase());
|
|
846
|
+
}
|
|
847
|
+
function isJSONSerializable(value) {
|
|
848
|
+
if (value === void 0) {
|
|
849
|
+
return false;
|
|
850
|
+
}
|
|
851
|
+
const t = typeof value;
|
|
852
|
+
if (t === "string" || t === "number" || t === "boolean" || t === null) {
|
|
853
|
+
return true;
|
|
854
|
+
}
|
|
855
|
+
if (t !== "object") {
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
if (Array.isArray(value)) {
|
|
859
|
+
return true;
|
|
860
|
+
}
|
|
861
|
+
if (value.buffer) {
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
865
|
+
}
|
|
866
|
+
const textTypes = /* @__PURE__ */ new Set([
|
|
867
|
+
"image/svg",
|
|
868
|
+
"application/xml",
|
|
869
|
+
"application/xhtml",
|
|
870
|
+
"application/html"
|
|
871
|
+
]);
|
|
872
|
+
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
873
|
+
function detectResponseType(_contentType = "") {
|
|
874
|
+
if (!_contentType) {
|
|
875
|
+
return "json";
|
|
876
|
+
}
|
|
877
|
+
const contentType = _contentType.split(";").shift() || "";
|
|
878
|
+
if (JSON_RE.test(contentType)) {
|
|
879
|
+
return "json";
|
|
880
|
+
}
|
|
881
|
+
if (textTypes.has(contentType) || contentType.startsWith("text/")) {
|
|
882
|
+
return "text";
|
|
883
|
+
}
|
|
884
|
+
return "blob";
|
|
885
|
+
}
|
|
886
|
+
function resolveFetchOptions(request, input, defaults, Headers) {
|
|
887
|
+
const headers = mergeHeaders(
|
|
888
|
+
input?.headers ?? request?.headers,
|
|
889
|
+
defaults?.headers,
|
|
890
|
+
Headers
|
|
891
|
+
);
|
|
892
|
+
let query;
|
|
893
|
+
if (defaults?.query || defaults?.params || input?.params || input?.query) {
|
|
894
|
+
query = {
|
|
895
|
+
...defaults?.params,
|
|
896
|
+
...defaults?.query,
|
|
897
|
+
...input?.params,
|
|
898
|
+
...input?.query
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
return {
|
|
902
|
+
...defaults,
|
|
903
|
+
...input,
|
|
904
|
+
query,
|
|
905
|
+
params: query,
|
|
906
|
+
headers
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
function mergeHeaders(input, defaults, Headers) {
|
|
910
|
+
if (!defaults) {
|
|
911
|
+
return new Headers(input);
|
|
912
|
+
}
|
|
913
|
+
const headers = new Headers(defaults);
|
|
914
|
+
if (input) {
|
|
915
|
+
for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) {
|
|
916
|
+
headers.set(key, value);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return headers;
|
|
920
|
+
}
|
|
921
|
+
async function callHooks(context, hooks) {
|
|
922
|
+
if (hooks) {
|
|
923
|
+
if (Array.isArray(hooks)) {
|
|
924
|
+
for (const hook of hooks) {
|
|
925
|
+
await hook(context);
|
|
926
|
+
}
|
|
927
|
+
} else {
|
|
928
|
+
await hooks(context);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const retryStatusCodes = /* @__PURE__ */ new Set([
|
|
934
|
+
408,
|
|
935
|
+
// Request Timeout
|
|
936
|
+
409,
|
|
937
|
+
// Conflict
|
|
938
|
+
425,
|
|
939
|
+
// Too Early (Experimental)
|
|
940
|
+
429,
|
|
941
|
+
// Too Many Requests
|
|
942
|
+
500,
|
|
943
|
+
// Internal Server Error
|
|
944
|
+
502,
|
|
945
|
+
// Bad Gateway
|
|
946
|
+
503,
|
|
947
|
+
// Service Unavailable
|
|
948
|
+
504
|
|
949
|
+
// Gateway Timeout
|
|
950
|
+
]);
|
|
951
|
+
const nullBodyResponses = /* @__PURE__ */ new Set([101, 204, 205, 304]);
|
|
952
|
+
function createFetch(globalOptions = {}) {
|
|
953
|
+
const {
|
|
954
|
+
fetch = globalThis.fetch,
|
|
955
|
+
Headers = globalThis.Headers,
|
|
956
|
+
AbortController = globalThis.AbortController
|
|
957
|
+
} = globalOptions;
|
|
958
|
+
async function onError(context) {
|
|
959
|
+
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
|
|
960
|
+
if (context.options.retry !== false && !isAbort) {
|
|
961
|
+
let retries;
|
|
962
|
+
if (typeof context.options.retry === "number") {
|
|
963
|
+
retries = context.options.retry;
|
|
964
|
+
} else {
|
|
965
|
+
retries = isPayloadMethod(context.options.method) ? 0 : 1;
|
|
966
|
+
}
|
|
967
|
+
const responseCode = context.response && context.response.status || 500;
|
|
968
|
+
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
|
|
969
|
+
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
|
|
970
|
+
if (retryDelay > 0) {
|
|
971
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
972
|
+
}
|
|
973
|
+
return $fetchRaw(context.request, {
|
|
974
|
+
...context.options,
|
|
975
|
+
retry: retries - 1
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
const error = createFetchError(context);
|
|
980
|
+
if (Error.captureStackTrace) {
|
|
981
|
+
Error.captureStackTrace(error, $fetchRaw);
|
|
982
|
+
}
|
|
983
|
+
throw error;
|
|
984
|
+
}
|
|
985
|
+
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
|
|
986
|
+
const context = {
|
|
987
|
+
request: _request,
|
|
988
|
+
options: resolveFetchOptions(
|
|
989
|
+
_request,
|
|
990
|
+
_options,
|
|
991
|
+
globalOptions.defaults,
|
|
992
|
+
Headers
|
|
993
|
+
),
|
|
994
|
+
response: void 0,
|
|
995
|
+
error: void 0
|
|
996
|
+
};
|
|
997
|
+
if (context.options.method) {
|
|
998
|
+
context.options.method = context.options.method.toUpperCase();
|
|
999
|
+
}
|
|
1000
|
+
if (context.options.onRequest) {
|
|
1001
|
+
await callHooks(context, context.options.onRequest);
|
|
1002
|
+
}
|
|
1003
|
+
if (typeof context.request === "string") {
|
|
1004
|
+
if (context.options.baseURL) {
|
|
1005
|
+
context.request = withBase(context.request, context.options.baseURL);
|
|
1006
|
+
}
|
|
1007
|
+
if (context.options.query) {
|
|
1008
|
+
context.request = withQuery(context.request, context.options.query);
|
|
1009
|
+
delete context.options.query;
|
|
1010
|
+
}
|
|
1011
|
+
if ("query" in context.options) {
|
|
1012
|
+
delete context.options.query;
|
|
1013
|
+
}
|
|
1014
|
+
if ("params" in context.options) {
|
|
1015
|
+
delete context.options.params;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (context.options.body && isPayloadMethod(context.options.method)) {
|
|
1019
|
+
if (isJSONSerializable(context.options.body)) {
|
|
1020
|
+
context.options.body = typeof context.options.body === "string" ? context.options.body : JSON.stringify(context.options.body);
|
|
1021
|
+
context.options.headers = new Headers(context.options.headers || {});
|
|
1022
|
+
if (!context.options.headers.has("content-type")) {
|
|
1023
|
+
context.options.headers.set("content-type", "application/json");
|
|
1024
|
+
}
|
|
1025
|
+
if (!context.options.headers.has("accept")) {
|
|
1026
|
+
context.options.headers.set("accept", "application/json");
|
|
1027
|
+
}
|
|
1028
|
+
} else if (
|
|
1029
|
+
// ReadableStream Body
|
|
1030
|
+
"pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || // Node.js Stream Body
|
|
1031
|
+
typeof context.options.body.pipe === "function"
|
|
1032
|
+
) {
|
|
1033
|
+
if (!("duplex" in context.options)) {
|
|
1034
|
+
context.options.duplex = "half";
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
let abortTimeout;
|
|
1039
|
+
if (!context.options.signal && context.options.timeout) {
|
|
1040
|
+
const controller = new AbortController();
|
|
1041
|
+
abortTimeout = setTimeout(() => {
|
|
1042
|
+
const error = new Error(
|
|
1043
|
+
"[TimeoutError]: The operation was aborted due to timeout"
|
|
1044
|
+
);
|
|
1045
|
+
error.name = "TimeoutError";
|
|
1046
|
+
error.code = 23;
|
|
1047
|
+
controller.abort(error);
|
|
1048
|
+
}, context.options.timeout);
|
|
1049
|
+
context.options.signal = controller.signal;
|
|
1050
|
+
}
|
|
1051
|
+
try {
|
|
1052
|
+
context.response = await fetch(
|
|
1053
|
+
context.request,
|
|
1054
|
+
context.options
|
|
1055
|
+
);
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
context.error = error;
|
|
1058
|
+
if (context.options.onRequestError) {
|
|
1059
|
+
await callHooks(
|
|
1060
|
+
context,
|
|
1061
|
+
context.options.onRequestError
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
return await onError(context);
|
|
1065
|
+
} finally {
|
|
1066
|
+
if (abortTimeout) {
|
|
1067
|
+
clearTimeout(abortTimeout);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
const hasBody = (context.response.body || // https://github.com/unjs/ofetch/issues/324
|
|
1071
|
+
// https://github.com/unjs/ofetch/issues/294
|
|
1072
|
+
// https://github.com/JakeChampion/fetch/issues/1454
|
|
1073
|
+
context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD";
|
|
1074
|
+
if (hasBody) {
|
|
1075
|
+
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
|
|
1076
|
+
switch (responseType) {
|
|
1077
|
+
case "json": {
|
|
1078
|
+
const data = await context.response.text();
|
|
1079
|
+
const parseFunction = context.options.parseResponse || destr;
|
|
1080
|
+
context.response._data = parseFunction(data);
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
case "stream": {
|
|
1084
|
+
context.response._data = context.response.body || context.response._bodyInit;
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
default: {
|
|
1088
|
+
context.response._data = await context.response[responseType]();
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
if (context.options.onResponse) {
|
|
1093
|
+
await callHooks(
|
|
1094
|
+
context,
|
|
1095
|
+
context.options.onResponse
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
|
|
1099
|
+
if (context.options.onResponseError) {
|
|
1100
|
+
await callHooks(
|
|
1101
|
+
context,
|
|
1102
|
+
context.options.onResponseError
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
return await onError(context);
|
|
1106
|
+
}
|
|
1107
|
+
return context.response;
|
|
1108
|
+
};
|
|
1109
|
+
const $fetch = async function $fetch2(request, options) {
|
|
1110
|
+
const r = await $fetchRaw(request, options);
|
|
1111
|
+
return r._data;
|
|
1112
|
+
};
|
|
1113
|
+
$fetch.raw = $fetchRaw;
|
|
1114
|
+
$fetch.native = (...args) => fetch(...args);
|
|
1115
|
+
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
|
|
1116
|
+
...globalOptions,
|
|
1117
|
+
...customGlobalOptions,
|
|
1118
|
+
defaults: {
|
|
1119
|
+
...globalOptions.defaults,
|
|
1120
|
+
...customGlobalOptions.defaults,
|
|
1121
|
+
...defaultOptions
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
return $fetch;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
const _globalThis = function() {
|
|
1128
|
+
if (typeof globalThis !== "undefined") {
|
|
1129
|
+
return globalThis;
|
|
1130
|
+
}
|
|
1131
|
+
if (typeof self !== "undefined") {
|
|
1132
|
+
return self;
|
|
1133
|
+
}
|
|
1134
|
+
if (typeof window !== "undefined") {
|
|
1135
|
+
return window;
|
|
1136
|
+
}
|
|
1137
|
+
if (typeof global !== "undefined") {
|
|
1138
|
+
return global;
|
|
1139
|
+
}
|
|
1140
|
+
throw new Error("unable to locate global object");
|
|
1141
|
+
}();
|
|
1142
|
+
const fetch = _globalThis.fetch ? (...args) => _globalThis.fetch(...args) : () => Promise.reject(new Error("[ofetch] global.fetch is not supported!"));
|
|
1143
|
+
const Headers = _globalThis.Headers;
|
|
1144
|
+
const AbortController = _globalThis.AbortController;
|
|
1145
|
+
createFetch({ fetch, Headers, AbortController });
|
|
1146
|
+
|
|
1147
|
+
async function checkForUpdateOf(name, current, nuxt = useNuxt()) {
|
|
1148
|
+
try {
|
|
1149
|
+
if (!current) {
|
|
1150
|
+
const require = createRequire(nuxt.options.rootDir);
|
|
1151
|
+
const modulePaths = [
|
|
1152
|
+
...nuxt.options.modulesDir,
|
|
1153
|
+
...require.resolve.paths(name) || []
|
|
1154
|
+
];
|
|
1155
|
+
const info = await getPackageInfo(name, { paths: modulePaths });
|
|
1156
|
+
if (!info)
|
|
1157
|
+
return;
|
|
1158
|
+
current = info.packageJson.version;
|
|
1159
|
+
}
|
|
1160
|
+
if (!current)
|
|
1161
|
+
return;
|
|
1162
|
+
const { getLatestVersion } = await import('fast-npm-meta');
|
|
1163
|
+
const { version: latest } = await getLatestVersion(name, {
|
|
1164
|
+
fetch
|
|
1165
|
+
});
|
|
1166
|
+
const needsUpdate = !!latest && latest !== current && semver.lt(current, latest);
|
|
1167
|
+
return {
|
|
1168
|
+
name,
|
|
1169
|
+
current,
|
|
1170
|
+
latest: latest || current,
|
|
1171
|
+
needsUpdate
|
|
1172
|
+
};
|
|
1173
|
+
} catch (e) {
|
|
1174
|
+
logger.warn(`Failed to check for update of ${name}:`);
|
|
1175
|
+
logger.warn(e);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
async function magicastGuard(fn, message = "") {
|
|
1180
|
+
let generated;
|
|
1181
|
+
try {
|
|
1182
|
+
generated = await fn();
|
|
1183
|
+
} catch (e) {
|
|
1184
|
+
logger.error(e);
|
|
1185
|
+
throw new Error(`Magicast failed to modify Nuxt config automatically. Maybe the config are composed too dynamically that we failed to statically analyze it. ${message}`);
|
|
1186
|
+
}
|
|
1187
|
+
return generated;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
function setupNpmRPC({ nuxt, ensureDevAuthToken }) {
|
|
1191
|
+
let detectPromise;
|
|
1192
|
+
const updatesPromise = /* @__PURE__ */ new Map();
|
|
1193
|
+
function getPackageManager() {
|
|
1194
|
+
detectPromise ||= detectPackageManager(nuxt.options.rootDir);
|
|
1195
|
+
return detectPromise;
|
|
1196
|
+
}
|
|
1197
|
+
async function getNpmCommand(command, packageName, options = {}) {
|
|
1198
|
+
const {
|
|
1199
|
+
dev = true,
|
|
1200
|
+
global = packageName === "@nuxt/devtools" && isInstalledGlobally
|
|
1201
|
+
} = options;
|
|
1202
|
+
const agent = await getPackageManager();
|
|
1203
|
+
const name = agent?.name || "npm";
|
|
1204
|
+
if (command === "install" || command === "update") {
|
|
1205
|
+
return [
|
|
1206
|
+
name,
|
|
1207
|
+
name === "npm" ? "install" : "add",
|
|
1208
|
+
`${packageName}@latest`,
|
|
1209
|
+
dev ? "-D" : "",
|
|
1210
|
+
global ? "-g" : "",
|
|
1211
|
+
// In yarn berry, `--ignore-scripts` is removed
|
|
1212
|
+
name === "yarn" && !agent?.version?.startsWith("1.") ? "" : "--ignore-scripts"
|
|
1213
|
+
].filter(Boolean);
|
|
1214
|
+
}
|
|
1215
|
+
if (command === "uninstall") {
|
|
1216
|
+
return [
|
|
1217
|
+
name,
|
|
1218
|
+
name === "npm" ? "uninstall" : "remove",
|
|
1219
|
+
packageName,
|
|
1220
|
+
global ? "-g" : ""
|
|
1221
|
+
].filter(Boolean);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
async function runNpmCommand(command, packageName, options = {}) {
|
|
1225
|
+
const args = await getNpmCommand(command, packageName, options);
|
|
1226
|
+
if (!args)
|
|
1227
|
+
return;
|
|
1228
|
+
const processId = `npm:${command}:${packageName}`;
|
|
1229
|
+
startSubprocess({
|
|
1230
|
+
command: args[0],
|
|
1231
|
+
args: args.slice(1)
|
|
1232
|
+
}, {
|
|
1233
|
+
id: processId,
|
|
1234
|
+
name: `${command} ${packageName}`,
|
|
1235
|
+
icon: "i-logos-npm-icon",
|
|
1236
|
+
restartable: false
|
|
1237
|
+
});
|
|
1238
|
+
return {
|
|
1239
|
+
processId
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
const installSet = /* @__PURE__ */ new Set();
|
|
1243
|
+
let latestGenerated = null;
|
|
1244
|
+
return {
|
|
1245
|
+
checkForUpdateFor(name) {
|
|
1246
|
+
if (!updatesPromise.has(name))
|
|
1247
|
+
updatesPromise.set(name, checkForUpdateOf(name, void 0, nuxt));
|
|
1248
|
+
return updatesPromise.get(name);
|
|
1249
|
+
},
|
|
1250
|
+
getNpmCommand,
|
|
1251
|
+
async runNpmCommand(token, ...args) {
|
|
1252
|
+
await ensureDevAuthToken(token);
|
|
1253
|
+
return runNpmCommand(...args);
|
|
1254
|
+
},
|
|
1255
|
+
async installNuxtModule(token, name, dry = true) {
|
|
1256
|
+
await ensureDevAuthToken(token);
|
|
1257
|
+
const commands = await getNpmCommand("install", name, { dev: true });
|
|
1258
|
+
const filepath = nuxt.options._nuxtConfigFile;
|
|
1259
|
+
let source = latestGenerated;
|
|
1260
|
+
if (source == null)
|
|
1261
|
+
source = await fs.readFile(filepath, "utf-8");
|
|
1262
|
+
const generated = await magicastGuard(async () => {
|
|
1263
|
+
const mod = parseModule(source, { sourceFileName: filepath });
|
|
1264
|
+
addNuxtModule(mod, name);
|
|
1265
|
+
return mod.generate().code;
|
|
1266
|
+
});
|
|
1267
|
+
const processId = `nuxt:add-module:${name}`;
|
|
1268
|
+
if (!dry) {
|
|
1269
|
+
latestGenerated = generated;
|
|
1270
|
+
installSet.add(name);
|
|
1271
|
+
const process = startSubprocess({
|
|
1272
|
+
command: commands[0],
|
|
1273
|
+
args: commands.slice(1)
|
|
1274
|
+
}, {
|
|
1275
|
+
id: processId,
|
|
1276
|
+
name: `Install ${name}`,
|
|
1277
|
+
icon: "carbon:intent-request-create",
|
|
1278
|
+
restartable: false
|
|
1279
|
+
});
|
|
1280
|
+
const execa = process.getProcess();
|
|
1281
|
+
const result = await execa;
|
|
1282
|
+
await Promise.resolve();
|
|
1283
|
+
installSet.delete(name);
|
|
1284
|
+
const code = result.exitCode;
|
|
1285
|
+
if (code !== 0) {
|
|
1286
|
+
console.error(result.stderr);
|
|
1287
|
+
throw new Error(`Failed to install module, process exited with ${code}`);
|
|
1288
|
+
}
|
|
1289
|
+
if (installSet.size === 0) {
|
|
1290
|
+
latestGenerated = null;
|
|
1291
|
+
await fs.writeFile(filepath, generated, "utf-8");
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
return {
|
|
1295
|
+
configOriginal: source,
|
|
1296
|
+
configGenerated: generated,
|
|
1297
|
+
commands,
|
|
1298
|
+
processId
|
|
1299
|
+
};
|
|
1300
|
+
},
|
|
1301
|
+
async uninstallNuxtModule(token, name, dry = true) {
|
|
1302
|
+
await ensureDevAuthToken(token);
|
|
1303
|
+
const commands = await getNpmCommand("uninstall", name);
|
|
1304
|
+
const filepath = nuxt.options._nuxtConfigFile;
|
|
1305
|
+
const source = await fs.readFile(filepath, "utf-8");
|
|
1306
|
+
const generated = await magicastGuard(async () => {
|
|
1307
|
+
const mod = parseModule(source, { sourceFileName: filepath });
|
|
1308
|
+
const config = getDefaultExportOptions(mod);
|
|
1309
|
+
config.modules ||= [];
|
|
1310
|
+
if (config.modules.includes(name)) {
|
|
1311
|
+
Object.values(config.modules).forEach((value, index) => {
|
|
1312
|
+
if (value === name)
|
|
1313
|
+
config.modules.splice(index - 1, 1);
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
return mod.generate().code;
|
|
1317
|
+
});
|
|
1318
|
+
const processId = `nuxt:remove-module:${name}`;
|
|
1319
|
+
if (!dry) {
|
|
1320
|
+
const process = startSubprocess({
|
|
1321
|
+
command: commands[0],
|
|
1322
|
+
args: commands.slice(1)
|
|
1323
|
+
}, {
|
|
1324
|
+
id: processId,
|
|
1325
|
+
name: `Uninstall ${name}`,
|
|
1326
|
+
icon: "carbon:intent-request-uninstall",
|
|
1327
|
+
restartable: false
|
|
1328
|
+
});
|
|
1329
|
+
const execa = process.getProcess();
|
|
1330
|
+
const result = await execa;
|
|
1331
|
+
await Promise.resolve();
|
|
1332
|
+
const code = result.exitCode;
|
|
1333
|
+
if (code !== 0) {
|
|
1334
|
+
console.error(result.stderr);
|
|
1335
|
+
throw new Error(`Failed to uninstall module', process exited with ${code}`);
|
|
1336
|
+
}
|
|
1337
|
+
await fs.writeFile(filepath, generated, "utf-8");
|
|
1338
|
+
}
|
|
1339
|
+
return {
|
|
1340
|
+
configOriginal: source,
|
|
1341
|
+
configGenerated: generated,
|
|
1342
|
+
commands,
|
|
1343
|
+
processId
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
let options;
|
|
1350
|
+
function getOptions() {
|
|
1351
|
+
return options;
|
|
1352
|
+
}
|
|
1353
|
+
function setupOptionsRPC({ nuxt }) {
|
|
1354
|
+
async function getOptions2(tab) {
|
|
1355
|
+
if (!options || options[tab]) {
|
|
1356
|
+
options = defaultTabOptions;
|
|
1357
|
+
await read(tab);
|
|
1358
|
+
}
|
|
1359
|
+
return options[tab];
|
|
1360
|
+
}
|
|
1361
|
+
async function read(tab) {
|
|
1362
|
+
options[tab] = await readLocalOptions(defaultTabOptions[tab], {
|
|
1363
|
+
root: nuxt.options.rootDir,
|
|
1364
|
+
key: tab !== "ui" && tab
|
|
1365
|
+
});
|
|
1366
|
+
return options;
|
|
1367
|
+
}
|
|
1368
|
+
getOptions2("ui");
|
|
1369
|
+
async function clearOptions() {
|
|
1370
|
+
options = void 0;
|
|
1371
|
+
await clearLocalOptions({
|
|
1372
|
+
root: nuxt.options.rootDir
|
|
1373
|
+
});
|
|
1374
|
+
}
|
|
1375
|
+
return {
|
|
1376
|
+
async updateOptions(tab, _settings) {
|
|
1377
|
+
const settings = await getOptions2(tab);
|
|
1378
|
+
Object.assign(settings, _settings);
|
|
1379
|
+
await writeLocalOptions(
|
|
1380
|
+
{ ...settings },
|
|
1381
|
+
{
|
|
1382
|
+
root: nuxt.options.rootDir,
|
|
1383
|
+
key: tab !== "ui" && tab
|
|
1384
|
+
}
|
|
1385
|
+
);
|
|
1386
|
+
nuxt.callHook("builder:generateApp", {
|
|
1387
|
+
filter(template) {
|
|
1388
|
+
return template.filename.includes("devtools/settings.js");
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
},
|
|
1392
|
+
getOptions: getOptions2,
|
|
1393
|
+
clearOptions
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
function setupServerRoutesRPC({ nuxt, refresh }) {
|
|
1398
|
+
let nitro;
|
|
1399
|
+
let cache = null;
|
|
1400
|
+
const refreshDebounced = debounce(() => {
|
|
1401
|
+
cache = null;
|
|
1402
|
+
refresh("getServerRoutes");
|
|
1403
|
+
}, 500);
|
|
1404
|
+
nuxt.hook("nitro:init", (_) => {
|
|
1405
|
+
nitro = _;
|
|
1406
|
+
cache = null;
|
|
1407
|
+
refresh("getServerRoutes");
|
|
1408
|
+
});
|
|
1409
|
+
nuxt.hook("ready", () => {
|
|
1410
|
+
nitro?.storage.watch((event, key) => {
|
|
1411
|
+
if (key.startsWith("src:api:") || key.startsWith("src:routes:"))
|
|
1412
|
+
refreshDebounced();
|
|
1413
|
+
});
|
|
1414
|
+
});
|
|
1415
|
+
function scan() {
|
|
1416
|
+
if (cache)
|
|
1417
|
+
return cache;
|
|
1418
|
+
cache = (() => {
|
|
1419
|
+
if (!nitro)
|
|
1420
|
+
return [];
|
|
1421
|
+
return [
|
|
1422
|
+
...nitro.scannedHandlers.filter((item) => !item.middleware).map((item) => ({
|
|
1423
|
+
route: item.route,
|
|
1424
|
+
filepath: item.handler,
|
|
1425
|
+
method: item.method,
|
|
1426
|
+
type: item.route?.startsWith("/api") ? "api" : "route"
|
|
1427
|
+
})),
|
|
1428
|
+
...nitro.options.handlers.filter((item) => !item.route?.startsWith("/_nitro") && !item.route?.startsWith("/__nuxt") && !item.middleware).map((item) => ({
|
|
1429
|
+
route: item.route,
|
|
1430
|
+
filepath: item.handler,
|
|
1431
|
+
method: item.method,
|
|
1432
|
+
type: "runtime"
|
|
1433
|
+
}))
|
|
1434
|
+
];
|
|
1435
|
+
})();
|
|
1436
|
+
return cache;
|
|
1437
|
+
}
|
|
1438
|
+
return {
|
|
1439
|
+
getServerRoutes() {
|
|
1440
|
+
return scan();
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
function setupServerTasksRPC({ nuxt, refresh }) {
|
|
1446
|
+
let nitro;
|
|
1447
|
+
let cache = null;
|
|
1448
|
+
const refreshDebounced = debounce(() => {
|
|
1449
|
+
cache = null;
|
|
1450
|
+
refresh("getServerTasks");
|
|
1451
|
+
}, 500);
|
|
1452
|
+
nuxt.hook("nitro:init", (_) => {
|
|
1453
|
+
nitro = _;
|
|
1454
|
+
cache = null;
|
|
1455
|
+
refresh("getServerTasks");
|
|
1456
|
+
});
|
|
1457
|
+
nuxt.hook("ready", () => {
|
|
1458
|
+
nitro?.storage.watch((event, key) => {
|
|
1459
|
+
if (key.startsWith("src:tasks:"))
|
|
1460
|
+
refreshDebounced();
|
|
1461
|
+
});
|
|
1462
|
+
});
|
|
1463
|
+
function scan() {
|
|
1464
|
+
if (cache)
|
|
1465
|
+
return cache;
|
|
1466
|
+
cache = (() => {
|
|
1467
|
+
if (!nitro) {
|
|
1468
|
+
return {
|
|
1469
|
+
tasks: {},
|
|
1470
|
+
scheduledTasks: {}
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
return {
|
|
1474
|
+
tasks: nitro.options.tasks,
|
|
1475
|
+
scheduledTasks: Object.entries(nitro.options.scheduledTasks ?? {}).reduce((acc, [cron, tasks]) => {
|
|
1476
|
+
acc[cron] = Array.isArray(tasks) ? tasks : [tasks];
|
|
1477
|
+
return acc;
|
|
1478
|
+
}, {})
|
|
1479
|
+
};
|
|
1480
|
+
})();
|
|
1481
|
+
return cache;
|
|
1482
|
+
}
|
|
1483
|
+
return {
|
|
1484
|
+
getServerTasks() {
|
|
1485
|
+
return scan();
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
const IGNORE_STORAGE_MOUNTS = ["root", "build", "src", "cache"];
|
|
1491
|
+
function shouldIgnoreStorageKey(key) {
|
|
1492
|
+
return IGNORE_STORAGE_MOUNTS.includes(key.split(":")[0]);
|
|
1493
|
+
}
|
|
1494
|
+
function setupStorageRPC({
|
|
1495
|
+
nuxt,
|
|
1496
|
+
rpc,
|
|
1497
|
+
ensureDevAuthToken
|
|
1498
|
+
}) {
|
|
1499
|
+
const storageMounts = {};
|
|
1500
|
+
let storage;
|
|
1501
|
+
nuxt.hook("nitro:init", (nitro) => {
|
|
1502
|
+
storage = nitro.storage;
|
|
1503
|
+
nuxt.hook("ready", () => {
|
|
1504
|
+
storage.watch((event, key) => {
|
|
1505
|
+
if (shouldIgnoreStorageKey(key))
|
|
1506
|
+
return;
|
|
1507
|
+
rpc.broadcast.callHook.asEvent("storage:key:update", key, event);
|
|
1508
|
+
});
|
|
1509
|
+
});
|
|
1510
|
+
const mounts = {
|
|
1511
|
+
...nitro.options.storage,
|
|
1512
|
+
...nitro.options.devStorage
|
|
1513
|
+
};
|
|
1514
|
+
for (const name of Object.keys(mounts)) {
|
|
1515
|
+
if (shouldIgnoreStorageKey(name))
|
|
1516
|
+
continue;
|
|
1517
|
+
storageMounts[name] = mounts[name];
|
|
1518
|
+
}
|
|
1519
|
+
});
|
|
1520
|
+
return {
|
|
1521
|
+
async getStorageMounts() {
|
|
1522
|
+
return storageMounts;
|
|
1523
|
+
},
|
|
1524
|
+
async getStorageKeys(base) {
|
|
1525
|
+
if (!storage)
|
|
1526
|
+
return [];
|
|
1527
|
+
try {
|
|
1528
|
+
const keys = await storage.getKeys(base);
|
|
1529
|
+
return keys.filter((key) => !shouldIgnoreStorageKey(key));
|
|
1530
|
+
} catch (err) {
|
|
1531
|
+
console.error(`Cloud not fetch storage keys for ${base}:`, err);
|
|
1532
|
+
return [];
|
|
1533
|
+
}
|
|
1534
|
+
},
|
|
1535
|
+
async getStorageItem(token, key) {
|
|
1536
|
+
await ensureDevAuthToken(token);
|
|
1537
|
+
if (!storage)
|
|
1538
|
+
return null;
|
|
1539
|
+
return await storage.getItem(key);
|
|
1540
|
+
},
|
|
1541
|
+
async setStorageItem(token, key, value) {
|
|
1542
|
+
await ensureDevAuthToken(token);
|
|
1543
|
+
if (!storage)
|
|
1544
|
+
return;
|
|
1545
|
+
return await storage.setItem(key, value);
|
|
1546
|
+
},
|
|
1547
|
+
async removeStorageItem(token, key) {
|
|
1548
|
+
await ensureDevAuthToken(token);
|
|
1549
|
+
if (!storage)
|
|
1550
|
+
return;
|
|
1551
|
+
return await storage.removeItem(key);
|
|
1552
|
+
}
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
const SEND_DELAY = 5e3;
|
|
1557
|
+
function throttle(fn, delay) {
|
|
1558
|
+
let timer;
|
|
1559
|
+
return () => {
|
|
1560
|
+
if (!timer) {
|
|
1561
|
+
timer = setTimeout(() => {
|
|
1562
|
+
timer = void 0;
|
|
1563
|
+
fn();
|
|
1564
|
+
}, delay);
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
let telemetry;
|
|
1569
|
+
const throttledSend = throttle(() => {
|
|
1570
|
+
telemetry?.sendEvents();
|
|
1571
|
+
}, SEND_DELAY);
|
|
1572
|
+
function setupTelemetryRPC({ nuxt, options }) {
|
|
1573
|
+
if (options.telemetry !== false) {
|
|
1574
|
+
nuxt.hook("telemetry:setup", (t) => {
|
|
1575
|
+
telemetry = t;
|
|
1576
|
+
t.eventFactories.devtools = (_, payload) => {
|
|
1577
|
+
return {
|
|
1578
|
+
name: "devtools",
|
|
1579
|
+
version,
|
|
1580
|
+
...payload
|
|
1581
|
+
};
|
|
1582
|
+
};
|
|
1583
|
+
t.createEvent("devtools", { event: "enabled" });
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
return {
|
|
1587
|
+
telemetryEvent(payload, immediate = false) {
|
|
1588
|
+
telemetryEvent(payload, immediate);
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
function telemetryEvent(payload, immediate = false) {
|
|
1593
|
+
if (!telemetry)
|
|
1594
|
+
return;
|
|
1595
|
+
if (getOptions()?.behavior.telemetry === false)
|
|
1596
|
+
return;
|
|
1597
|
+
telemetry.createEvent("devtools", payload);
|
|
1598
|
+
if (immediate)
|
|
1599
|
+
telemetry.sendEvents();
|
|
1600
|
+
else
|
|
1601
|
+
throttledSend();
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
function setupTerminalRPC({ nuxt, rpc, refresh, ensureDevAuthToken }) {
|
|
1605
|
+
const terminals = /* @__PURE__ */ new Map();
|
|
1606
|
+
nuxt.hook("devtools:terminal:register", (terminal) => {
|
|
1607
|
+
terminals.set(terminal.id, terminal);
|
|
1608
|
+
refresh("getTerminals");
|
|
1609
|
+
return terminal.id;
|
|
1610
|
+
});
|
|
1611
|
+
nuxt.hook("devtools:terminal:remove", ({ id }) => {
|
|
1612
|
+
if (!terminals.has(id))
|
|
1613
|
+
return false;
|
|
1614
|
+
terminals.delete(id);
|
|
1615
|
+
refresh("getTerminals");
|
|
1616
|
+
return true;
|
|
1617
|
+
});
|
|
1618
|
+
nuxt.hook("devtools:terminal:write", ({ id, data }) => {
|
|
1619
|
+
const terminal = terminals.get(id);
|
|
1620
|
+
if (!terminal)
|
|
1621
|
+
return false;
|
|
1622
|
+
terminal.buffer ||= "";
|
|
1623
|
+
terminal.buffer += data;
|
|
1624
|
+
rpc.broadcast.onTerminalData.asEvent({ id, data });
|
|
1625
|
+
return true;
|
|
1626
|
+
});
|
|
1627
|
+
nuxt.hook("devtools:terminal:exit", ({ id, code }) => {
|
|
1628
|
+
const terminal = terminals.get(id);
|
|
1629
|
+
if (!terminal)
|
|
1630
|
+
return false;
|
|
1631
|
+
terminal.isTerminated = true;
|
|
1632
|
+
rpc.broadcast.onTerminalExit.asEvent({ id, code });
|
|
1633
|
+
refresh("getTerminals");
|
|
1634
|
+
return true;
|
|
1635
|
+
});
|
|
1636
|
+
function serializeTerminal(terminal, buffer = false) {
|
|
1637
|
+
if (!terminal)
|
|
1638
|
+
return;
|
|
1639
|
+
return {
|
|
1640
|
+
id: terminal.id,
|
|
1641
|
+
name: terminal.name,
|
|
1642
|
+
description: terminal.description,
|
|
1643
|
+
icon: terminal.icon,
|
|
1644
|
+
terminatable: terminal.terminatable ?? !!terminal.onActionTerminate,
|
|
1645
|
+
restartable: terminal.restartable ?? !!terminal.onActionRestart,
|
|
1646
|
+
isTerminated: terminal.isTerminated,
|
|
1647
|
+
buffer: buffer ? terminal.buffer : void 0
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
return {
|
|
1651
|
+
getTerminals() {
|
|
1652
|
+
return Array.from(terminals.values()).map((i) => serializeTerminal(i));
|
|
1653
|
+
},
|
|
1654
|
+
async getTerminalDetail(token, id) {
|
|
1655
|
+
await ensureDevAuthToken(token);
|
|
1656
|
+
return serializeTerminal(terminals.get(id), true);
|
|
1657
|
+
},
|
|
1658
|
+
async runTerminalAction(token, id, action) {
|
|
1659
|
+
await ensureDevAuthToken(token);
|
|
1660
|
+
const terminal = terminals.get(id);
|
|
1661
|
+
if (!terminal)
|
|
1662
|
+
return false;
|
|
1663
|
+
switch (action) {
|
|
1664
|
+
case "restart":
|
|
1665
|
+
if (!terminal.onActionRestart)
|
|
1666
|
+
return false;
|
|
1667
|
+
await terminal.onActionRestart();
|
|
1668
|
+
return true;
|
|
1669
|
+
case "terminate":
|
|
1670
|
+
if (!terminal.onActionTerminate)
|
|
1671
|
+
return false;
|
|
1672
|
+
await terminal.onActionTerminate();
|
|
1673
|
+
return true;
|
|
1674
|
+
case "remove":
|
|
1675
|
+
if (!terminal.isTerminated)
|
|
1676
|
+
terminal.onActionTerminate?.();
|
|
1677
|
+
terminals.delete(id);
|
|
1678
|
+
refresh("getTerminals");
|
|
1679
|
+
return true;
|
|
1680
|
+
case "clear":
|
|
1681
|
+
terminal.buffer = "";
|
|
1682
|
+
refresh("getTerminals");
|
|
1683
|
+
return true;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
function setupTimelineRPC({ nuxt }) {
|
|
1690
|
+
return {
|
|
1691
|
+
async enableTimeline(dry) {
|
|
1692
|
+
const filepath = nuxt.options._nuxtConfigFile;
|
|
1693
|
+
const source = await fs.readFile(filepath, "utf-8");
|
|
1694
|
+
const generated = await magicastGuard(async () => {
|
|
1695
|
+
const mod = parseModule(source, { sourceFileName: filepath });
|
|
1696
|
+
const options = getDefaultExportOptions(mod);
|
|
1697
|
+
options.devtools = options.devtools || {};
|
|
1698
|
+
options.devtools.timeline = options.devtools.timeline || {};
|
|
1699
|
+
options.devtools.timeline.enabled = true;
|
|
1700
|
+
return mod.generate().code;
|
|
1701
|
+
}, "\nYou can enable timeline manually by adding `devtools: { timeline: { enabled: true } }`");
|
|
1702
|
+
if (!dry) {
|
|
1703
|
+
await fs.writeFile(filepath, generated, "utf-8");
|
|
1704
|
+
await nuxt.callHook("restart", { hard: true });
|
|
1705
|
+
}
|
|
1706
|
+
return [source, generated];
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
const LOG_PREFIX = colors.cyan("Nuxt DevTools:");
|
|
1712
|
+
|
|
1713
|
+
const pagesIndexTemplate = `<script setup lang="ts">
|
|
1714
|
+
const route = useRoute()
|
|
1715
|
+
<\/script>
|
|
1716
|
+
|
|
1717
|
+
<template>
|
|
1718
|
+
<div>
|
|
1719
|
+
<h1>Nuxt Routing set up successfully!</h1>
|
|
1720
|
+
<p>Current route: {{ route.path }}</p>
|
|
1721
|
+
<a href="https://nuxt.com/docs/getting-started/routing" target="_blank">Learn more about Nuxt Routing</a>
|
|
1722
|
+
</div>
|
|
1723
|
+
</template>
|
|
1724
|
+
`;
|
|
1725
|
+
async function enablePages(nuxt) {
|
|
1726
|
+
const baseDir = nuxt.options.future.compatibilityVersion === 4 ? nuxt.options.dir.app : nuxt.options.srcDir;
|
|
1727
|
+
const pathApp = join(baseDir, "app.vue");
|
|
1728
|
+
const pathPageIndex = join(baseDir, "pages/index.vue");
|
|
1729
|
+
if (fs$1.existsSync(pathPageIndex)) {
|
|
1730
|
+
logger.warn("pages/index.vue already exists, skipping");
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1733
|
+
let appContent = fs$1.existsSync(pathApp) ? await fs.readFile(pathApp, "utf-8") : void 0;
|
|
1734
|
+
await fs.mkdir(dirname$1(pathPageIndex), { recursive: true });
|
|
1735
|
+
await fs.writeFile(pathPageIndex, pagesIndexTemplate, "utf-8");
|
|
1736
|
+
if (appContent && !appContent.includes("<NuxtPage")) {
|
|
1737
|
+
appContent = appContent.replace("</template>", " <NuxtPage />\n</template>").replace(/<NuxtWelcome\s*\/>/, "");
|
|
1738
|
+
await fs.writeFile(pathApp, appContent, "utf-8");
|
|
1739
|
+
}
|
|
1740
|
+
logger.success("Routing creation wizard completed");
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
const wizard = {
|
|
1744
|
+
enablePages
|
|
1745
|
+
};
|
|
1746
|
+
|
|
1747
|
+
function setupWizardRPC({ nuxt, ensureDevAuthToken }) {
|
|
1748
|
+
return {
|
|
1749
|
+
async runWizard(token, name, ...args) {
|
|
1750
|
+
await ensureDevAuthToken(token);
|
|
1751
|
+
logger.info(LOG_PREFIX, `Running wizard ${colors.green(name)}...`);
|
|
1752
|
+
return wizard[name](nuxt, ...args);
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
function setupRPC(nuxt, options) {
|
|
1758
|
+
const serverFunctions = {};
|
|
1759
|
+
const extendedRpcMap = /* @__PURE__ */ new Map();
|
|
1760
|
+
const rpc = createBirpcGroup(
|
|
1761
|
+
serverFunctions,
|
|
1762
|
+
[],
|
|
1763
|
+
{
|
|
1764
|
+
resolver: (name, fn) => {
|
|
1765
|
+
if (fn)
|
|
1766
|
+
return fn;
|
|
1767
|
+
if (!name.includes(":"))
|
|
1768
|
+
return;
|
|
1769
|
+
const [namespace, fnName] = name.split(":");
|
|
1770
|
+
return extendedRpcMap.get(namespace)?.[fnName];
|
|
1771
|
+
},
|
|
1772
|
+
onError(error, name) {
|
|
1773
|
+
logger.error(
|
|
1774
|
+
colors.yellow(`[nuxt-devtools] RPC error on executing "${colors.bold(name)}":
|
|
1775
|
+
`) + colors.red(error?.message || "")
|
|
1776
|
+
);
|
|
1777
|
+
},
|
|
1778
|
+
timeout: 12e4
|
|
1779
|
+
}
|
|
1780
|
+
);
|
|
1781
|
+
function refresh(event) {
|
|
1782
|
+
rpc.broadcast.refresh.asEvent(event);
|
|
1783
|
+
}
|
|
1784
|
+
function extendServerRpc(namespace, functions) {
|
|
1785
|
+
extendedRpcMap.set(namespace, functions);
|
|
1786
|
+
return {
|
|
1787
|
+
broadcast: new Proxy({}, {
|
|
1788
|
+
get: (_, key) => {
|
|
1789
|
+
if (typeof key !== "string")
|
|
1790
|
+
return;
|
|
1791
|
+
return rpc.broadcast[`${namespace}:${key}`];
|
|
1792
|
+
}
|
|
1793
|
+
})
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
const ctx = {
|
|
1797
|
+
nuxt,
|
|
1798
|
+
options,
|
|
1799
|
+
rpc,
|
|
1800
|
+
refresh,
|
|
1801
|
+
extendServerRpc,
|
|
1802
|
+
openInEditorHooks: [],
|
|
1803
|
+
async ensureDevAuthToken(token) {
|
|
1804
|
+
if (options.disableAuthorization)
|
|
1805
|
+
return;
|
|
1806
|
+
if (token !== await getDevAuthToken())
|
|
1807
|
+
throw new Error("Invalid dev auth token.");
|
|
1808
|
+
}
|
|
1809
|
+
};
|
|
1810
|
+
nuxt.devtools = ctx;
|
|
1811
|
+
Object.assign(serverFunctions, {
|
|
1812
|
+
...setupGeneralRPC(ctx),
|
|
1813
|
+
...setupCustomTabRPC(ctx),
|
|
1814
|
+
...setupStorageRPC(ctx),
|
|
1815
|
+
...setupAssetsRPC(ctx),
|
|
1816
|
+
...setupNpmRPC(ctx),
|
|
1817
|
+
...setupWizardRPC(ctx),
|
|
1818
|
+
...setupTerminalRPC(ctx),
|
|
1819
|
+
...setupServerRoutesRPC(ctx),
|
|
1820
|
+
...setupServerTasksRPC(ctx),
|
|
1821
|
+
...setupAnalyzeBuildRPC(ctx),
|
|
1822
|
+
...setupOptionsRPC(ctx),
|
|
1823
|
+
...setupTimelineRPC(ctx),
|
|
1824
|
+
...setupTelemetryRPC(ctx)
|
|
1825
|
+
});
|
|
1826
|
+
const wsClients = /* @__PURE__ */ new Set();
|
|
1827
|
+
const vitePlugin = {
|
|
1828
|
+
name: "nuxt:devtools:rpc",
|
|
1829
|
+
configureServer(server) {
|
|
1830
|
+
server.ws.on("connection", (ws) => {
|
|
1831
|
+
wsClients.add(ws);
|
|
1832
|
+
const channel = {
|
|
1833
|
+
post: (d) => ws.send(JSON.stringify({
|
|
1834
|
+
type: "custom",
|
|
1835
|
+
event: WS_EVENT_NAME,
|
|
1836
|
+
data: d
|
|
1837
|
+
})),
|
|
1838
|
+
on: (fn) => {
|
|
1839
|
+
ws.on("message", (e) => {
|
|
1840
|
+
try {
|
|
1841
|
+
const data = JSON.parse(String(e)) || {};
|
|
1842
|
+
if (data.type === "custom" && data.event === WS_EVENT_NAME) {
|
|
1843
|
+
fn(data.data);
|
|
1844
|
+
}
|
|
1845
|
+
} catch {
|
|
1846
|
+
}
|
|
1847
|
+
});
|
|
1848
|
+
},
|
|
1849
|
+
serialize: stringify,
|
|
1850
|
+
deserialize: parse$1
|
|
1851
|
+
};
|
|
1852
|
+
rpc.updateChannels((c) => {
|
|
1853
|
+
c.push(channel);
|
|
1854
|
+
});
|
|
1855
|
+
ws.on("close", () => {
|
|
1856
|
+
wsClients.delete(ws);
|
|
1857
|
+
rpc.updateChannels((c) => {
|
|
1858
|
+
const index = c.indexOf(channel);
|
|
1859
|
+
if (index >= 0)
|
|
1860
|
+
c.splice(index, 1);
|
|
1861
|
+
});
|
|
1862
|
+
});
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
return {
|
|
1867
|
+
vitePlugin,
|
|
1868
|
+
...ctx
|
|
1869
|
+
};
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
async function enableModule(options, nuxt) {
|
|
1873
|
+
if (process.env.TEST || process.env.NODE_ENV === "test" || nuxt.options.test)
|
|
1874
|
+
return;
|
|
1875
|
+
if (nuxt.options.builder !== "@nuxt/vite-builder") {
|
|
1876
|
+
logger.warn("Nuxt DevTools only supports Vite mode, module is disabled.");
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
if (!nuxt.options.dev) {
|
|
1880
|
+
if (nuxt.options.build.analyze && (nuxt.options.build.analyze === true || nuxt.options.build.analyze.enabled))
|
|
1881
|
+
await import('./analyze-build.mjs').then(({ setup }) => setup(nuxt, options));
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
const enabledExplicitly = nuxt.options.devtools === true || nuxt.options.devtools && nuxt.options.devtools.enabled || !!nuxt.options.modules.find((m) => m === "@nuxt/devtools" || m === "@nuxt/devtools-edge" || m === "@nuxt/devtools-nightly");
|
|
1885
|
+
await nuxt.callHook("devtools:before");
|
|
1886
|
+
if (options.iframeProps) {
|
|
1887
|
+
nuxt.options.runtimeConfig.app.devtools ||= {};
|
|
1888
|
+
nuxt.options.runtimeConfig.app.devtools.iframeProps = options.iframeProps;
|
|
1889
|
+
}
|
|
1890
|
+
nuxt.options.imports.collectMeta = true;
|
|
1891
|
+
addPlugin({
|
|
1892
|
+
src: join(runtimeDir, "plugins/devtools.client"),
|
|
1893
|
+
mode: "client"
|
|
1894
|
+
});
|
|
1895
|
+
addPlugin({
|
|
1896
|
+
src: join(runtimeDir, "plugins/devtools.server"),
|
|
1897
|
+
mode: "server"
|
|
1898
|
+
});
|
|
1899
|
+
addTemplate({
|
|
1900
|
+
filename: "devtools/settings.mjs",
|
|
1901
|
+
async getContents() {
|
|
1902
|
+
const uiOptions = await readLocalOptions(
|
|
1903
|
+
{
|
|
1904
|
+
...defaultTabOptions.ui,
|
|
1905
|
+
// When not enabled explicitly, we hide the panel by default
|
|
1906
|
+
showPanel: enabledExplicitly ? true : null
|
|
1907
|
+
},
|
|
1908
|
+
{ root: nuxt.options.rootDir }
|
|
1909
|
+
);
|
|
1910
|
+
return `export default ${JSON.stringify({
|
|
1911
|
+
ui: uiOptions
|
|
1912
|
+
})}`;
|
|
1913
|
+
}
|
|
1914
|
+
});
|
|
1915
|
+
nuxt.hook("nitro:config", (config) => {
|
|
1916
|
+
if (config.experimental?.tasks)
|
|
1917
|
+
defaultTabOptions.serverTasks.enabled = true;
|
|
1918
|
+
config.externals = config.externals || {};
|
|
1919
|
+
config.externals.inline = config.externals.inline || [];
|
|
1920
|
+
config.externals.inline.push(join(runtimeDir, "nitro"));
|
|
1921
|
+
config.virtual = config.virtual || {};
|
|
1922
|
+
config.virtual["#nuxt-devtools-inline"] = `export const script = \`
|
|
1923
|
+
if (!window.__NUXT_DEVTOOLS_TIME_METRIC__) {
|
|
1924
|
+
Object.defineProperty(window, '__NUXT_DEVTOOLS_TIME_METRIC__', {
|
|
1925
|
+
value: {},
|
|
1926
|
+
enumerable: false,
|
|
1927
|
+
configurable: true,
|
|
1928
|
+
})
|
|
1929
|
+
}
|
|
1930
|
+
window.__NUXT_DEVTOOLS_TIME_METRIC__.appInit = Date.now()
|
|
1931
|
+
\``;
|
|
1932
|
+
config.plugins = config.plugins || [];
|
|
1933
|
+
config.plugins.unshift(join(runtimeDir, "nitro/inline"));
|
|
1934
|
+
});
|
|
1935
|
+
const {
|
|
1936
|
+
vitePlugin,
|
|
1937
|
+
...ctx
|
|
1938
|
+
} = setupRPC(nuxt, options);
|
|
1939
|
+
addVitePlugin(vitePlugin);
|
|
1940
|
+
const clientDirExists = existsSync(clientDir);
|
|
1941
|
+
const analyzeDir = join(nuxt.options.rootDir, ".nuxt/analyze");
|
|
1942
|
+
nuxt.hook("vite:extendConfig", (config) => {
|
|
1943
|
+
config.server ||= {};
|
|
1944
|
+
config.server.fs ||= {};
|
|
1945
|
+
config.server.fs.allow ||= [
|
|
1946
|
+
searchForWorkspaceRoot(process.cwd())
|
|
1947
|
+
];
|
|
1948
|
+
config.server.fs.allow.push(packageDir);
|
|
1949
|
+
config.server.watch ||= {};
|
|
1950
|
+
config.server.watch.ignored ||= [];
|
|
1951
|
+
if (!Array.isArray(config.server.watch.ignored))
|
|
1952
|
+
config.server.watch.ignored = [config.server.watch.ignored];
|
|
1953
|
+
config.server.watch.ignored.push("**/.nuxt/analyze/**");
|
|
1954
|
+
});
|
|
1955
|
+
nuxt.hook("imports:extend", (imports) => {
|
|
1956
|
+
imports.push({
|
|
1957
|
+
name: "useNuxtDevTools",
|
|
1958
|
+
from: join(runtimeDir, "use-nuxt-devtools")
|
|
1959
|
+
});
|
|
1960
|
+
});
|
|
1961
|
+
const ROUTE_PATH = `${nuxt.options.app.baseURL || "/"}/__nuxt_devtools__`.replace(/\/+/g, "/");
|
|
1962
|
+
const ROUTE_CLIENT = `${ROUTE_PATH}/client`;
|
|
1963
|
+
const ROUTE_AUTH = `${ROUTE_PATH}/auth`;
|
|
1964
|
+
const ROUTE_AUTH_VERIFY = `${ROUTE_PATH}/auth-verify`;
|
|
1965
|
+
const ROUTE_ANALYZE = `${ROUTE_PATH}/analyze`;
|
|
1966
|
+
nuxt.hook("vite:serverCreated", (server) => {
|
|
1967
|
+
server.middlewares.use(ROUTE_ANALYZE, sirv(analyzeDir, { single: false, dev: true }));
|
|
1968
|
+
if (clientDirExists) {
|
|
1969
|
+
const indexHtmlPath = join(clientDir, "index.html");
|
|
1970
|
+
const indexContent = fs.readFile(indexHtmlPath, "utf-8");
|
|
1971
|
+
const handleStatic = sirv(clientDir, {
|
|
1972
|
+
dev: true,
|
|
1973
|
+
single: false
|
|
1974
|
+
});
|
|
1975
|
+
const handleIndex = async (res) => {
|
|
1976
|
+
res.setHeader("Content-Type", "text/html");
|
|
1977
|
+
res.statusCode = 200;
|
|
1978
|
+
res.write((await indexContent).replace(/\/__NUXT_DEVTOOLS_BASE__\//g, `${ROUTE_CLIENT}/`));
|
|
1979
|
+
res.end();
|
|
1980
|
+
};
|
|
1981
|
+
server.middlewares.use(ROUTE_CLIENT, (req, res) => {
|
|
1982
|
+
if (req.url === "/")
|
|
1983
|
+
return handleIndex(res);
|
|
1984
|
+
return handleStatic(req, res, () => handleIndex(res));
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
server.middlewares.use(ROUTE_AUTH, sirv(join(runtimeDir, "auth"), { single: true, dev: true }));
|
|
1988
|
+
server.middlewares.use(ROUTE_AUTH_VERIFY, async (req, res) => {
|
|
1989
|
+
const search = req.url?.split("?")[1];
|
|
1990
|
+
if (!search) {
|
|
1991
|
+
res.statusCode = 400;
|
|
1992
|
+
res.end("No token provided");
|
|
1993
|
+
}
|
|
1994
|
+
const query = new URLSearchParams(search);
|
|
1995
|
+
const token = query.get("token");
|
|
1996
|
+
if (!token) {
|
|
1997
|
+
res.statusCode = 400;
|
|
1998
|
+
res.end("No token provided");
|
|
1999
|
+
}
|
|
2000
|
+
if (token === await getDevAuthToken()) {
|
|
2001
|
+
res.statusCode = 200;
|
|
2002
|
+
res.end("Valid token");
|
|
2003
|
+
} else {
|
|
2004
|
+
res.statusCode = 403;
|
|
2005
|
+
res.end("Invalid token");
|
|
2006
|
+
}
|
|
2007
|
+
});
|
|
2008
|
+
});
|
|
2009
|
+
await import('./plugin-metrics.mjs').then(({ setup }) => setup(ctx));
|
|
2010
|
+
await import('./vue-devtools.mjs').then(({ setup }) => setup(ctx));
|
|
2011
|
+
if (options.viteInspect !== false)
|
|
2012
|
+
await import('./vite-inspect.mjs').then(({ setup }) => setup(ctx));
|
|
2013
|
+
if (options.componentInspector !== false)
|
|
2014
|
+
await import('./vue-inspector.mjs').then(({ setup }) => setup(ctx));
|
|
2015
|
+
const integrations = [
|
|
2016
|
+
options.vscode?.enabled ? import('./vscode.mjs').then(({ setup }) => setup(ctx)) : null,
|
|
2017
|
+
options.experimental?.timeline || options.timeline?.enabled ? import('./timeline.mjs').then(({ setup }) => setup(ctx)) : null
|
|
2018
|
+
];
|
|
2019
|
+
await Promise.all(integrations);
|
|
2020
|
+
await nuxt.callHook("devtools:initialized", {
|
|
2021
|
+
version,
|
|
2022
|
+
packagePath: packageDir,
|
|
2023
|
+
isGlobalInstall: isGlobalInstall()
|
|
2024
|
+
});
|
|
2025
|
+
const isMac = os.platform() === "darwin";
|
|
2026
|
+
logger.log([
|
|
2027
|
+
colors.yellow(` \u279C DevTools: `),
|
|
2028
|
+
colors.dim("press "),
|
|
2029
|
+
colors.green("Shift"),
|
|
2030
|
+
colors.dim(" + "),
|
|
2031
|
+
colors.green(isMac ? "Option" : "Alt"),
|
|
2032
|
+
colors.dim(" + "),
|
|
2033
|
+
colors.green("D"),
|
|
2034
|
+
colors.dim(` in the browser (v${version})`),
|
|
2035
|
+
"\n"
|
|
2036
|
+
].join(""));
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
const moduleMain = {
|
|
2040
|
+
__proto__: null,
|
|
2041
|
+
enableModule: enableModule
|
|
2042
|
+
};
|
|
2043
|
+
|
|
2044
|
+
export { LOG_PREFIX as L, moduleMain as m };
|