@vesk/adapter 0.2.9 → 0.2.11

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.
Files changed (42) hide show
  1. package/dist/client-bundle.d.ts +29 -0
  2. package/dist/client-bundle.d.ts.map +1 -1
  3. package/dist/client-bundle.js +333 -52
  4. package/dist/dev-api.d.ts +78 -0
  5. package/dist/dev-api.d.ts.map +1 -0
  6. package/dist/dev-api.js +338 -0
  7. package/dist/dev-config.d.ts +48 -0
  8. package/dist/dev-config.d.ts.map +1 -0
  9. package/dist/dev-config.js +964 -0
  10. package/dist/dev-server.d.ts +85 -0
  11. package/dist/dev-server.d.ts.map +1 -1
  12. package/dist/dev-server.js +329 -8
  13. package/dist/error-codeframe.d.ts +23 -0
  14. package/dist/error-codeframe.d.ts.map +1 -0
  15. package/dist/error-codeframe.js +127 -0
  16. package/dist/error-tips.d.ts +7 -0
  17. package/dist/error-tips.d.ts.map +1 -0
  18. package/dist/error-tips.js +91 -0
  19. package/dist/hmr-utils.d.ts +14 -0
  20. package/dist/hmr-utils.d.ts.map +1 -0
  21. package/dist/hmr-utils.js +56 -0
  22. package/dist/hmr.d.ts +40 -0
  23. package/dist/hmr.d.ts.map +1 -1
  24. package/dist/hmr.js +139 -20
  25. package/dist/index.d.ts +37 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +105 -22
  28. package/dist/paths.d.ts +8 -0
  29. package/dist/paths.d.ts.map +1 -1
  30. package/dist/paths.js +32 -0
  31. package/dist/platform-handler.d.ts.map +1 -1
  32. package/dist/platform-handler.js +2 -1
  33. package/dist/plugins.d.ts +147 -0
  34. package/dist/plugins.d.ts.map +1 -0
  35. package/dist/plugins.js +1109 -0
  36. package/dist/prod-server.d.ts.map +1 -1
  37. package/dist/prod-server.js +43 -9
  38. package/dist/ssr-function.d.ts.map +1 -1
  39. package/dist/ssr-function.js +14 -2
  40. package/dist/types.d.ts +1 -1
  41. package/dist/types.d.ts.map +1 -1
  42. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'node:fs';
2
- import { resolve, dirname, relative } from 'node:path';
2
+ import { resolve, dirname, relative, basename } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { cssBlockEnd } from '@vesk/compiler/src/scan';
5
5
  import { bundleRuntime } from '@vesk/adapter/src/runtime-bundle';
@@ -22,6 +22,45 @@ async function resolveCompilerApi(name) {
22
22
  }
23
23
  return import(`@vesk/compiler/src/${name.replace(/\.js$/, '')}`);
24
24
  }
25
+ /**
26
+ * Defensive local mirror of the plugin-manager's `filterActivePlugins`
27
+ * (`@vesk/adapter/src/plugins`): keep when there is no matching record, or the
28
+ * record's `active` is true; drop when a name-matched record is explicitly
29
+ * inactive. Names match CASE-INSENSITIVELY to stay aligned with the manager —
30
+ * it reads/writes state via `eqIgnoreCase`. Only used as the fallback when the
31
+ * plugin-manager module is unavailable during a build; the live build gate in
32
+ * `build()` calls the module's own filter.
33
+ */
34
+ export function filterActivePlugins(plugins, records) {
35
+ if (!records || records.length === 0)
36
+ return plugins;
37
+ return plugins.filter(p => {
38
+ const record = records.find(r => String(r.name || '').toLowerCase() === String(p.name || '').toLowerCase());
39
+ return record ? record.active : true;
40
+ });
41
+ }
42
+ /**
43
+ * Build-time enforcement gate (fallback): an INACTIVE plugin must NEVER ship —
44
+ * it must not have any hook invoked and must not appear in CSS / transformed
45
+ * JS / platform output. Returns the actives-only list. A null/absent state
46
+ * degrades to "all config plugins stay active" (defensive). The live gate in
47
+ * `build()` prefers `@vesk/adapter/src/plugins#filterActivePlugins`; this
48
+ * helper exists for the no-module fallback and for direct unit testing.
49
+ */
50
+ export function filterPluginsForBuild(plugins, state) {
51
+ if (!state || !Array.isArray(state.plugins))
52
+ return plugins;
53
+ return filterActivePlugins(plugins, state.plugins);
54
+ }
55
+ /** Resolve the `.vesk` dir that owns plugin activation state. `outDir` is
56
+ * `.vesk` itself (versioned builds) or `.vesk/{dev|build}`; in both cases the
57
+ * `.vesk` parent holds `plugins.json`. */
58
+ function veskDirFromOutDir(outDir) {
59
+ const base = basename(outDir);
60
+ if (base === 'dev' || base === 'build')
61
+ return dirname(outDir);
62
+ return outDir;
63
+ }
25
64
  export async function build(appDir, options) {
26
65
  appDir = resolve(appDir);
27
66
  const outDir = resolve(options?.outDir || resolve(appDir, '..', '.vesk'));
@@ -33,7 +72,41 @@ export async function build(appDir, options) {
33
72
  const { configureMd } = await import('@vesk/runtime/src/md');
34
73
  configureMd(options.md);
35
74
  }
75
+ // Build-time plugin activation gate. Read plugin activation from the
76
+ // plugin-manager module (`@vesk/adapter/src/plugins`): `getPluginRecords`
77
+ // returns full `PluginRecord[]` (name + active are the fields we consume);
78
+ // `readPluginState` is the `.vesk/plugins.json` fallback. An INACTIVE plugin
79
+ // must never ship — drop it from `pluginsPipelines`, which is the ONLY list
80
+ // every plugin hook / CSS pipeline iterates. If the module is missing
81
+ // (pre-rebuild) or throws, degrade to all-active.
82
+ const veskDir = veskDirFromOutDir(outDir);
83
+ let pluginsPipelines = plugins;
84
+ try {
85
+ const pluginApi = await import('@vesk/adapter/src/plugins');
86
+ let records = [];
87
+ if (typeof pluginApi.getPluginRecords === 'function') {
88
+ records = pluginApi.getPluginRecords(appDir, veskDir, plugins.map(p => p.name));
89
+ }
90
+ else if (typeof pluginApi.readPluginState === 'function') {
91
+ const st = pluginApi.readPluginState(veskDir);
92
+ records = (st && Array.isArray(st.plugins) ? st.plugins : []);
93
+ }
94
+ if (typeof pluginApi.filterActivePlugins === 'function') {
95
+ pluginsPipelines = pluginApi.filterActivePlugins(plugins, records);
96
+ }
97
+ else {
98
+ pluginsPipelines = filterPluginsForBuild(plugins, { version: 1, plugins: records });
99
+ }
100
+ }
101
+ catch {
102
+ pluginsPipelines = plugins;
103
+ }
36
104
  for (const plugin of plugins) {
105
+ if (!pluginsPipelines.includes(plugin)) {
106
+ console.error(`vesk build: skipping inactive plugin "${plugin.name}"`);
107
+ }
108
+ }
109
+ for (const plugin of pluginsPipelines) {
37
110
  if (typeof plugin.onBuildStart === 'function') {
38
111
  await plugin.onBuildStart();
39
112
  }
@@ -194,33 +267,40 @@ export async function build(appDir, options) {
194
267
  const userCssTarget = resolve(outDir, 'static', 'global.css');
195
268
  writeFileSync(userCssTarget, userCss, 'utf-8');
196
269
  console.error(`vesk build: css → static/global.css (${userCss.length} bytes)`);
197
- let twCss = cssContent;
198
- for (const plugin of plugins) {
199
- if (typeof plugin.onCSS === 'function') {
200
- const result = await plugin.onCSS(twCss, cssSourcePath);
201
- if (result !== null && typeof result === 'string') {
202
- twCss = result;
270
+ const twCssTarget = resolve(outDir, 'static', '_tailwind.css');
271
+ const isTailwindActive = pluginsPipelines.some((p) => String(p.name).toLowerCase().includes('tailwind'));
272
+ if (!isTailwindActive) {
273
+ writeFileSync(twCssTarget, '', 'utf-8');
274
+ console.error('vesk build: css → static/_tailwind.css (empty, tailwind plugin inactive)');
275
+ }
276
+ else {
277
+ let twCss = cssContent;
278
+ for (const plugin of pluginsPipelines) {
279
+ if (typeof plugin.onCSS === 'function') {
280
+ const result = await plugin.onCSS(twCss, cssSourcePath);
281
+ if (result !== null && typeof result === 'string') {
282
+ twCss = result;
283
+ }
203
284
  }
204
285
  }
205
- }
206
- const twCssTarget = resolve(outDir, 'static', '_tailwind.css');
207
- const hasUnresolvedTailwindImport = /@import\s+['"]tailwindcss['"]/.test(twCss);
208
- if (hasUnresolvedTailwindImport) {
209
- const lines = twCss.split('\n').filter(l => !/^\s*@import\s+['"]tailwindcss['"]/.test(l));
210
- twCss = lines.join('\n').trim();
211
- if (twCss.length === 0) {
212
- writeFileSync(twCssTarget, '', 'utf-8');
213
- console.error('vesk build: css → static/_tailwind.css (empty, tailwind unresolved)');
286
+ const hasUnresolvedTailwindImport = /@import\s+['"]tailwindcss['"]/.test(twCss);
287
+ if (hasUnresolvedTailwindImport) {
288
+ const lines = twCss.split('\n').filter(l => !/^\s*@import\s+['"]tailwindcss['"]/.test(l));
289
+ twCss = lines.join('\n').trim();
290
+ if (twCss.length === 0) {
291
+ writeFileSync(twCssTarget, '', 'utf-8');
292
+ console.error('vesk build: css → static/_tailwind.css (empty, tailwind unresolved)');
293
+ }
294
+ else {
295
+ writeFileSync(twCssTarget, twCss, 'utf-8');
296
+ console.error(`vesk build: css → static/_tailwind.css (${twCss.length} bytes, tailwind partially unresolved)`);
297
+ }
214
298
  }
215
299
  else {
216
300
  writeFileSync(twCssTarget, twCss, 'utf-8');
217
- console.error(`vesk build: css → static/_tailwind.css (${twCss.length} bytes, tailwind partially unresolved)`);
301
+ console.error(`vesk build: css → static/_tailwind.css (${twCss.length} bytes)`);
218
302
  }
219
303
  }
220
- else {
221
- writeFileSync(twCssTarget, twCss, 'utf-8');
222
- console.error(`vesk build: css → static/_tailwind.css (${twCss.length} bytes)`);
223
- }
224
304
  }
225
305
  let prerenderedRoutes = [];
226
306
  if (options?.ssg) {
@@ -286,7 +366,7 @@ export async function build(appDir, options) {
286
366
  }
287
367
  }
288
368
  }
289
- for (const plugin of plugins) {
369
+ for (const plugin of pluginsPipelines) {
290
370
  if (typeof plugin.onBuildEnd === 'function') {
291
371
  await plugin.onBuildEnd();
292
372
  }
@@ -295,3 +375,6 @@ export async function build(appDir, options) {
295
375
  return { routeTree, apiTree, ssrRoutes, apiRoutes, manifest };
296
376
  }
297
377
  export { startProdServer } from '@vesk/adapter/src/prod-server';
378
+ // DevTools unified API surface — the shared, exportable connector both the
379
+ // adapter and CLI dev servers route their `/__vesk/*` panel through.
380
+ export { createDevApiRouter, DEFAULT_CAPABILITIES, DEFAULT_COMMAND_ALLOWLIST, CapabilityTable, } from '@vesk/adapter/src/dev-api';
package/dist/paths.d.ts CHANGED
@@ -5,6 +5,14 @@
5
5
  * serving / prerender writes so traversal defenses cannot drift.
6
6
  */
7
7
  export declare function resolveWithin(baseDir: string, relPath: string): string | null;
8
+ /**
9
+ * Installs `globalThis.__vsk_md_read_file` — the server-side backing of <Md>
10
+ * runtime markdown-file loading. Reads ONLY `.md`/`.markdown` files strictly
11
+ * inside one of the given public dirs (never above them, never other file
12
+ * types) and returns null otherwise, so a client-supplied path can only ever
13
+ * surface a public markdown file, never arbitrary filesystem content.
14
+ */
15
+ export declare function installMdReadHook(publicDirs: string[]): void;
8
16
  /**
9
17
  * True when an incoming WebSocket upgrade may connect: same-origin when the
10
18
  * client sends an Origin header, always allowed for non-browser clients that
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM7E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAU5E"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM7E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAkB5D;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAU5E"}
package/dist/paths.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { resolve, sep } from 'node:path';
2
+ import { existsSync, statSync, readFileSync } from 'node:fs';
2
3
  /**
3
4
  * Resolves `relPath` against `baseDir` and returns the absolute path ONLY if
4
5
  * it stays strictly inside `baseDir` (never the directory itself, never a
@@ -13,6 +14,37 @@ export function resolveWithin(baseDir, relPath) {
13
14
  return null;
14
15
  return target;
15
16
  }
17
+ /**
18
+ * Installs `globalThis.__vsk_md_read_file` — the server-side backing of <Md>
19
+ * runtime markdown-file loading. Reads ONLY `.md`/`.markdown` files strictly
20
+ * inside one of the given public dirs (never above them, never other file
21
+ * types) and returns null otherwise, so a client-supplied path can only ever
22
+ * surface a public markdown file, never arbitrary filesystem content.
23
+ */
24
+ export function installMdReadHook(publicDirs) {
25
+ const dirs = publicDirs.map((d) => resolve(d));
26
+ globalThis.__vsk_md_read_file = (p) => {
27
+ for (const dir of dirs) {
28
+ try {
29
+ let rel = String(p);
30
+ while (rel.length > 0 && rel.charCodeAt(0) === 47)
31
+ rel = rel.slice(1); // strip leading '/'
32
+ const abs = resolveWithin(dir, rel);
33
+ if (!abs)
34
+ continue;
35
+ const lower = abs.toLowerCase();
36
+ if (!lower.endsWith('.md') && !lower.endsWith('.markdown'))
37
+ continue;
38
+ if (existsSync(abs) && statSync(abs).isFile())
39
+ return readFileSync(abs, 'utf8');
40
+ }
41
+ catch {
42
+ /* try the next public dir */
43
+ }
44
+ }
45
+ return null;
46
+ };
47
+ }
16
48
  /**
17
49
  * True when an incoming WebSocket upgrade may connect: same-origin when the
18
50
  * client sends an Origin header, always allowed for non-browser clients that
@@ -1 +1 @@
1
- {"version":3,"file":"platform-handler.d.ts","sourceRoot":"","sources":["../src/platform-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAQD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAgIjF;AAED,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFzF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;CACxB"}
1
+ {"version":3,"file":"platform-handler.d.ts","sourceRoot":"","sources":["../src/platform-handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMpD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAQD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAiIjF;AAED,MAAM,WAAW,qBAAqB;IACpC,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsFzF;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;CACxB"}
@@ -96,7 +96,7 @@ export async function handleRequest(request) {
96
96
  return new Response(null, { status: 308, headers: { Location: '/_vesk/static/public' + (pathname.endsWith('/') ? pathname + 'index.html' : pathname + '.html') } });
97
97
  }
98
98
 
99
- let mwCtx = { params: {}, url, locals: {}, cookies: {}, request, set() {}, get() { return undefined; } };
99
+ let mwCtx = { params: {}, url, locals: {}, cookies: {}, request, resolveUrl(u) { return new URL(u, request.url).href; }, set() {}, get() { return undefined; } };
100
100
  if (${hasMwLiteral}) {
101
101
  mwCtx = {
102
102
  request,
@@ -104,6 +104,7 @@ export async function handleRequest(request) {
104
104
  url,
105
105
  locals: {},
106
106
  cookies: typeof parseCookies !== 'undefined' ? parseCookies(request.headers.get('cookie') || '') : {},
107
+ resolveUrl(u) { return new URL(u, request.url).href; },
107
108
  set(key, value) { this.locals[key] = value; },
108
109
  get(key) { return this.locals[key]; },
109
110
  };
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Dev-side plugin ("module") manager for Vesk.
3
+ *
4
+ * The user-facing surface is a Nuxt-like flow: INSTALL/UNINSTALL packages and
5
+ * ACTIVATE/DEACTIVATE plugins. Active/installed state lives in a state file
6
+ * (`.vesk/<PLUGIN_STATE_FILENAME>`) that the build-enforcement agent consumes
7
+ * so that INACTIVE plugins never ship in a production build. The dev panel
8
+ * talks to dev-server HTTP endpoints which call into this module.
9
+ *
10
+ * No compiler/runtime imports: this module only touches node built-ins.
11
+ */
12
+ export interface PluginRecord {
13
+ name: string;
14
+ package: string;
15
+ path: string | null;
16
+ active: boolean;
17
+ installed: boolean;
18
+ version: string | null;
19
+ latest: string | null;
20
+ description: string | null;
21
+ author: string | null;
22
+ license: string | null;
23
+ homepage: string | null;
24
+ repository: string | null;
25
+ updatedAt: string | null;
26
+ keywords: string[];
27
+ iconUrl: string | null;
28
+ metaSource: 'vesk.meta.json' | 'package.json' | 'none';
29
+ source: 'config' | 'state';
30
+ error: string | null;
31
+ }
32
+ export interface PluginStateFile {
33
+ version: 1;
34
+ plugins: {
35
+ name: string;
36
+ package: string;
37
+ active: boolean;
38
+ }[];
39
+ }
40
+ export interface PluginSearchResult {
41
+ name: string;
42
+ version: string | null;
43
+ description: string | null;
44
+ author: string | null;
45
+ date: string | null;
46
+ keywords: string[];
47
+ links: Record<string, string> | null;
48
+ }
49
+ export interface PluginExportsInfo {
50
+ ok: boolean;
51
+ name: string;
52
+ entry: string | null;
53
+ packageJsonExports: Record<string, string> | null;
54
+ dtsPath: string | null;
55
+ dtsExports: string[];
56
+ }
57
+ export declare const PLUGIN_STATE_FILENAME = "plugins.json";
58
+ /**
59
+ * Read the plugin state file. Tolerates a missing file (returns defaults) and
60
+ * a corrupt file (mismatched version or invalid JSON → reseed to defaults).
61
+ */
62
+ export declare function readPluginState(veskDir: string): PluginStateFile;
63
+ /** Write the plugin state file. */
64
+ export declare function writePluginState(veskDir: string, state: PluginStateFile): void;
65
+ /**
66
+ * Merge config-declared plugins and state-only entries into a unified record
67
+ * list.
68
+ *
69
+ * Precedence: a state entry (matched by name OR package, case-insensitive)
70
+ * overrides a config plugin's activation. Config plugins default to ACTIVE
71
+ * unless a matching state entry deactivates them. Entries that exist only in
72
+ * the state file are reported as source 'state'. `active` is the resolved
73
+ * build participation — always AND-ed with `installed`.
74
+ */
75
+ export declare function getPluginRecords(appDir: string, veskDir: string, configPluginNames: string[]): PluginRecord[];
76
+ /** Toggle a plugin's active flag in the state file (matched by name). Returns the new state. */
77
+ export declare function setPluginActive(veskDir: string, name: string, active: boolean): PluginStateFile;
78
+ declare function runNpm(appDir: string, args: string[], timeoutMs?: number): Promise<{
79
+ code: number;
80
+ stdout: string;
81
+ stderr: string;
82
+ }>;
83
+ /**
84
+ * Install a package into the app and register it as an active plugin in the
85
+ * state file. The package spec is validated first; then it is verified to be
86
+ * a Vesk plugin (via its package.json, never by importing module code). A
87
+ * plausible-but-unflagged package is still registered but flagged with an
88
+ * `error` noting it may not be a Vesk plugin.
89
+ */
90
+ export declare function installPlugin(appDir: string, veskDir: string, pkg: string): Promise<PluginRecord>;
91
+ /** Uninstall a package from the app and drop all state entries whose package matches. */
92
+ export declare function uninstallPlugin(appDir: string, veskDir: string, pkg: string): Promise<void>;
93
+ /**
94
+ * Update (reinstall at latest) an installed plugin and refresh its state entry.
95
+ * Returns the fresh record. `npm install <pkg>@latest` runs through the
96
+ * `runNpm` seam; the state entry keeps its activation, and the record is
97
+ * re-resolved against the freshly installed package.
98
+ */
99
+ export declare function updatePlugin(appDir: string, veskDir: string, pkg: string): Promise<PluginRecord>;
100
+ /**
101
+ * Filter the config-declared plugin array down to the active set.
102
+ *
103
+ * Rule (source of truth = records): for each config plugin whose `name`
104
+ * matches an ACTIVE record → keep; matched INACTIVE record → drop (never
105
+ * ships); config plugin with no matching record → keep (defaults active).
106
+ */
107
+ export declare function filterActivePlugins(configPlugins: unknown[], records: PluginRecord[]): unknown[];
108
+ /** Resolve the icon a plugin declares in `vesk.meta.json` (or conventional
109
+ * `icon.png`/`icon.ico`) from its package dir. Returns the absolute file plus
110
+ * MIME, or null when nothing is declared/present. Never a default image. */
111
+ export declare function findPluginIcon(appDir: string, name: string): {
112
+ file: string;
113
+ mime: string;
114
+ } | null;
115
+ /**
116
+ * Parse top-level `export ...` declarations from a `.d.ts` source into the
117
+ * exported-name list (adapter text processing — no module execution). Wildcard
118
+ * re-exports contribute nothing; `export { a as b }` yields `b`.
119
+ */
120
+ export declare function parseDtsExports(source: string): string[];
121
+ /**
122
+ * Introspect an installed plugin's public surface WITHOUT importing/executing
123
+ * it: resolved entry (package.json main/module), flat package.json `exports`
124
+ * map, and the `.d.ts`-parsed export names.
125
+ */
126
+ export declare function introspectPlugin(appDir: string, name: string): PluginExportsInfo;
127
+ type FetchLike = (url: string, init?: {
128
+ signal?: AbortSignal;
129
+ }) => Promise<Response>;
130
+ /**
131
+ * Fill registry-backed fields (latest, updatedAt, and any still-empty
132
+ * author/repository/license/description) on the given records, best-effort and
133
+ * cached so repeated GETs never hang. Returns the same array (mutated).
134
+ */
135
+ export declare function enrichPluginRecords(records: PluginRecord[]): Promise<PluginRecord[]>;
136
+ /**
137
+ * Search the npm registry (proxied). Empty `q` surfaces a curated `@vesk/*`
138
+ * scope set (`scope:vesk`). Best-effort: an unreachable registry yields `[]`.
139
+ */
140
+ export declare function searchPlugins(q: string): Promise<PluginSearchResult[]>;
141
+ export declare const __internals: {
142
+ runNpm: typeof runNpm;
143
+ fetch: FetchLike;
144
+ clearRegistryCache: () => void;
145
+ };
146
+ export {};
147
+ //# sourceMappingURL=plugins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}