@addfox/rsbuild-plugin-extension-manifest 0.1.1-beta.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 addfox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # @addfox/rsbuild-plugin-extension-manifest
2
+
3
+ [中文](README-zh_CN.md) | English
4
+
5
+ ---
6
+
7
+ Rsbuild plugin: after build, writes manifest.json (per-browser) based on CLI `-b`/`--browser` (launch target). Injected by CLI pipeline.
8
+
9
+ - Uses `@addfox/core`'s `resolveManifestForTarget` to build the final manifest
10
+ - Handles content script output (JS/CSS) for `[addfox.content]` placeholder expansion
11
+ - Auto-detects shadow/iframe content UI usage to control CSS auto-fill in manifest
12
+ - Validates entry HTML rules (e.g. popup must have HTML, background cannot have HTML in MV3)
@@ -0,0 +1,15 @@
1
+ import type { RsbuildPluginAPI } from "@rsbuild/core";
2
+ import type { AddfoxResolvedConfig, EntryInfo, BrowserTarget } from "@addfox/core";
3
+ /**
4
+ * Writes manifest.json after build. Entry and HTML (html: false for background/content) are handled by plugin-extension-entry.
5
+ * Browser comes from CLI -l/--launch (config/constants), not from env.
6
+ *
7
+ * @param resolvedConfig - Resolved Addfox configuration
8
+ * @param entries - Discovered entries
9
+ * @param browser - Target browser (chromium or firefox)
10
+ * @param distPath - Output directory path (browser-specific, e.g., .addfox/extension/extension-chromium)
11
+ */
12
+ export declare function extensionPlugin(resolvedConfig: AddfoxResolvedConfig, entries: EntryInfo[], browser: BrowserTarget, distPath: string): {
13
+ name: string;
14
+ setup(api: RsbuildPluginAPI): void;
15
+ };
package/dist/index.js ADDED
@@ -0,0 +1,598 @@
1
+ import { resolve } from "path";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
+ import { writeFile } from "fs/promises";
4
+ import { getAddfoxVersion, resolveManifestForTarget } from "@addfox/core";
5
+ const CONTENT_CSS_GLOBAL_KEY = "__ADDFOX_CONTENT_CSS_FILES__";
6
+ const CONTENT_CSS_TEXTS_GLOBAL_KEY = "__ADDFOX_CONTENT_CSS_TEXTS__";
7
+ const REQUIRED_HTML_ENTRIES = new Set([
8
+ "popup",
9
+ "options",
10
+ "sidepanel",
11
+ "offscreen"
12
+ ]);
13
+ const CONTENT_CSS_PATTERN = /defineShadowContentUI|defineIframeContentUI/;
14
+ const CONTENT_WRAPPER_PATTERN = /wrapper\s*:\s*["'](?:shadow|iframe)["']/;
15
+ const CONTENT_JS_PATTERNS = [
16
+ (k)=>k.startsWith("content/") && k.endsWith(".js"),
17
+ (k)=>"content.js" === k
18
+ ];
19
+ const CONTENT_CSS_PATTERNS = [
20
+ (k)=>k.startsWith("content/") && k.endsWith(".css") || "content.css" === k,
21
+ (k)=>k.startsWith("static/css/content")
22
+ ];
23
+ function extensionPlugin(resolvedConfig, entries, browser, distPath) {
24
+ const { root, outputRoot, manifest } = resolvedConfig;
25
+ const metaDir = resolve(root, outputRoot);
26
+ return {
27
+ name: "rsbuild-plugin-extension-manifest",
28
+ setup (api) {
29
+ api.onBeforeCreateCompiler(async ({ bundlerConfigs })=>{
30
+ const config = bundlerConfigs[0];
31
+ if (!config) return;
32
+ config.plugins = config.plugins ?? [];
33
+ config.plugins.push(createManifestPlugin(distPath, metaDir, manifest, entries, browser));
34
+ });
35
+ }
36
+ };
37
+ }
38
+ function createManifestPlugin(distPath, metaDir, manifest, entries, browser) {
39
+ return {
40
+ name: "rsbuild-plugin-extension-manifest:post-build",
41
+ apply (compiler) {
42
+ compiler.hooks.afterEmit.tap("rsbuild-plugin-extension-manifest:post-build", (compilation)=>{
43
+ emitManifest(distPath, metaDir, manifest, entries, browser, compilation);
44
+ });
45
+ }
46
+ };
47
+ }
48
+ function emitManifest(distPath, metaDir, manifest, entries, browser, compilation) {
49
+ ensureDir(distPath);
50
+ const safeCompilation = compilation ?? {};
51
+ const contentScriptOutput = collectContentScriptOutput(safeCompilation, entries);
52
+ injectContentCssRuntimeMeta(distPath, contentScriptOutput);
53
+ const manifestObj = resolveManifestForTarget(manifest, entries, browser, console.warn, contentScriptOutput);
54
+ const finalManifest = applyContentCssManifestPolicy(manifestObj, manifest, browser, contentScriptOutput);
55
+ validateEntryHtmlRules(entries, finalManifest);
56
+ writeManifestJson(distPath, finalManifest);
57
+ const entrypointsMap = extractEntrypointsMap(safeCompilation, entries);
58
+ Promise.all([
59
+ writeMetaMarkdown(metaDir, finalManifest, entries, entrypointsMap),
60
+ writeLlmsTxt(metaDir, finalManifest, entries)
61
+ ]).catch(()=>{});
62
+ }
63
+ function ensureDir(dirPath) {
64
+ if (!existsSync(dirPath)) mkdirSync(dirPath, {
65
+ recursive: true
66
+ });
67
+ }
68
+ function writeManifestJson(distPath, manifest) {
69
+ const manifestPath = resolve(distPath, "manifest.json");
70
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
71
+ }
72
+ function collectContentScriptOutput(compilation, entries) {
73
+ const hasContent = entries.some((e)=>"content" === e.name);
74
+ if (!hasContent) return;
75
+ const autoFillCssInManifest = !shouldDisableManifestCssAutoFill(entries);
76
+ const fromEntrypoint = tryGetContentEntryFiles(compilation);
77
+ const byNames = collectContentScriptOutputByNames(compilation);
78
+ if (fromEntrypoint?.js.length) {
79
+ const css = fromEntrypoint.css.length ? fromEntrypoint.css : byNames?.css ?? [];
80
+ return {
81
+ js: fromEntrypoint.js,
82
+ css,
83
+ autoFillCssInManifest
84
+ };
85
+ }
86
+ if (!byNames) return;
87
+ return {
88
+ ...byNames,
89
+ autoFillCssInManifest
90
+ };
91
+ }
92
+ function tryGetContentEntryFiles(compilation) {
93
+ const entrypoints = compilation.entrypoints;
94
+ if (!entrypoints) return;
95
+ const contentEntry = getContentEntryFromEntrypoints(entrypoints);
96
+ if (!contentEntry || "function" != typeof contentEntry.getFiles) return;
97
+ const files = safeGetFiles(contentEntry);
98
+ if (!files?.length) return;
99
+ return categorizeFiles(files);
100
+ }
101
+ function getContentEntryFromEntrypoints(entrypoints) {
102
+ if (isMap(entrypoints)) return entrypoints.get("content");
103
+ if (isRecord(entrypoints)) return entrypoints["content"];
104
+ }
105
+ function isMap(value) {
106
+ return "function" == typeof value.get;
107
+ }
108
+ function isRecord(value) {
109
+ return "object" == typeof value && null !== value;
110
+ }
111
+ function safeGetFiles(entry) {
112
+ try {
113
+ const files = entry.getFiles?.();
114
+ return Array.isArray(files) && files.length ? files : void 0;
115
+ } catch {
116
+ return;
117
+ }
118
+ }
119
+ function categorizeFiles(files) {
120
+ const js = [];
121
+ const css = [];
122
+ for (const name of files){
123
+ if ("string" != typeof name) continue;
124
+ const normalized = normalizePath(name);
125
+ if (normalized.endsWith(".js")) js.push(normalized);
126
+ else if (normalized.endsWith(".css")) css.push(normalized);
127
+ }
128
+ return {
129
+ js: js.sort(),
130
+ css: css.sort()
131
+ };
132
+ }
133
+ function collectContentScriptOutputByNames(compilation) {
134
+ const keys = getAssetKeys(compilation);
135
+ if (!keys.length) return;
136
+ return {
137
+ js: filterAndSortKeys(keys, CONTENT_JS_PATTERNS),
138
+ css: filterAndSortKeys(keys, CONTENT_CSS_PATTERNS)
139
+ };
140
+ }
141
+ function getAssetKeys(compilation) {
142
+ if (compilation.assets) return Object.keys(compilation.assets);
143
+ return safeGetAssetKeys(compilation.getAssets);
144
+ }
145
+ function safeGetAssetKeys(getAssets) {
146
+ if ("function" != typeof getAssets) return [];
147
+ try {
148
+ const assets = getAssets();
149
+ if (!Array.isArray(assets)) return [];
150
+ return assets.map((a)=>a?.filename ?? a?.name).filter((s)=>"string" == typeof s);
151
+ } catch {
152
+ return [];
153
+ }
154
+ }
155
+ function filterAndSortKeys(keys, patterns) {
156
+ return keys.filter((k)=>{
157
+ const normalized = normalizePath(k);
158
+ if (!normalized.endsWith(".css") && !normalized.endsWith(".js")) return false;
159
+ return patterns.some((pattern)=>pattern(normalized));
160
+ }).map(normalizePath).sort();
161
+ }
162
+ function normalizePath(path) {
163
+ return path.replace(/\\/g, "/");
164
+ }
165
+ function shouldDisableManifestCssAutoFill(entries) {
166
+ const contentEntry = entries.find((e)=>"content" === e.name);
167
+ if (!contentEntry) return false;
168
+ return hasShadowOrIframeContentUIUsage(contentEntry.scriptPath);
169
+ }
170
+ function hasShadowOrIframeContentUIUsage(scriptPath) {
171
+ const source = safeReadFile(scriptPath);
172
+ if (!source) return false;
173
+ return CONTENT_CSS_PATTERN.test(source) || CONTENT_WRAPPER_PATTERN.test(source);
174
+ }
175
+ function safeReadFile(filePath) {
176
+ if (!existsSync(filePath)) return;
177
+ try {
178
+ return readFileSync(filePath, "utf-8");
179
+ } catch {
180
+ return;
181
+ }
182
+ }
183
+ function applyContentCssManifestPolicy(outputManifest, inputManifest, browser, contentScriptOutput) {
184
+ const shouldRemoveCss = contentScriptOutput?.autoFillCssInManifest === false && !hasUserDefinedContentCss(inputManifest, browser);
185
+ return shouldRemoveCss ? removeContentScriptCss(outputManifest) : outputManifest;
186
+ }
187
+ function hasUserDefinedContentCss(manifest, browser) {
188
+ const branch = pickManifestBranch(manifest, browser);
189
+ if (!branch) return false;
190
+ const scripts = branch.content_scripts;
191
+ if (!Array.isArray(scripts)) return false;
192
+ return scripts.some(hasCssField);
193
+ }
194
+ function hasCssField(item) {
195
+ if (!isPlainObject(item)) return false;
196
+ const css = item.css;
197
+ return Array.isArray(css) && css.length > 0;
198
+ }
199
+ function pickManifestBranch(manifest, browser) {
200
+ if (!isPlainObject(manifest)) return null;
201
+ if (!("chromium" in manifest) && !("firefox" in manifest)) return manifest;
202
+ const byBrowser = manifest;
203
+ const primary = "firefox" === browser ? byBrowser.firefox : byBrowser.chromium;
204
+ const fallback = "firefox" === browser ? byBrowser.chromium : byBrowser.firefox;
205
+ return asManifestRecord(primary) ?? asManifestRecord(fallback);
206
+ }
207
+ function asManifestRecord(value) {
208
+ return isPlainObject(value) ? value : null;
209
+ }
210
+ function isPlainObject(value) {
211
+ return "object" == typeof value && null !== value && !Array.isArray(value);
212
+ }
213
+ function removeContentScriptCss(manifest) {
214
+ const scripts = manifest.content_scripts;
215
+ if (!Array.isArray(scripts)) return manifest;
216
+ const next = scripts.map((item)=>{
217
+ if (!isPlainObject(item)) return item;
218
+ const { css: _, ...rest } = item;
219
+ return rest;
220
+ });
221
+ return {
222
+ ...manifest,
223
+ content_scripts: next
224
+ };
225
+ }
226
+ function injectContentCssRuntimeMeta(distPath, contentScriptOutput) {
227
+ if (!contentScriptOutput?.css.length || !contentScriptOutput.js.length) return;
228
+ const normalizedCss = contentScriptOutput.css.map(normalizePath);
229
+ const cssTexts = normalizedCss.map((file)=>readCssAssetText(distPath, file));
230
+ const banner = buildCssBanner(normalizedCss, cssTexts);
231
+ for (const jsRel of contentScriptOutput.js)prependBannerToJsFile(distPath, jsRel, banner);
232
+ }
233
+ function buildCssBanner(cssFiles, cssTexts) {
234
+ return `;globalThis.${CONTENT_CSS_GLOBAL_KEY}=${JSON.stringify(cssFiles)};globalThis.${CONTENT_CSS_TEXTS_GLOBAL_KEY}=${JSON.stringify(cssTexts)};\n`;
235
+ }
236
+ function prependBannerToJsFile(distPath, jsRel, banner) {
237
+ const absPath = resolve(distPath, jsRel);
238
+ if (!existsSync(absPath)) return;
239
+ const src = readFileSync(absPath, "utf-8");
240
+ if (hasCssMetaInjected(src)) return;
241
+ writeFileSync(absPath, banner + src, "utf-8");
242
+ }
243
+ function hasCssMetaInjected(source) {
244
+ return source.includes(`globalThis.${CONTENT_CSS_GLOBAL_KEY}`) && source.includes(`globalThis.${CONTENT_CSS_TEXTS_GLOBAL_KEY}`);
245
+ }
246
+ function readCssAssetText(distPath, file) {
247
+ const absPath = resolve(distPath, file);
248
+ return safeReadFile(absPath) ?? "";
249
+ }
250
+ function validateEntryHtmlRules(entries, manifest) {
251
+ const mv = getManifestVersion(manifest);
252
+ const errors = entries.flatMap((entry)=>validateEntryHtml(entry, mv));
253
+ if (errors.length) throw new Error(errors.join("; "));
254
+ }
255
+ function validateEntryHtml(entry, mv) {
256
+ const errors = [];
257
+ const htmlFlag = getEntryHtmlFlag(entry);
258
+ if (REQUIRED_HTML_ENTRIES.has(entry.name) && false === htmlFlag) errors.push(`entry "${entry.name}" must generate HTML; html:false is not allowed`);
259
+ if (3 === mv && "background" === entry.name && true === htmlFlag) errors.push('entry "background" cannot generate HTML in MV3');
260
+ return errors;
261
+ }
262
+ function getManifestVersion(manifest) {
263
+ const mv = manifest.manifest_version;
264
+ return 2 === mv || 3 === mv ? mv : null;
265
+ }
266
+ function getEntryHtmlFlag(entry) {
267
+ return entry.html;
268
+ }
269
+ async function writeMetaMarkdown(metaDir, manifest, entries, entrypointsMap) {
270
+ if (!ensureMetaDir(metaDir)) return;
271
+ const content = buildMetaMarkdown(manifest, entries, entrypointsMap);
272
+ const metaPath = resolve(metaDir, "meta.md");
273
+ await writeFile(metaPath, content, "utf-8");
274
+ }
275
+ function ensureMetaDir(metaDir) {
276
+ try {
277
+ if (!existsSync(metaDir)) mkdirSync(metaDir, {
278
+ recursive: true
279
+ });
280
+ return true;
281
+ } catch {
282
+ return false;
283
+ }
284
+ }
285
+ function buildMetaMarkdown(manifest, entries, entrypointsMap) {
286
+ const sections = [
287
+ formatAiPromptHeader(),
288
+ formatBasicSection(manifest),
289
+ formatPermissionsSection(manifest),
290
+ formatEntriesSection(entries, entrypointsMap)
291
+ ];
292
+ return sections.join("\n\n") + "\n";
293
+ }
294
+ function formatAiPromptHeader() {
295
+ return "---\nai_context: addfox_extension_metadata\ndescription: Structured metadata about the Addfox browser extension project\nwhen_to_use:\n - Initial project exploration - understand extension structure, entries, permissions\n - Build debugging - check entry configuration, output paths, dependencies\n - Architecture review - analyze entry relationships and code organization\n - Before modifying entries - see current configuration and generated outputs\nstructure:\n - Section 1: Basic project info (name, version, manifest version)\n - Section 2: Permissions (required, host, optional)\n - Section 3: Entries (source files, build outputs, configuration flags)\nrelated_files:\n - error.md: Runtime errors (use when debugging extension errors)\n - llms.txt: This project's AI guide (always read first)\n---";
296
+ }
297
+ async function writeLlmsTxt(metaDir, manifest, entries) {
298
+ if (!ensureMetaDir(metaDir)) return;
299
+ const content = buildLlmsTxt(manifest, entries);
300
+ const llmsPath = resolve(metaDir, "llms.txt");
301
+ await writeFile(llmsPath, content, "utf-8");
302
+ }
303
+ function buildLlmsTxt(manifest, entries) {
304
+ const name = getString(manifest.name) ?? "Unknown";
305
+ const description = getString(manifest.description) ?? "Browser extension";
306
+ const version = getString(manifest.version) ?? "Unknown";
307
+ const mv = getManifestVersion(manifest);
308
+ const entryList = entries.map((e)=>`- **${e.name}**: ${e.scriptPath}`).join("\n");
309
+ return [
310
+ "# AI Guide for Addfox Extension Project",
311
+ "",
312
+ "> This file guides AI assistants working on this browser extension project.",
313
+ "> Generated by Addfox framework. Do not edit manually.",
314
+ "",
315
+ "## Project Overview",
316
+ "",
317
+ `- **Name**: ${name}`,
318
+ `- **Description**: ${description}`,
319
+ `- **Version**: ${version}`,
320
+ `- **Manifest Version**: ${mv ?? "Unknown"}`,
321
+ "- **Framework**: Addfox (browser extension framework)",
322
+ "",
323
+ "## Entry Points",
324
+ "",
325
+ entryList || "- No entries configured",
326
+ "",
327
+ "## AI Context Files in .addfox/",
328
+ "",
329
+ "This project generates three AI-friendly files in the \`.addfox/\` directory:",
330
+ "",
331
+ "### 1. llms.txt (this file)",
332
+ "**Purpose**: High-level project guide for AI assistants.",
333
+ "",
334
+ "**When to read**:",
335
+ "- First interaction with the project",
336
+ "- Understanding project structure and conventions",
337
+ "- Looking for guidance on which file to use next",
338
+ "",
339
+ "**Contains**: Project overview, entry list, and file usage guide.",
340
+ "",
341
+ "### 2. meta.md",
342
+ "**Purpose**: Detailed project metadata and build information.",
343
+ "",
344
+ "**When to use**:",
345
+ "- ⭐ **AL**: Understanding extension structure, entries, and configuration",
346
+ "- ⭐ **Analyzing entry points**: Source files, build outputs, dependencies",
347
+ "- ⭐ **Build debugging**: Entry configuration, output paths, build issues",
348
+ "- ⭐ **Architecture review**: Entry relationships and code organization",
349
+ "- ⭐ **Before modifying entries**: Current configuration and generated outputs",
350
+ "",
351
+ "**Contains**:",
352
+ "- Basic info: name, version, manifest version",
353
+ "- Permissions: required, host, and optional permissions",
354
+ "- Entries: file tree showing source → build output mapping",
355
+ "",
356
+ "### 3. error.md",
357
+ "**Purpose**: Runtime error information from the extension.",
358
+ "",
359
+ "**When to use**:",
360
+ "- ⭐ **ALWAYS**: When user reports extension runtime errors",
361
+ "- ⭐ **Debugging**: Extension crashes, console errors, unexpected behavior",
362
+ "- ⭐ **Entry-specific issues**: Errors occurring in specific entry contexts",
363
+ "- ⭐ **Build vs runtime**: Errors that appear after successful build",
364
+ "",
365
+ "**Contains**:",
366
+ "- Error type and message",
367
+ "- Entry context where error occurred",
368
+ "- Stack trace",
369
+ "- Location (file, line, column)",
370
+ "- Timestamp",
371
+ "",
372
+ "**Note**: This file is cleared on each dev server start. It only contains the most recent error.",
373
+ "",
374
+ "## Quick Decision Guide",
375
+ "",
376
+ "| Scenario | File to Use | Why |",
377
+ "|----------|-------------|-----|",
378
+ "| First time seeing project | llms.txt | Get oriented |",
379
+ "| Understanding structure | meta.md | Detailed metadata |",
380
+ "| Build issues | meta.md | Entry configurations |",
381
+ "| Runtime errors | error.md | Stack traces and context |",
382
+ "| Permission issues | meta.md | Permission lists |",
383
+ "| Entry relationships | meta.md | File trees |",
384
+ "",
385
+ "## Addfox Framework Conventions",
386
+ "",
387
+ "### Entry Names",
388
+ "Standard browser extension entries:",
389
+ "- \`popup\`: Popup UI (usually has HTML)",
390
+ "- \`options\`: Options/settings page (usually has HTML)",
391
+ "- `background`: Service worker / background script (no HTML in MV3)",
392
+ "- `content`: Content script injected into web pages",
393
+ "- \`sidepanel\`: Side panel UI (Chrome)",
394
+ "- \`devtools\`: DevTools panel",
395
+ "- \`offscreen\`: Offscreen document (for DOM APIs in MV3)",
396
+ "",
397
+ "### Entry Configuration",
398
+ "Entries can have these flags:",
399
+ "- \`html: true\`: Generates HTML page (for popup/options)",
400
+ "- \`html: false\`: No HTML generation (for background/content)",
401
+ "- `outputFollowsScriptPath`: Output follows source script location",
402
+ "- `scriptInject: 'head' | 'body'`: Where to inject script in HTML",
403
+ "",
404
+ "---",
405
+ "",
406
+ "*Generated by Addfox. Last updated: " + new Date().toISOString() + "*",
407
+ ""
408
+ ].join("\n");
409
+ }
410
+ function formatBasicSection(manifest) {
411
+ const name = getString(manifest.name);
412
+ const description = getString(manifest.description);
413
+ const version = getString(manifest.version);
414
+ const frameworkVersion = getString(getAddfoxVersion());
415
+ const manifestVersion = getManifestVersion(manifest);
416
+ return [
417
+ "# Extension Meta",
418
+ "",
419
+ "## 1. Basic information",
420
+ "",
421
+ "- Framework: addfox",
422
+ `- Name: ${name ?? "Unknown"}`,
423
+ `- Description: ${description ?? "None"}`,
424
+ `- Version: ${version ?? "Unknown"}`,
425
+ `- Framework version: ${frameworkVersion ?? "Unknown"}`,
426
+ `- Manifest version: ${manifestVersion ?? "Unknown"}`
427
+ ].join("\n");
428
+ }
429
+ function getString(value) {
430
+ return "string" == typeof value ? value : void 0;
431
+ }
432
+ function formatPermissionsSection(manifest) {
433
+ const permissions = pickArray(manifest.permissions);
434
+ const hostPermissions = pickArray(manifest.host_permissions);
435
+ const optionalPermissions = pickArray(manifest.optional_permissions);
436
+ return [
437
+ "## 2. Permissions",
438
+ "",
439
+ "### 2.1 Permissions",
440
+ formatList(permissions),
441
+ "",
442
+ "### 2.2 Host permissions",
443
+ formatList(hostPermissions),
444
+ "",
445
+ "### 2.3 Optional permissions",
446
+ formatList(optionalPermissions)
447
+ ].join("\n");
448
+ }
449
+ function formatList(items) {
450
+ return items.length ? items.map((p)=>`- ${p}`).join("\n") : "- None";
451
+ }
452
+ function formatEntriesSection(entries, entrypointsMap) {
453
+ const lines = [
454
+ "## 3. Entries",
455
+ ""
456
+ ];
457
+ if (!entries.length) {
458
+ lines.push("- None");
459
+ return lines.join("\n");
460
+ }
461
+ const treeLines = [];
462
+ for(let i = 0; i < entries.length; i++){
463
+ const entry = entries[i];
464
+ const mapping = entrypointsMap?.get(entry.name);
465
+ const entryTree = formatEntryTree(entry, mapping);
466
+ treeLines.push(entryTree);
467
+ if (i < entries.length - 1) treeLines.push("");
468
+ }
469
+ lines.push("```text");
470
+ lines.push(...treeLines);
471
+ lines.push("```");
472
+ return lines.join("\n");
473
+ }
474
+ function formatEntryTree(entry, mapping) {
475
+ const lines = [];
476
+ const name = entry.name;
477
+ lines.push(`${name}/`);
478
+ const sourcePath = mapping?.source ?? entry.scriptPath ?? "unknown";
479
+ lines.push(`├── 📄 Source: ${normalizePath(sourcePath)}`);
480
+ if (entry.htmlPath) lines.push(`├── 📄 HTML: ${normalizePath(entry.htmlPath)}`);
481
+ const outputs = mapping?.outputs ?? [];
482
+ if (outputs.length > 0) {
483
+ const jsFiles = outputs.filter((f)=>f.endsWith(".js"));
484
+ const cssFiles = outputs.filter((f)=>f.endsWith(".css"));
485
+ const htmlFiles = outputs.filter((f)=>f.endsWith(".html"));
486
+ const otherFiles = outputs.filter((f)=>!f.endsWith(".js") && !f.endsWith(".css") && !f.endsWith(".html"));
487
+ const allGroups = [
488
+ {
489
+ label: "JS",
490
+ files: jsFiles
491
+ },
492
+ {
493
+ label: "CSS",
494
+ files: cssFiles
495
+ },
496
+ {
497
+ label: "HTML",
498
+ files: htmlFiles
499
+ },
500
+ {
501
+ label: "Other",
502
+ files: otherFiles
503
+ }
504
+ ].filter((g)=>g.files.length > 0);
505
+ for(let i = 0; i < allGroups.length; i++){
506
+ const group = allGroups[i];
507
+ const isLastGroup = i === allGroups.length - 1;
508
+ const groupPrefix = isLastGroup ? "└──" : "├──";
509
+ lines.push(`${groupPrefix} 📁 ${group.label}/`);
510
+ for(let j = 0; j < group.files.length; j++){
511
+ const file = group.files[j];
512
+ const isLastFile = j === group.files.length - 1;
513
+ const filePrefix = isLastGroup ? isLastFile ? " └──" : " ├──" : isLastFile ? "│ └──" : "│ ├──";
514
+ lines.push(`${filePrefix} ${file}`);
515
+ }
516
+ }
517
+ } else lines.push("└── 📁 Output: (not yet built)");
518
+ const configs = [];
519
+ if (true === entry.html) configs.push("html: true");
520
+ if (false === entry.html) configs.push("html: false");
521
+ if (entry.outputFollowsScriptPath) configs.push("outputFollowsScriptPath: true");
522
+ if (entry.scriptInject) configs.push(`scriptInject: ${entry.scriptInject}`);
523
+ if (configs.length > 0) lines.push(` ⚙️ ${configs.join(", ")}`);
524
+ return lines.join("\n");
525
+ }
526
+ function pickArray(field) {
527
+ if (!Array.isArray(field)) return [];
528
+ return field.filter((item)=>"string" == typeof item);
529
+ }
530
+ function extractEntrypointsMap(compilation, entries) {
531
+ const map = new Map();
532
+ const entrypoints = compilation.entrypoints;
533
+ for (const entry of entries){
534
+ const entryOutput = {
535
+ source: entry.scriptPath,
536
+ outputs: []
537
+ };
538
+ if (entrypoints) {
539
+ const ep = getEntrypointFromMap(entrypoints, entry.name);
540
+ if (ep && "function" == typeof ep.getFiles) try {
541
+ const files = ep.getFiles();
542
+ if (Array.isArray(files)) entryOutput.outputs = files.map(normalizePath).sort();
543
+ } catch {}
544
+ }
545
+ if (0 === entryOutput.outputs.length && compilation.assets) {
546
+ const inferredOutputs = inferEntryOutputsFromAssets(entry, compilation.assets);
547
+ entryOutput.outputs = inferredOutputs;
548
+ }
549
+ map.set(entry.name, entryOutput);
550
+ }
551
+ return map;
552
+ }
553
+ function getEntrypointFromMap(entrypoints, name) {
554
+ if (isMap(entrypoints)) return entrypoints.get(name);
555
+ if (isRecord(entrypoints)) return entrypoints[name];
556
+ }
557
+ function inferEntryOutputsFromAssets(entry, assets) {
558
+ const outputs = [];
559
+ const assetNames = Object.keys(assets);
560
+ const jsPatterns = [
561
+ `${entry.name}.js`,
562
+ `${entry.name}/index.js`,
563
+ `static/js/${entry.name}.*.js`,
564
+ `${entry.name}.*.js`
565
+ ];
566
+ const cssPatterns = [
567
+ `${entry.name}.css`,
568
+ `${entry.name}/index.css`,
569
+ `static/css/${entry.name}.*.css`,
570
+ `${entry.name}.*.css`
571
+ ];
572
+ const htmlPatterns = [
573
+ `${entry.name}.html`,
574
+ `${entry.name}/index.html`,
575
+ `${entry.name}/*.html`
576
+ ];
577
+ const patterns = [
578
+ ...jsPatterns,
579
+ ...cssPatterns,
580
+ ...htmlPatterns
581
+ ];
582
+ for (const asset of assetNames){
583
+ const normalizedAsset = normalizePath(asset);
584
+ for (const pattern of patterns)if (matchPattern(normalizedAsset, pattern)) {
585
+ outputs.push(normalizedAsset);
586
+ break;
587
+ }
588
+ }
589
+ return outputs.sort();
590
+ }
591
+ function matchPattern(filename, pattern) {
592
+ const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "{{GLOBSTAR}}").replace(/\*/g, "[^/]*").replace(/{{GLOBSTAR}}/g, ".*");
593
+ const regex = new RegExp(`^${regexPattern}$`);
594
+ return regex.test(filename);
595
+ }
596
+ export { extensionPlugin };
597
+
598
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { Compiler } from \"@rspack/core\";\r\nimport type { RsbuildPluginAPI } from \"@rsbuild/core\";\r\nimport { resolve } from \"path\";\r\nimport { writeFileSync, existsSync, mkdirSync, readFileSync } from \"fs\";\r\nimport { writeFile as writeFileAsync } from \"fs/promises\";\r\nimport type {\r\n AddfoxResolvedConfig,\r\n EntryInfo,\r\n BrowserTarget,\r\n ManifestRecord,\r\n ContentScriptOutput,\r\n} from \"@addfox/core\";\r\nimport { resolveManifestForTarget, getAddfoxVersion } from \"@addfox/core\";\r\n\r\nconst CONTENT_CSS_GLOBAL_KEY = \"__ADDFOX_CONTENT_CSS_FILES__\";\r\nconst CONTENT_CSS_TEXTS_GLOBAL_KEY = \"__ADDFOX_CONTENT_CSS_TEXTS__\";\r\n\r\nconst REQUIRED_HTML_ENTRIES = new Set([\"popup\", \"options\", \"sidepanel\", \"offscreen\"]);\r\n\r\nconst CONTENT_CSS_PATTERN = /defineShadowContentUI|defineIframeContentUI/;\r\nconst CONTENT_WRAPPER_PATTERN = /wrapper\\s*:\\s*[\"'](?:shadow|iframe)[\"']/;\r\n\r\nconst CONTENT_JS_PATTERNS = [\r\n (k: string) => k.startsWith(\"content/\") && k.endsWith(\".js\"),\r\n (k: string) => k === \"content.js\",\r\n];\r\n\r\nconst CONTENT_CSS_PATTERNS = [\r\n (k: string) => (k.startsWith(\"content/\") && k.endsWith(\".css\")) || k === \"content.css\",\r\n (k: string) => k.startsWith(\"static/css/content\"),\r\n];\r\n\r\ntype ContentScriptOutputWithPolicy = ContentScriptOutput & {\r\n autoFillCssInManifest?: boolean;\r\n};\r\n\r\ntype EntrypointLike = { getFiles?: () => ReadonlyArray<string> };\r\ntype EntrypointsMap = Map<string, EntrypointLike>;\r\ntype EntrypointsRecord = Record<string, EntrypointLike>;\r\ntype CompilationLike = {\r\n entrypoints?: unknown;\r\n assets?: Record<string, unknown>;\r\n getAssets?: () => ReadonlyArray<{ filename?: string; name?: string }>;\r\n};\r\ntype AssetLike = { filename?: string; name?: string };\r\n\r\n/**\r\n * Writes manifest.json after build. Entry and HTML (html: false for background/content) are handled by plugin-extension-entry.\r\n * Browser comes from CLI -l/--launch (config/constants), not from env.\r\n * \r\n * @param resolvedConfig - Resolved Addfox configuration\r\n * @param entries - Discovered entries\r\n * @param browser - Target browser (chromium or firefox)\r\n * @param distPath - Output directory path (browser-specific, e.g., .addfox/extension/extension-chromium)\r\n */\r\nexport function extensionPlugin(\r\n resolvedConfig: AddfoxResolvedConfig,\r\n entries: EntryInfo[],\r\n browser: BrowserTarget,\r\n distPath: string\r\n) {\r\n const { root, outputRoot, manifest } = resolvedConfig;\r\n const metaDir = resolve(root, outputRoot);\r\n\r\n return {\r\n name: \"rsbuild-plugin-extension-manifest\",\r\n setup(api: RsbuildPluginAPI) {\r\n api.onBeforeCreateCompiler(async ({ bundlerConfigs }) => {\r\n const config = bundlerConfigs[0];\r\n if (!config) return;\r\n\r\n config.plugins = config.plugins ?? [];\r\n config.plugins.push(createManifestPlugin(distPath, metaDir, manifest, entries, browser));\r\n });\r\n },\r\n };\r\n}\r\n\r\nfunction createManifestPlugin(\r\n distPath: string,\r\n metaDir: string,\r\n manifest: AddfoxResolvedConfig[\"manifest\"],\r\n entries: EntryInfo[],\r\n browser: BrowserTarget\r\n) {\r\n return {\r\n name: \"rsbuild-plugin-extension-manifest:post-build\",\r\n apply(compiler: Compiler) {\r\n compiler.hooks.afterEmit.tap(\"rsbuild-plugin-extension-manifest:post-build\", (compilation) => {\r\n emitManifest(distPath, metaDir, manifest, entries, browser, compilation);\r\n });\r\n },\r\n };\r\n}\r\n\r\nfunction emitManifest(\r\n distPath: string,\r\n metaDir: string,\r\n manifest: AddfoxResolvedConfig[\"manifest\"],\r\n entries: EntryInfo[],\r\n browser: BrowserTarget,\r\n compilation?: CompilationLike\r\n): void {\r\n ensureDir(distPath);\r\n\r\n const safeCompilation: CompilationLike = compilation ?? {};\r\n const contentScriptOutput = collectContentScriptOutput(safeCompilation, entries);\r\n injectContentCssRuntimeMeta(distPath, contentScriptOutput);\r\n\r\n const manifestObj = resolveManifestForTarget(\r\n manifest,\r\n entries,\r\n browser,\r\n console.warn,\r\n contentScriptOutput\r\n );\r\n\r\n const finalManifest = applyContentCssManifestPolicy(\r\n manifestObj,\r\n manifest,\r\n browser,\r\n contentScriptOutput\r\n );\r\n\r\n validateEntryHtmlRules(entries, finalManifest);\r\n writeManifestJson(distPath, finalManifest);\r\n\r\n // Extract entrypoints mapping for AI context\r\n const entrypointsMap = extractEntrypointsMap(safeCompilation, entries);\r\n\r\n // Fire-and-forget meta.md and llms.txt generation for AI consumption\r\n void Promise.all([\r\n writeMetaMarkdown(metaDir, finalManifest, entries, entrypointsMap),\r\n writeLlmsTxt(metaDir, finalManifest, entries),\r\n ]).catch(() => {\r\n // Intentionally ignore write errors to keep build/dev unaffected.\r\n });\r\n}\r\n\r\nfunction ensureDir(dirPath: string): void {\r\n if (!existsSync(dirPath)) {\r\n mkdirSync(dirPath, { recursive: true });\r\n }\r\n}\r\n\r\nfunction writeManifestJson(distPath: string, manifest: ManifestRecord): void {\r\n const manifestPath = resolve(distPath, \"manifest.json\");\r\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), \"utf-8\");\r\n}\r\n\r\n/**\r\n * Collect content entry js and css for [addfox.content] placeholder expansion.\r\n * Prefer compilation.entrypoints[\"content\"].getFiles() so we get exactly the assets built from the content entry (including any CSS it imports). Fallback to naming-based collection if entrypoints are unavailable or return no CSS.\r\n */\r\nfunction collectContentScriptOutput(\r\n compilation: CompilationLike,\r\n entries: EntryInfo[]\r\n): ContentScriptOutputWithPolicy | undefined {\r\n const hasContent = entries.some((e) => e.name === \"content\");\r\n if (!hasContent) return undefined;\r\n\r\n const autoFillCssInManifest = !shouldDisableManifestCssAutoFill(entries);\r\n const fromEntrypoint = tryGetContentEntryFiles(compilation);\r\n const byNames = collectContentScriptOutputByNames(compilation);\r\n\r\n if (fromEntrypoint?.js.length) {\r\n const css = fromEntrypoint.css.length ? fromEntrypoint.css : (byNames?.css ?? []);\r\n return { js: fromEntrypoint.js, css, autoFillCssInManifest };\r\n }\r\n\r\n if (!byNames) return undefined;\r\n return { ...byNames, autoFillCssInManifest };\r\n}\r\n\r\nfunction tryGetContentEntryFiles(compilation: CompilationLike): ContentScriptOutput | undefined {\r\n const entrypoints = compilation.entrypoints;\r\n if (!entrypoints) return undefined;\r\n\r\n const contentEntry = getContentEntryFromEntrypoints(entrypoints);\r\n if (!contentEntry || typeof contentEntry.getFiles !== \"function\") return undefined;\r\n\r\n const files = safeGetFiles(contentEntry);\r\n if (!files?.length) return undefined;\r\n\r\n return categorizeFiles(files);\r\n}\r\n\r\nfunction getContentEntryFromEntrypoints(entrypoints: unknown): EntrypointLike | undefined {\r\n if (isMap(entrypoints)) {\r\n return entrypoints.get(\"content\");\r\n }\r\n if (isRecord(entrypoints)) {\r\n return entrypoints[\"content\"];\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction isMap(value: unknown): value is EntrypointsMap {\r\n return typeof (value as EntrypointsMap).get === \"function\";\r\n}\r\n\r\nfunction isRecord(value: unknown): value is EntrypointsRecord {\r\n return typeof value === \"object\" && value !== null;\r\n}\r\n\r\nfunction safeGetFiles(entry: EntrypointLike): ReadonlyArray<string> | undefined {\r\n try {\r\n const files = entry.getFiles?.();\r\n return Array.isArray(files) && files.length ? files : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nfunction categorizeFiles(files: ReadonlyArray<string>): ContentScriptOutput {\r\n const js: string[] = [];\r\n const css: string[] = [];\r\n\r\n for (const name of files) {\r\n if (typeof name !== \"string\") continue;\r\n const normalized = normalizePath(name);\r\n\r\n if (normalized.endsWith(\".js\")) js.push(normalized);\r\n else if (normalized.endsWith(\".css\")) css.push(normalized);\r\n }\r\n\r\n return { js: js.sort(), css: css.sort() };\r\n}\r\n\r\nfunction collectContentScriptOutputByNames(compilation: CompilationLike): ContentScriptOutput | undefined {\r\n const keys = getAssetKeys(compilation);\r\n if (!keys.length) return undefined;\r\n\r\n return {\r\n js: filterAndSortKeys(keys, CONTENT_JS_PATTERNS),\r\n css: filterAndSortKeys(keys, CONTENT_CSS_PATTERNS),\r\n };\r\n}\r\n\r\nfunction getAssetKeys(compilation: CompilationLike): string[] {\r\n if (compilation.assets) {\r\n return Object.keys(compilation.assets);\r\n }\r\n return safeGetAssetKeys(compilation.getAssets);\r\n}\r\n\r\nfunction safeGetAssetKeys(getAssets?: () => ReadonlyArray<AssetLike>): string[] {\r\n if (typeof getAssets !== \"function\") return [];\r\n\r\n try {\r\n const assets = getAssets();\r\n if (!Array.isArray(assets)) return [];\r\n\r\n return assets\r\n .map((a) => a?.filename ?? a?.name)\r\n .filter((s): s is string => typeof s === \"string\");\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nfunction filterAndSortKeys(keys: string[], patterns: ((k: string) => boolean)[]): string[] {\r\n return keys\r\n .filter((k) => {\r\n const normalized = normalizePath(k);\r\n if (!normalized.endsWith(\".css\") && !normalized.endsWith(\".js\")) return false;\r\n return patterns.some((pattern) => pattern(normalized));\r\n })\r\n .map(normalizePath)\r\n .sort();\r\n}\r\n\r\nfunction normalizePath(path: string): string {\r\n return path.replace(/\\\\/g, \"/\");\r\n}\r\n\r\nfunction shouldDisableManifestCssAutoFill(entries: EntryInfo[]): boolean {\r\n const contentEntry = entries.find((e) => e.name === \"content\");\r\n if (!contentEntry) return false;\r\n return hasShadowOrIframeContentUIUsage(contentEntry.scriptPath);\r\n}\r\n\r\nfunction hasShadowOrIframeContentUIUsage(scriptPath: string): boolean {\r\n const source = safeReadFile(scriptPath);\r\n if (!source) return false;\r\n\r\n return CONTENT_CSS_PATTERN.test(source) || CONTENT_WRAPPER_PATTERN.test(source);\r\n}\r\n\r\nfunction safeReadFile(filePath: string): string | undefined {\r\n if (!existsSync(filePath)) return undefined;\r\n try {\r\n return readFileSync(filePath, \"utf-8\");\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nfunction applyContentCssManifestPolicy(\r\n outputManifest: ManifestRecord,\r\n inputManifest: AddfoxResolvedConfig[\"manifest\"],\r\n browser: BrowserTarget,\r\n contentScriptOutput?: ContentScriptOutputWithPolicy\r\n): ManifestRecord {\r\n const shouldRemoveCss =\r\n contentScriptOutput?.autoFillCssInManifest === false &&\r\n !hasUserDefinedContentCss(inputManifest, browser);\r\n\r\n return shouldRemoveCss ? removeContentScriptCss(outputManifest) : outputManifest;\r\n}\r\n\r\nfunction hasUserDefinedContentCss(\r\n manifest: AddfoxResolvedConfig[\"manifest\"],\r\n browser: BrowserTarget\r\n): boolean {\r\n const branch = pickManifestBranch(manifest, browser);\r\n if (!branch) return false;\r\n\r\n const scripts = branch.content_scripts;\r\n if (!Array.isArray(scripts)) return false;\r\n\r\n return scripts.some(hasCssField);\r\n}\r\n\r\nfunction hasCssField(item: unknown): boolean {\r\n if (!isPlainObject(item)) return false;\r\n const css = item.css;\r\n return Array.isArray(css) && css.length > 0;\r\n}\r\n\r\nfunction pickManifestBranch(\r\n manifest: AddfoxResolvedConfig[\"manifest\"],\r\n browser: BrowserTarget\r\n): ManifestRecord | null {\r\n if (!isPlainObject(manifest)) return null;\r\n if (!(\"chromium\" in manifest) && !(\"firefox\" in manifest)) {\r\n return manifest as ManifestRecord;\r\n }\r\n\r\n const byBrowser = manifest as { chromium?: unknown; firefox?: unknown };\r\n const primary = browser === \"firefox\" ? byBrowser.firefox : byBrowser.chromium;\r\n const fallback = browser === \"firefox\" ? byBrowser.chromium : byBrowser.firefox;\r\n\r\n return asManifestRecord(primary) ?? asManifestRecord(fallback);\r\n}\r\n\r\nfunction asManifestRecord(value: unknown): ManifestRecord | null {\r\n return isPlainObject(value) ? (value as ManifestRecord) : null;\r\n}\r\n\r\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\r\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction removeContentScriptCss(manifest: ManifestRecord): ManifestRecord {\r\n const scripts = manifest.content_scripts;\r\n if (!Array.isArray(scripts)) return manifest;\r\n\r\n const next = scripts.map((item) => {\r\n if (!isPlainObject(item)) return item;\r\n const { css: _, ...rest } = item;\r\n return rest;\r\n });\r\n\r\n return { ...manifest, content_scripts: next };\r\n}\r\n\r\nfunction injectContentCssRuntimeMeta(\r\n distPath: string,\r\n contentScriptOutput?: ContentScriptOutputWithPolicy\r\n): void {\r\n if (!contentScriptOutput?.css.length || !contentScriptOutput.js.length) return;\r\n\r\n const normalizedCss = contentScriptOutput.css.map(normalizePath);\r\n const cssTexts = normalizedCss.map((file) => readCssAssetText(distPath, file));\r\n const banner = buildCssBanner(normalizedCss, cssTexts);\r\n\r\n for (const jsRel of contentScriptOutput.js) {\r\n prependBannerToJsFile(distPath, jsRel, banner);\r\n }\r\n}\r\n\r\nfunction buildCssBanner(cssFiles: string[], cssTexts: string[]): string {\r\n return (\r\n `;globalThis.${CONTENT_CSS_GLOBAL_KEY}=${JSON.stringify(cssFiles)};` +\r\n `globalThis.${CONTENT_CSS_TEXTS_GLOBAL_KEY}=${JSON.stringify(cssTexts)};\\n`\r\n );\r\n}\r\n\r\nfunction prependBannerToJsFile(distPath: string, jsRel: string, banner: string): void {\r\n const absPath = resolve(distPath, jsRel);\r\n if (!existsSync(absPath)) return;\r\n\r\n const src = readFileSync(absPath, \"utf-8\");\r\n if (hasCssMetaInjected(src)) return;\r\n\r\n writeFileSync(absPath, banner + src, \"utf-8\");\r\n}\r\n\r\nfunction hasCssMetaInjected(source: string): boolean {\r\n return (\r\n source.includes(`globalThis.${CONTENT_CSS_GLOBAL_KEY}`) &&\r\n source.includes(`globalThis.${CONTENT_CSS_TEXTS_GLOBAL_KEY}`)\r\n );\r\n}\r\n\r\nfunction readCssAssetText(distPath: string, file: string): string {\r\n const absPath = resolve(distPath, file);\r\n return safeReadFile(absPath) ?? \"\";\r\n}\r\n\r\nfunction validateEntryHtmlRules(entries: EntryInfo[], manifest: ManifestRecord): void {\r\n const mv = getManifestVersion(manifest);\r\n const errors = entries.flatMap((entry) => validateEntryHtml(entry, mv));\r\n\r\n if (errors.length) {\r\n throw new Error(errors.join(\"; \"));\r\n }\r\n}\r\n\r\nfunction validateEntryHtml(entry: EntryInfo, mv: 2 | 3 | null): string[] {\r\n const errors: string[] = [];\r\n const htmlFlag = getEntryHtmlFlag(entry);\r\n\r\n if (REQUIRED_HTML_ENTRIES.has(entry.name) && htmlFlag === false) {\r\n errors.push(`entry \"${entry.name}\" must generate HTML; html:false is not allowed`);\r\n }\r\n if (mv === 3 && entry.name === \"background\" && htmlFlag === true) {\r\n errors.push(`entry \"background\" cannot generate HTML in MV3`);\r\n }\r\n\r\n return errors;\r\n}\r\n\r\nfunction getManifestVersion(manifest: ManifestRecord): 2 | 3 | null {\r\n const mv = manifest.manifest_version;\r\n return mv === 2 || mv === 3 ? mv : null;\r\n}\r\n\r\nfunction getEntryHtmlFlag(entry: EntryInfo): boolean | undefined {\r\n return (entry as EntryInfo & { html?: boolean }).html;\r\n}\r\n\r\nasync function writeMetaMarkdown(\r\n metaDir: string,\r\n manifest: ManifestRecord,\r\n entries: EntryInfo[],\r\n entrypointsMap?: EntrypointsMapData\r\n): Promise<void> {\r\n if (!ensureMetaDir(metaDir)) return;\r\n\r\n const content = buildMetaMarkdown(manifest, entries, entrypointsMap);\r\n const metaPath = resolve(metaDir, \"meta.md\");\r\n await writeFileAsync(metaPath, content, \"utf-8\");\r\n}\r\n\r\nfunction ensureMetaDir(metaDir: string): boolean {\r\n try {\r\n if (!existsSync(metaDir)) mkdirSync(metaDir, { recursive: true });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction buildMetaMarkdown(\r\n manifest: ManifestRecord,\r\n entries: EntryInfo[],\r\n entrypointsMap?: EntrypointsMapData\r\n): string {\r\n const sections = [\r\n formatAiPromptHeader(),\r\n formatBasicSection(manifest),\r\n formatPermissionsSection(manifest),\r\n formatEntriesSection(entries, entrypointsMap),\r\n ];\r\n\r\n return sections.join(\"\\n\\n\") + \"\\n\";\r\n}\r\n\r\nfunction formatAiPromptHeader(): string {\r\n return [\r\n \"---\",\r\n \"ai_context: addfox_extension_metadata\",\r\n \"description: Structured metadata about the Addfox browser extension project\",\r\n \"when_to_use:\",\r\n \" - Initial project exploration - understand extension structure, entries, permissions\",\r\n \" - Build debugging - check entry configuration, output paths, dependencies\",\r\n \" - Architecture review - analyze entry relationships and code organization\",\r\n \" - Before modifying entries - see current configuration and generated outputs\",\r\n \"structure:\",\r\n \" - Section 1: Basic project info (name, version, manifest version)\",\r\n \" - Section 2: Permissions (required, host, optional)\",\r\n \" - Section 3: Entries (source files, build outputs, configuration flags)\",\r\n \"related_files:\",\r\n \" - error.md: Runtime errors (use when debugging extension errors)\",\r\n \" - llms.txt: This project's AI guide (always read first)\",\r\n \"---\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nasync function writeLlmsTxt(\r\n metaDir: string,\r\n manifest: ManifestRecord,\r\n entries: EntryInfo[]\r\n): Promise<void> {\r\n if (!ensureMetaDir(metaDir)) return;\r\n\r\n const content = buildLlmsTxt(manifest, entries);\r\n const llmsPath = resolve(metaDir, \"llms.txt\");\r\n await writeFileAsync(llmsPath, content, \"utf-8\");\r\n}\r\n\r\nfunction buildLlmsTxt(manifest: ManifestRecord, entries: EntryInfo[]): string {\r\n const name = getString(manifest.name) ?? \"Unknown\";\r\n const description = getString(manifest.description) ?? \"Browser extension\";\r\n const version = getString(manifest.version) ?? \"Unknown\";\r\n const mv = getManifestVersion(manifest);\r\n\r\n const entryList = entries.map((e) => `- **${e.name}**: ${e.scriptPath}`).join(\"\\n\");\r\n\r\n return [\r\n \"# AI Guide for Addfox Extension Project\",\r\n \"\",\r\n \"> This file guides AI assistants working on this browser extension project.\",\r\n \"> Generated by Addfox framework. Do not edit manually.\",\r\n \"\",\r\n \"## Project Overview\",\r\n \"\",\r\n `- **Name**: ${name}`,\r\n `- **Description**: ${description}`,\r\n `- **Version**: ${version}`,\r\n `- **Manifest Version**: ${mv ?? \"Unknown\"}`,\r\n `- **Framework**: Addfox (browser extension framework)`,\r\n \"\",\r\n \"## Entry Points\",\r\n \"\",\r\n entryList || \"- No entries configured\",\r\n \"\",\r\n \"## AI Context Files in .addfox/\",\r\n \"\",\r\n \"This project generates three AI-friendly files in the \\`.addfox/\\` directory:\",\r\n \"\",\r\n \"### 1. llms.txt (this file)\",\r\n \"**Purpose**: High-level project guide for AI assistants.\",\r\n \"\",\r\n \"**When to read**:\",\r\n \"- First interaction with the project\",\r\n \"- Understanding project structure and conventions\",\r\n \"- Looking for guidance on which file to use next\",\r\n \"\",\r\n \"**Contains**: Project overview, entry list, and file usage guide.\",\r\n \"\",\r\n \"### 2. meta.md\",\r\n \"**Purpose**: Detailed project metadata and build information.\",\r\n \"\",\r\n \"**When to use**:\",\r\n \"- ⭐ **AL**: Understanding extension structure, entries, and configuration\",\r\n \"- ⭐ **Analyzing entry points**: Source files, build outputs, dependencies\",\r\n \"- ⭐ **Build debugging**: Entry configuration, output paths, build issues\",\r\n \"- ⭐ **Architecture review**: Entry relationships and code organization\",\r\n \"- ⭐ **Before modifying entries**: Current configuration and generated outputs\",\r\n \"\",\r\n \"**Contains**:\",\r\n \"- Basic info: name, version, manifest version\",\r\n \"- Permissions: required, host, and optional permissions\",\r\n \"- Entries: file tree showing source → build output mapping\",\r\n \"\",\r\n \"### 3. error.md\",\r\n \"**Purpose**: Runtime error information from the extension.\",\r\n \"\",\r\n \"**When to use**:\",\r\n \"- ⭐ **ALWAYS**: When user reports extension runtime errors\",\r\n \"- ⭐ **Debugging**: Extension crashes, console errors, unexpected behavior\",\r\n \"- ⭐ **Entry-specific issues**: Errors occurring in specific entry contexts\",\r\n \"- ⭐ **Build vs runtime**: Errors that appear after successful build\",\r\n \"\",\r\n \"**Contains**:\",\r\n \"- Error type and message\",\r\n \"- Entry context where error occurred\",\r\n \"- Stack trace\",\r\n \"- Location (file, line, column)\",\r\n \"- Timestamp\",\r\n \"\",\r\n \"**Note**: This file is cleared on each dev server start. It only contains the most recent error.\",\r\n \"\",\r\n \"## Quick Decision Guide\",\r\n \"\",\r\n \"| Scenario | File to Use | Why |\",\r\n \"|----------|-------------|-----|\",\r\n \"| First time seeing project | llms.txt | Get oriented |\",\r\n \"| Understanding structure | meta.md | Detailed metadata |\",\r\n \"| Build issues | meta.md | Entry configurations |\",\r\n \"| Runtime errors | error.md | Stack traces and context |\",\r\n \"| Permission issues | meta.md | Permission lists |\",\r\n \"| Entry relationships | meta.md | File trees |\",\r\n \"\",\r\n \"## Addfox Framework Conventions\",\r\n \"\",\r\n \"### Entry Names\",\r\n \"Standard browser extension entries:\",\r\n \"- \\`popup\\`: Popup UI (usually has HTML)\",\r\n \"- \\`options\\`: Options/settings page (usually has HTML)\",\r\n \"- \\`background\\`: Service worker / background script (no HTML in MV3)\",\r\n \"- \\`content\\`: Content script injected into web pages\",\r\n \"- \\`sidepanel\\`: Side panel UI (Chrome)\",\r\n \"- \\`devtools\\`: DevTools panel\",\r\n \"- \\`offscreen\\`: Offscreen document (for DOM APIs in MV3)\",\r\n \"\",\r\n \"### Entry Configuration\",\r\n \"Entries can have these flags:\",\r\n \"- \\`html: true\\`: Generates HTML page (for popup/options)\",\r\n \"- \\`html: false\\`: No HTML generation (for background/content)\",\r\n \"- \\`outputFollowsScriptPath\\`: Output follows source script location\",\r\n \"- \\`scriptInject: 'head' | 'body'\\`: Where to inject script in HTML\",\r\n \"\",\r\n \"---\",\r\n \"\",\r\n \"*Generated by Addfox. Last updated: \" + new Date().toISOString() + \"*\",\r\n \"\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction formatBasicSection(manifest: ManifestRecord): string {\r\n const name = getString(manifest.name);\r\n const description = getString(manifest.description);\r\n const version = getString(manifest.version);\r\n const frameworkVersion = getString(getAddfoxVersion());\r\n const manifestVersion = getManifestVersion(manifest);\r\n\r\n return [\r\n \"# Extension Meta\",\r\n \"\",\r\n \"## 1. Basic information\",\r\n \"\",\r\n \"- Framework: addfox\",\r\n `- Name: ${name ?? \"Unknown\"}`,\r\n `- Description: ${description ?? \"None\"}`,\r\n `- Version: ${version ?? \"Unknown\"}`,\r\n `- Framework version: ${frameworkVersion ?? \"Unknown\"}`,\r\n `- Manifest version: ${manifestVersion ?? \"Unknown\"}`,\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction getString(value: unknown): string | undefined {\r\n return typeof value === \"string\" ? value : undefined;\r\n}\r\n\r\nfunction formatPermissionsSection(manifest: ManifestRecord): string {\r\n const permissions = pickArray(manifest.permissions);\r\n const hostPermissions = pickArray(manifest.host_permissions);\r\n const optionalPermissions = pickArray(manifest.optional_permissions);\r\n\r\n return [\r\n \"## 2. Permissions\",\r\n \"\",\r\n \"### 2.1 Permissions\",\r\n formatList(permissions),\r\n \"\",\r\n \"### 2.2 Host permissions\",\r\n formatList(hostPermissions),\r\n \"\",\r\n \"### 2.3 Optional permissions\",\r\n formatList(optionalPermissions),\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction formatList(items: string[]): string {\r\n return items.length ? items.map((p) => `- ${p}`).join(\"\\n\") : \"- None\";\r\n}\r\n\r\nfunction formatEntriesSection(entries: EntryInfo[], entrypointsMap?: EntrypointsMapData): string {\r\n const lines = [\"## 3. Entries\", \"\"];\r\n\r\n if (!entries.length) {\r\n lines.push(\"- None\");\r\n return lines.join(\"\\n\");\r\n }\r\n\r\n // Build tree content for all entries\r\n const treeLines: string[] = [];\r\n for (let i = 0; i < entries.length; i++) {\r\n const entry = entries[i];\r\n const mapping = entrypointsMap?.get(entry.name);\r\n const entryTree = formatEntryTree(entry, mapping);\r\n treeLines.push(entryTree);\r\n // Add blank line between entries (except after last)\r\n if (i < entries.length - 1) {\r\n treeLines.push(\"\");\r\n }\r\n }\r\n\r\n // Wrap in text code block for tree visualization\r\n lines.push(\"```text\");\r\n lines.push(...treeLines);\r\n lines.push(\"```\");\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\nfunction formatEntryTree(entry: EntryInfo, mapping?: EntryFilesMapping): string {\r\n const lines: string[] = [];\r\n const name = entry.name;\r\n\r\n // Entry header\r\n lines.push(`${name}/`);\r\n\r\n // Source file\r\n const sourcePath = mapping?.source ?? entry.scriptPath ?? \"unknown\";\r\n lines.push(`├── 📄 Source: ${normalizePath(sourcePath)}`);\r\n\r\n // HTML file if exists\r\n if (entry.htmlPath) {\r\n lines.push(`├── 📄 HTML: ${normalizePath(entry.htmlPath)}`);\r\n }\r\n\r\n // Output files from compilation\r\n const outputs = mapping?.outputs ?? [];\r\n if (outputs.length > 0) {\r\n // Group outputs by type\r\n const jsFiles = outputs.filter((f) => f.endsWith(\".js\"));\r\n const cssFiles = outputs.filter((f) => f.endsWith(\".css\"));\r\n const htmlFiles = outputs.filter((f) => f.endsWith(\".html\"));\r\n const otherFiles = outputs.filter((f) => !f.endsWith(\".js\") && !f.endsWith(\".css\") && !f.endsWith(\".html\"));\r\n\r\n const allGroups = [\r\n { label: \"JS\", files: jsFiles },\r\n { label: \"CSS\", files: cssFiles },\r\n { label: \"HTML\", files: htmlFiles },\r\n { label: \"Other\", files: otherFiles },\r\n ].filter((g) => g.files.length > 0);\r\n\r\n for (let i = 0; i < allGroups.length; i++) {\r\n const group = allGroups[i];\r\n const isLastGroup = i === allGroups.length - 1;\r\n const groupPrefix = isLastGroup ? \"└──\" : \"├──\";\r\n\r\n lines.push(`${groupPrefix} 📁 ${group.label}/`);\r\n\r\n for (let j = 0; j < group.files.length; j++) {\r\n const file = group.files[j];\r\n const isLastFile = j === group.files.length - 1;\r\n const filePrefix = isLastGroup ? (isLastFile ? \" └──\" : \" ├──\") : (isLastFile ? \"│ └──\" : \"│ ├──\");\r\n lines.push(`${filePrefix} ${file}`);\r\n }\r\n }\r\n } else {\r\n lines.push(\"└── 📁 Output: (not yet built)\");\r\n }\r\n\r\n // Configuration flags\r\n const configs: string[] = [];\r\n if (entry.html === true) configs.push(\"html: true\");\r\n if (entry.html === false) configs.push(\"html: false\");\r\n if (entry.outputFollowsScriptPath) configs.push(\"outputFollowsScriptPath: true\");\r\n if (entry.scriptInject) configs.push(`scriptInject: ${entry.scriptInject}`);\r\n\r\n if (configs.length > 0) {\r\n lines.push(` ⚙️ ${configs.join(\", \")}`);\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\nfunction pickArray(field: unknown): string[] {\r\n if (!Array.isArray(field)) return [];\r\n return field.filter((item): item is string => typeof item === \"string\");\r\n}\r\n\r\n/** Entry files mapping from compilation entrypoints */\r\ninterface EntryFilesMapping {\r\n /** Source entry file path */\r\n source: string;\r\n /** Output files generated for this entry (JS, CSS, HTML) */\r\n outputs: string[];\r\n}\r\n\r\ntype EntrypointsMapData = Map<string, EntryFilesMapping>;\r\n\r\n/**\r\n * Extract entrypoints mapping from compilation for AI context.\r\n * Maps each entry name to its source file and generated output files.\r\n */\r\nfunction extractEntrypointsMap(compilation: CompilationLike, entries: EntryInfo[]): EntrypointsMapData {\r\n const map = new Map<string, EntryFilesMapping>();\r\n const entrypoints = compilation.entrypoints;\r\n\r\n for (const entry of entries) {\r\n const entryOutput: EntryFilesMapping = {\r\n source: entry.scriptPath,\r\n outputs: [],\r\n };\r\n\r\n // Try to get files from compilation entrypoints\r\n if (entrypoints) {\r\n const ep = getEntrypointFromMap(entrypoints, entry.name);\r\n if (ep && typeof ep.getFiles === \"function\") {\r\n try {\r\n const files = ep.getFiles();\r\n if (Array.isArray(files)) {\r\n entryOutput.outputs = files.map(normalizePath).sort();\r\n }\r\n } catch {\r\n // Fallback to empty outputs if getFiles fails\r\n }\r\n }\r\n }\r\n\r\n // If no outputs from entrypoints, try to infer from assets\r\n if (entryOutput.outputs.length === 0 && compilation.assets) {\r\n const inferredOutputs = inferEntryOutputsFromAssets(entry, compilation.assets);\r\n entryOutput.outputs = inferredOutputs;\r\n }\r\n\r\n map.set(entry.name, entryOutput);\r\n }\r\n\r\n return map;\r\n}\r\n\r\nfunction getEntrypointFromMap(entrypoints: unknown, name: string): EntrypointLike | undefined {\r\n if (isMap(entrypoints)) {\r\n return entrypoints.get(name);\r\n }\r\n if (isRecord(entrypoints)) {\r\n return entrypoints[name];\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction inferEntryOutputsFromAssets(entry: EntryInfo, assets: Record<string, unknown>): string[] {\r\n const outputs: string[] = [];\r\n const assetNames = Object.keys(assets);\r\n\r\n // Match JS files\r\n const jsPatterns = [\r\n `${entry.name}.js`,\r\n `${entry.name}/index.js`,\r\n `static/js/${entry.name}.*.js`,\r\n `${entry.name}.*.js`,\r\n ];\r\n\r\n // Match CSS files\r\n const cssPatterns = [\r\n `${entry.name}.css`,\r\n `${entry.name}/index.css`,\r\n `static/css/${entry.name}.*.css`,\r\n `${entry.name}.*.css`,\r\n ];\r\n\r\n // Match HTML files\r\n const htmlPatterns = [\r\n `${entry.name}.html`,\r\n `${entry.name}/index.html`,\r\n `${entry.name}/*.html`,\r\n ];\r\n\r\n const patterns = [...jsPatterns, ...cssPatterns, ...htmlPatterns];\r\n\r\n for (const asset of assetNames) {\r\n const normalizedAsset = normalizePath(asset);\r\n for (const pattern of patterns) {\r\n if (matchPattern(normalizedAsset, pattern)) {\r\n outputs.push(normalizedAsset);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return outputs.sort();\r\n}\r\n\r\nfunction matchPattern(filename: string, pattern: string): boolean {\r\n // Convert simple glob pattern to regex\r\n const regexPattern = pattern\r\n .replace(/\\./g, \"\\\\.\")\r\n .replace(/\\*\\*/g, \"{{GLOBSTAR}}\")\r\n .replace(/\\*/g, \"[^/]*\")\r\n .replace(/{{GLOBSTAR}}/g, \".*\");\r\n const regex = new RegExp(`^${regexPattern}$`);\r\n return regex.test(filename);\r\n}\r\n"],"names":["CONTENT_CSS_GLOBAL_KEY","CONTENT_CSS_TEXTS_GLOBAL_KEY","REQUIRED_HTML_ENTRIES","Set","CONTENT_CSS_PATTERN","CONTENT_WRAPPER_PATTERN","CONTENT_JS_PATTERNS","k","CONTENT_CSS_PATTERNS","extensionPlugin","resolvedConfig","entries","browser","distPath","root","outputRoot","manifest","metaDir","resolve","api","bundlerConfigs","config","createManifestPlugin","compiler","compilation","emitManifest","ensureDir","safeCompilation","contentScriptOutput","collectContentScriptOutput","injectContentCssRuntimeMeta","manifestObj","resolveManifestForTarget","console","finalManifest","applyContentCssManifestPolicy","validateEntryHtmlRules","writeManifestJson","entrypointsMap","extractEntrypointsMap","Promise","writeMetaMarkdown","writeLlmsTxt","dirPath","existsSync","mkdirSync","manifestPath","writeFileSync","JSON","hasContent","e","autoFillCssInManifest","shouldDisableManifestCssAutoFill","fromEntrypoint","tryGetContentEntryFiles","byNames","collectContentScriptOutputByNames","css","entrypoints","contentEntry","getContentEntryFromEntrypoints","files","safeGetFiles","categorizeFiles","isMap","isRecord","value","entry","Array","undefined","js","name","normalized","normalizePath","keys","getAssetKeys","filterAndSortKeys","Object","safeGetAssetKeys","getAssets","assets","a","s","patterns","pattern","path","hasShadowOrIframeContentUIUsage","scriptPath","source","safeReadFile","filePath","readFileSync","outputManifest","inputManifest","shouldRemoveCss","hasUserDefinedContentCss","removeContentScriptCss","branch","pickManifestBranch","scripts","hasCssField","item","isPlainObject","byBrowser","primary","fallback","asManifestRecord","next","_","rest","normalizedCss","cssTexts","file","readCssAssetText","banner","buildCssBanner","jsRel","prependBannerToJsFile","cssFiles","absPath","src","hasCssMetaInjected","mv","getManifestVersion","errors","validateEntryHtml","Error","htmlFlag","getEntryHtmlFlag","ensureMetaDir","content","buildMetaMarkdown","metaPath","writeFileAsync","sections","formatAiPromptHeader","formatBasicSection","formatPermissionsSection","formatEntriesSection","buildLlmsTxt","llmsPath","getString","description","version","entryList","Date","frameworkVersion","getAddfoxVersion","manifestVersion","permissions","pickArray","hostPermissions","optionalPermissions","formatList","items","p","lines","treeLines","i","mapping","entryTree","formatEntryTree","sourcePath","outputs","jsFiles","f","htmlFiles","otherFiles","allGroups","g","group","isLastGroup","groupPrefix","j","isLastFile","filePrefix","configs","field","map","Map","entryOutput","ep","getEntrypointFromMap","inferredOutputs","inferEntryOutputsFromAssets","assetNames","jsPatterns","cssPatterns","htmlPatterns","asset","normalizedAsset","matchPattern","filename","regexPattern","regex","RegExp"],"mappings":"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AAI,CAAC;IAE9E,OAAO;QACL;QACA;QACA;QACA;QACA;QACA;QACA;QACA,CAAC,YAAY,EAAEqB,MAAM;QACrB,CAAC,mBAAmB,EAAEuE,aAAa;QACnC,CAAC,eAAe,EAAEC,SAAS;QAC3B,CAAC,wBAAwB,EAAErB,MAAM,WAAW;QAC5C;QACA;QACA;QACA;QACAsB,aAAa;QACb;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,IAAIC,OAAO,WAAW,KAAK;QACpE;KACD,CAAC,IAAI,CAAC;AACT;AAEA,SAAST,mBAAmBxH,QAAwB;IAClD,MAAMuD,OAAOsE,UAAU7H,SAAS,IAAI;IACpC,MAAM8H,cAAcD,UAAU7H,SAAS,WAAW;IAClD,MAAM+H,UAAUF,UAAU7H,SAAS,OAAO;IAC1C,MAAMkI,mBAAmBL,UAAUM;IACnC,MAAMC,kBAAkBzB,mBAAmB3G;IAE3C,OAAO;QACL;QACA;QACA;QACA;QACA;QACA,CAAC,QAAQ,EAAEuD,QAAQ,WAAW;QAC9B,CAAC,eAAe,EAAEuE,eAAe,QAAQ;QACzC,CAAC,WAAW,EAAEC,WAAW,WAAW;QACpC,CAAC,qBAAqB,EAAEG,oBAAoB,WAAW;QACvD,CAAC,oBAAoB,EAAEE,mBAAmB,WAAW;KACtD,CAAC,IAAI,CAAC;AACT;AAEA,SAASP,UAAU3E,KAAc;IAC/B,OAAO,AAAiB,YAAjB,OAAOA,QAAqBA,QAAQG;AAC7C;AAEA,SAASoE,yBAAyBzH,QAAwB;IACxD,MA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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@addfox/rsbuild-plugin-extension-manifest",
3
+ "version": "0.1.1-beta.2",
4
+ "description": "Rsbuild plugin: write manifest.json and remove stray HTML (internal)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "main": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "@addfox/core": "0.1.1-beta.2"
22
+ },
23
+ "devDependencies": {
24
+ "@rspack/core": "^1.7.8",
25
+ "@rsbuild/core": "^1.7.3",
26
+ "@rslib/core": "^0.20.0",
27
+ "@rstest/core": "^0.9.2",
28
+ "@rstest/coverage-istanbul": "^0.3.0",
29
+ "@types/node": "^20.0.0",
30
+ "typescript": "^5.0.0"
31
+ },
32
+ "peerDependencies": {
33
+ "@rsbuild/core": ">=1.0.0",
34
+ "@rspack/core": ">=1.0.0"
35
+ },
36
+ "scripts": {
37
+ "build": "rslib build",
38
+ "dev": "rslib build --watch",
39
+ "test": "rstest run",
40
+ "test:coverage": "rstest run --coverage"
41
+ }
42
+ }