extension 3.0.0-next.9 → 3.1.0-next.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,26 +1,30 @@
1
1
  [npm-version-image]: https://img.shields.io/npm/v/extension.svg?color=0971fe
2
2
  [npm-version-url]: https://www.npmjs.com/package/extension
3
- [action-image]: https://github.com/extension-js/extension.js/actions/workflows/ci.yml/badge.svg?branch=main&color=2ecc40
3
+ [npm-downloads-image]: https://img.shields.io/npm/dm/extension.svg?color=0971fe
4
+ [npm-downloads-url]: https://www.npmjs.com/package/extension
5
+ [action-image]: https://github.com/extension-js/extension.js/actions/workflows/ci.yml/badge.svg?branch=main&color=0971fe
4
6
  [action-url]: https://github.com/extension-js/extension.js/actions
5
- [discord-image]: https://img.shields.io/discord/1253608412890271755?label=Discord&logo=discord&style=flat&color=2ecc40
7
+ [discord-image]: https://img.shields.io/discord/1253608412890271755?label=Discord&logo=discord&style=flat&color=0971fe
6
8
  [discord-url]: https://discord.gg/v9h2RgeTSN
7
- [snyk-image]: https://snyk.io/test/github/extension-js/extension/badge.svg?color=2ecc40
9
+ [snyk-image]: https://snyk.io/test/github/extension-js/extension/badge.svg?color=0971fe
8
10
  [snyk-url]: https://snyk.io/test/github/extension-js/extension
9
11
 
10
- > The cross-browser extension framework
12
+ [![Version][npm-version-image]][npm-version-url] [![Downloads][npm-downloads-image]][npm-downloads-url] [![CI][action-image]][action-url] [![Discord][discord-image]][discord-url]
13
+
14
+ # Extension.js
11
15
 
12
- # Extension.js [![Version][npm-version-image]][npm-version-url] [![workflow][action-image]][action-url] [![discord][discord-image]][discord-url]
16
+ > The cross-browser extension framework
13
17
 
14
18
  <img alt="Logo" align="right" src="https://avatars.githubusercontent.com/u/172809806" width="15.5%" />
15
19
 
16
- - [Create A New Extension](#create-a-new-extension) — How to create a new extension.
17
- - [Get Started Immediately](#get-started-immediately) — Get work done in no time.
18
- - [Start From An Example](https://github.com/extension-js/extension.js/tree/main/examples) — Start with your favorite tool.
19
- - [I have An Extension](#i-have-an-extension) — Use only specific parts of Extension.js.
20
+ - [Create a new extension](#create-a-new-extension) — How to create a new extension.
21
+ - [Watch demo](#watch-demo) — See how creating a new extension works.
22
+ - [Start from an example](https://github.com/extension-js/extension.js/tree/main/examples) — Start from a working baseline.
23
+ - [I have an extension](#i-have-an-extension) — Use only specific parts of Extension.js.
20
24
 
21
- Extension.js makes it very easy to develop cross-browser extensions.<br />Developers prefer it for its fast builds, unified interface, and zero configuration setup.
25
+ Create cross-browser extensions without manual build configuration.<br />Use Extension.js to develop, build, and preview across browsers with a unified workflow.
22
26
 
23
- ## Create A New Extension
27
+ ## Create a new extension
24
28
 
25
29
  Use the `create` command to generate a new extension. Also works with pnpm, yarn, and bun.
26
30
 
@@ -30,11 +34,11 @@ cd my-extension
30
34
  npm run dev
31
35
  ```
32
36
 
33
- ### Watch Demo
37
+ ### Watch demo
34
38
 
35
- https://github.com/cezaraugusto/extension/assets/4672033/7263d368-99c4-434f-a60a-72c489672586
39
+ [Watch demo](https://github.com/cezaraugusto/extension/assets/4672033/7263d368-99c4-434f-a60a-72c489672586)
36
40
 
37
- ## Web Standards and Framework Support
41
+ ## Web standards and framework support
38
42
 
39
43
  <!-- For a preview of extensions running these technologies, see the [templates](https://templates.extension.land) website. -->
40
44
 
@@ -46,15 +50,18 @@ https://github.com/cezaraugusto/extension/assets/4672033/7263d368-99c4-434f-a60a
46
50
 
47
51
  </div>
48
52
 
49
- ## Get Started Immediately
53
+ <details>
54
+ <summary>Get started from a sample</summary>
55
+
56
+ ## Get started
50
57
 
51
58
  Start developing an extension using a sample from Chrome Extension Samples
52
59
 
53
60
  See the example below where we request the sample [page-redder](https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/sample.page-redder) from [Google Chrome Extension Samples](https://github.com/GoogleChrome/chrome-extensions-samples).
54
61
 
55
- ### Watch Demo
62
+ ### Watch demo
56
63
 
57
- https://github.com/cezaraugusto/extension/assets/4672033/ee221a94-6ec7-4e04-8553-8812288927f1
64
+ [Watch demo](https://github.com/cezaraugusto/extension/assets/4672033/ee221a94-6ec7-4e04-8553-8812288927f1)
58
65
 
59
66
  ### Try Yourself
60
67
 
@@ -64,13 +71,13 @@ npx extension@latest dev https://github.com/GoogleChrome/chrome-extensions-sampl
64
71
 
65
72
  </details>
66
73
 
67
- ## I have An Extension
74
+ ## I have an extension
68
75
 
69
76
  If you have an existing extension which is using a package manager, you can install the Extension.js package and manually create the scripts used to run your extension.
70
77
 
71
- ### See How It Works
78
+ ### See how it works
72
79
 
73
- https://github.com/cezaraugusto/extension/assets/4672033/48694a23-b7f1-4098-9c5d-eff49983739c
80
+ [See how it works](https://github.com/cezaraugusto/extension/assets/4672033/48694a23-b7f1-4098-9c5d-eff49983739c)
74
81
 
75
82
  **Step 1 - Install extension as a `devDependency`**
76
83
 
@@ -102,9 +109,9 @@ Done. You are all set!
102
109
 
103
110
  ## Using a specific browser for development
104
111
 
105
- | <img src="https://raw.githubusercontent.com/alrra/browser-logos/main/src/chrome/chrome.svg" width="70"> | <img src="https://raw.githubusercontent.com/alrra/browser-logos/main/src/edge/edge.svg" width="70"> | <img src="https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox.svg" width="70"> | <img src="https://raw.githubusercontent.com/alrra/browser-logos/main/src/safari/safari.svg" width="70"> | <img src="https://raw.githubusercontent.com/alrra/browser-logos/main/src/chromium/chromium.svg" width="70"> | <img src="https://raw.githubusercontent.com/alrra/browser-logos/main/src/firefox/firefox.svg" width="70"> |
106
- | :-----------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------: |
107
- | Chrome browser<br>✅ | Edge browser<br>✅ | Firefox browser<br>✅ | Safari browser<br>(soon) | Chromium-based<br>✅ | Gecko-based<br>✅ |
112
+ | <img src="https://media.extension.land/logos/browsers/chrome.svg" width="70"> | <img src="https://media.extension.land/logos/browsers/edge.svg" width="70"> | <img src="https://media.extension.land/logos/browsers/firefox.svg" width="70"> | <img src="https://media.extension.land/logos/browsers/safari.svg" width="70"> | <img src="https://media.extension.land/logos/browsers/chromium.svg" width="70"> | <img src="https://media.extension.land/logos/browsers/firefox.svg" width="70"> |
113
+ | :---------------------------------------------------------------------------: | :-------------------------------------------------------------------------: | :----------------------------------------------------------------------------: | :---------------------------------------------------------------------------: | :-----------------------------------------------------------------------------: | :----------------------------------------------------------------------------: |
114
+ | Chrome browser<br>✅ | Edge browser<br>✅ | Firefox browser<br>✅ | Safari browser<br>(soon) | Chromium-based<br>✅ | Gecko-based<br>✅ |
108
115
 
109
116
  ### Browser flags and custom binaries
110
117
 
@@ -133,7 +140,7 @@ npx extension@latest dev --gecko-binary "/Applications/Firefox.app/Contents/MacO
133
140
  <div align="center">
134
141
  <p>
135
142
  <span style="font-size:21px; color:black;">Browser testing via</span><br>
136
- <a href="https://www.lambdatest.com/?utm_source=extensionjs&utm_medium=sponsor" target="_blank">
143
+ <a href="https://www.lambdatest.com/?utm_source=extensionjs&utm_medium=sponsor" target="_blank" rel="noopener noreferrer">
137
144
  <img src="https://www.lambdatest.com/blue-logo.png" width="250" height="45" alt="LambdaTest Logo" />
138
145
  </a>
139
146
  </p>
@@ -7,6 +7,15 @@ export declare const fmt: {
7
7
  block(title: string, rows: Array<[string, string]>): string;
8
8
  truncate(input: unknown, max?: number): string;
9
9
  };
10
+ export declare const commandDescriptions: {
11
+ readonly create: "Creates a new extension from a template (React, TypeScript, Vue, Svelte, etc.)";
12
+ readonly dev: "Starts the development server with hot reloading";
13
+ readonly start: "Builds and starts the extension in production mode";
14
+ readonly preview: "Previews the extension in production mode without building";
15
+ readonly build: "Builds the extension for packaging/distribution";
16
+ readonly cleanup: "Cleans up orphaned instances and frees unused ports";
17
+ };
18
+ export declare function unhandledError(err: unknown): string;
10
19
  export declare function updateFailed(err: any): string;
11
20
  export declare function checkUpdates(packageJson: Record<string, any>, update: {
12
21
  latest: string;
package/dist/cli.js CHANGED
@@ -23,25 +23,63 @@ var __webpack_require__ = {};
23
23
  })();
24
24
  var __webpack_exports__ = {};
25
25
  const external_commander_namespaceObject = require("commander");
26
- var package_namespaceObject = JSON.parse('{"license":"MIT","repository":{"type":"git","url":"https://github.com/extension-js/extension.js","directory":"programs/cli"},"engines":{"node":">=18"},"exports":{".":{"types":"./dist/cli.d.ts","import":"./dist/cli.js","require":"./dist/cli.js"}},"main":"./dist/cli.js","types":"./dist/cli.d.ts","typesVersions":{"*":{"types":["./types/index.d.ts"],"types/*":["./types/*"]}},"files":["dist","types"],"bin":{"extension":"./dist/cli.js"},"name":"extension","version":"3.0.0-next.9","description":"Create cross-browser extensions with no build configuration.","homepage":"https://extension.js.org/","author":{"name":"Cezar Augusto","email":"boss@cezaraugusto.net","url":"https://cezaraugusto.com"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org","tag":"latest"},"scripts":{"prepare":"rslib build >/dev/null 2>&1 || true","postinstall":"rslib build >/dev/null 2>&1 || true","compile":"rslib build","watch":"rslib build --watch","test":"vitest run"},"keywords":["zero-config","build","develop","browser","extension","chrome extension","edge extension","firefox extension","safari extension","web","react","typescript","webextension","browser-extension","chrome-extension","firefox-addon","edge-extension","safari-web-extension","manifest-v3","mv3","cross-browser","content-script","background-script","devtools","create-extension","scaffold","starter-template","boilerplate","cli"],"dependencies":{"commander":"^12.1.0","extension-create":"^2.2.0","pintor":"0.3.0","semver":"^7.6.3","update-check":"^1.5.4"},"devDependencies":{"@rslib/core":"^0.6.9","@types/chrome":"^0.0.287","@types/node":"^22.10.1","@types/react":"^19.0.1","@types/react-dom":"^19.0.1","@types/webextension-polyfill":"0.12.3","@types/mock-fs":"^4.13.4","@types/semver":"^7.5.8","mock-fs":"^5.4.1","webextension-polyfill":"^0.12.0","tsconfig":"*","typescript":"5.7.2","vitest":"^3.2.4"}}');
26
+ var package_namespaceObject = JSON.parse('{"license":"MIT","repository":{"type":"git","url":"git+https://github.com/extension-js/extension.js.git","directory":"programs/cli"},"engines":{"node":">=18"},"exports":{".":{"types":"./dist/cli.d.ts","import":"./dist/cli.js","require":"./dist/cli.js"}},"main":"./dist/cli.js","types":"./dist/cli.d.ts","typesVersions":{"*":{"types":["./types/index.d.ts"],"types/*":["./types/*"]}},"files":["dist","types"],"bin":{"extension":"./dist/cli.js"},"name":"extension","version":"3.1.0-next.10","description":"Create cross-browser extensions with no build configuration.","homepage":"https://extension.js.org/","bugs":{"url":"https://github.com/extension-js/extension.js/issues"},"author":{"name":"Cezar Augusto","email":"boss@cezaraugusto.net","url":"https://cezaraugusto.com"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"scripts":{"prepublishOnly":"pnpm run compile","compile":"rslib build","watch":"rslib build --watch","test":"vitest run"},"keywords":["zero-config","build","develop","browser","extension","chrome extension","edge extension","firefox extension","safari extension","web","react","typescript","webextension","browser-extension","chrome-extension","firefox-addon","edge-extension","safari-web-extension","manifest-v3","mv3","cross-browser","content-script","background-script","devtools","create-extension","scaffold","starter-template","boilerplate","cli"],"dependencies":{"extension-create":"^3.1.0-next.10","extension-develop":"^3.1.0-next.10","commander":"^14.0.2","pintor":"0.3.0","semver":"^7.7.3","update-check":"^1.5.4"},"devDependencies":{"@rslib/core":"^0.19.2","@types/chrome":"^0.1.33","@types/node":"^25.0.9","@types/react":"^19.2.8","@types/react-dom":"^19.2.3","@types/webextension-polyfill":"0.12.4","@types/mock-fs":"^4.13.4","@types/semver":"^7.7.1","mock-fs":"^5.5.0","webextension-polyfill":"^0.12.0","tsconfig":"*","typescript":"5.9.3","vitest":"^4.0.17"}}');
27
27
  const external_update_check_namespaceObject = require("update-check");
28
28
  var external_update_check_default = /*#__PURE__*/ __webpack_require__.n(external_update_check_namespaceObject);
29
29
  const external_pintor_namespaceObject = require("pintor");
30
30
  var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pintor_namespaceObject);
31
31
  function getLoggingPrefix(type) {
32
- if ('true' === process.env.EXTENSION_AUTHOR_MODE) return external_pintor_default().brightMagenta('error' === type ? 'ERROR' : "\u25BA\u25BA\u25BA");
32
+ const isAuthor = 'true' === process.env.EXTENSION_AUTHOR_MODE;
33
+ if (isAuthor) {
34
+ const base = 'error' === type ? 'ERROR Author says' : '►►► Author says';
35
+ return external_pintor_default().brightMagenta(base);
36
+ }
33
37
  if ('error' === type) return external_pintor_default().red('ERROR');
34
- if ('warn' === type) return external_pintor_default().brightYellow("\u25BA\u25BA\u25BA");
35
- if ('info' === type) return external_pintor_default().gray("\u25BA\u25BA\u25BA");
36
- return external_pintor_default().green("\u25BA\u25BA\u25BA");
38
+ if ('warn' === type) return external_pintor_default().brightYellow('►►►');
39
+ if ('info' === type) return external_pintor_default().gray('►►►');
40
+ return external_pintor_default().green('►►►');
37
41
  }
38
42
  const code = (text)=>external_pintor_default().blue(text);
39
43
  const arg = (text)=>external_pintor_default().gray(text);
44
+ const fmt = {
45
+ heading: (title)=>external_pintor_default().underline(external_pintor_default().blue(title)),
46
+ label: (k)=>external_pintor_default().gray(k.toUpperCase()),
47
+ val: (v)=>external_pintor_default().underline(v),
48
+ code: (v)=>external_pintor_default().blue(v),
49
+ bullet: (s)=>`- ${s}`,
50
+ block (title, rows) {
51
+ const head = fmt.heading(title);
52
+ const body = rows.map(([k, v])=>`${fmt.label(k)} ${v}`).join('\n');
53
+ return `${head}\n${body}`;
54
+ },
55
+ truncate (input, max = 800) {
56
+ const s = (()=>{
57
+ try {
58
+ return 'string' == typeof input ? input : JSON.stringify(input);
59
+ } catch {
60
+ return String(input);
61
+ }
62
+ })();
63
+ return s.length > max ? s.slice(0, max) + '…' : s;
64
+ }
65
+ };
66
+ const commandDescriptions = {
67
+ create: 'Creates a new extension from a template (React, TypeScript, Vue, Svelte, etc.)',
68
+ dev: 'Starts the development server with hot reloading',
69
+ start: 'Builds and starts the extension in production mode',
70
+ preview: 'Previews the extension in production mode without building',
71
+ build: 'Builds the extension for packaging/distribution',
72
+ cleanup: 'Cleans up orphaned instances and frees unused ports'
73
+ };
74
+ function unhandledError(err) {
75
+ const message = err instanceof Error ? err.stack || err.message : 'string' == typeof err ? err : fmt.truncate(err);
76
+ return `${getLoggingPrefix('error')} ${external_pintor_default().red(String(message || 'Unknown error'))}`;
77
+ }
40
78
  function updateFailed(err) {
41
- return `${getLoggingPrefix('error')} Failed to check for updates.\n${external_pintor_default().red(String((null == err ? void 0 : err.message) || err))}`;
79
+ return `${getLoggingPrefix('error')} Failed to check for updates.\n${external_pintor_default().red(String(err?.message || err))}`;
42
80
  }
43
81
  function checkUpdates(packageJson, update) {
44
- return `${getLoggingPrefix('info')} \u{1F9E9} ${external_pintor_default().blue('Extension.js')} update available.\n\nYou are currently using version ${external_pintor_default().red(String(packageJson.version))}. Latest stable is ${external_pintor_default().green(String(update.latest))}.\nPlease update to enjoy new features and improvements.`;
82
+ return `${getLoggingPrefix('info')} 🧩 ${external_pintor_default().blue('Extension.js')} update available.\n\nYou are currently using version ${external_pintor_default().red(String(packageJson.version))}. Latest stable is ${external_pintor_default().green(String(update.latest))}.\nUpdate to the latest stable to get fixes and new features.`;
45
83
  }
46
84
  function programUserHelp() {
47
85
  return `\n${getLoggingPrefix('info')} ${external_pintor_default().underline('Help center for the Extension.js program')}
@@ -56,22 +94,22 @@ Example
56
94
 
57
95
  Available Commands
58
96
  - ${code('extension create ' + arg('<project-name|project-path>'))}
59
- Creates a new extension from a template (React, TypeScript, Vue, Svelte, etc.)
97
+ ${commandDescriptions.create}
60
98
 
61
99
  - ${code('extension dev ' + arg('[project-path|remote-url]'))}
62
- Starts a development server with hot reloading
100
+ ${commandDescriptions.dev}
63
101
 
64
102
  - ${code('extension start ' + arg('[project-path|remote-url]'))}
65
- Builds and starts the extension in production mode
103
+ ${commandDescriptions.start}
66
104
 
67
105
  - ${code('extension preview ' + arg('[project-path|remote-url]'))}
68
- Previews the extension in production mode without building
106
+ ${commandDescriptions.preview}
69
107
 
70
108
  - ${code('extension build ' + arg('[project-path|remote-url]'))}
71
- Builds the extension for packaging/distribution
109
+ ${commandDescriptions.build}
72
110
 
73
111
  - ${code('extension cleanup')}
74
- Cleans up orphaned instances and frees unused ports
112
+ ${commandDescriptions.cleanup}
75
113
 
76
114
  Common Options
77
115
  - ${code('--browser')} ${arg('<chrome|edge|firefox|chromium|chromium-based|gecko-based|firefox-based>')} Target browser/engine (default: chrome)
@@ -144,7 +182,7 @@ Centralized Logger (for AI & CI)
144
182
  - ${code('--no-log-color')} ${arg(' ')} Disable ANSI colors (pretty)
145
183
  - ${code('--log-url')} ${arg('<substring|/regex/>')} Filter by URL
146
184
  - ${code('--log-tab')} ${arg('<id>')} Filter by tabId
147
- - Good CI pattern: ${code('EXTENSION_ENV=development EXTENSION_AUTO_EXIT_MS=6000 extension dev ./ext --logs=info --log-format=json')}
185
+ - Good CI pattern: ${code('EXTENSION_AUTHOR_MODE=development EXTENSION_AUTO_EXIT_MS=6000 extension dev ./ext --logs=info --log-format=json')}
148
186
 
149
187
  Special Folders for Entrypoints
150
188
  - Use special folders to handle entrypoints and assets not declared in manifest.json:
@@ -154,17 +192,17 @@ Special Folders for Entrypoints
154
192
 
155
193
  Predictable Output Paths
156
194
  - Core HTML destinations are standardized across browsers so you can reference them safely in code/tests:
157
- - ${code('devtools_page')} \u{2192} ${code('devtools/index.html')}
158
- - ${code('sidebar_action.default_panel')} (MV2) and ${code('side_panel.default_path')} (MV3) \u{2192} ${code('sidebar/index.html')}
159
- - ${code('options_ui.page')} and ${code('options_page')} \u{2192} ${code('options/index.html')}
160
- - ${code('background.page')} \u{2192} ${code('background/index.html')}
161
- - ${code('action.default_popup')}, ${code('browser_action.default_popup')}, ${code('page_action.default_popup')} \u{2192} ${code('action/index.html')}
195
+ - ${code('devtools_page')} ${code('devtools/index.html')}
196
+ - ${code('sidebar_action.default_panel')} (MV2) and ${code('side_panel.default_path')} (MV3) ${code('sidebar/index.html')}
197
+ - ${code('options_ui.page')} and ${code('options_page')} ${code('options/index.html')}
198
+ - ${code('background.page')} ${code('background/index.html')}
199
+ - ${code('action.default_popup')}, ${code('browser_action.default_popup')}, ${code('page_action.default_popup')} ${code('action/index.html')}
162
200
  - Other predictable outputs:
163
- - ${code('chrome_url_overrides.*')} \u{2192} ${code('chrome_url_overrides/<key>.html')}
164
- - ${code("content_scripts[n].js/css")} \u{2192} ${code("content_scripts/content-<n>.{js,css}")}
165
- - ${code('sandbox.pages[]')} \u{2192} ${code('sandbox/page-<n>.html')}
166
- - ${code("user_scripts.api_script")} \u{2192} ${code("user_scripts/api_script.js")}
167
- - ${code('icons/*')} \u{2192} ${code('icons/')} (feature-specific icon folders preserved where applicable)
201
+ - ${code('chrome_url_overrides.*')} ${code('chrome_url_overrides/<key>.html')}
202
+ - ${code("content_scripts[n].js/css")} ${code("content_scripts/content-<n>.{js,css}")}
203
+ - ${code('sandbox.pages[]')} ${code('sandbox/page-<n>.html')}
204
+ - ${code("user_scripts.api_script")} ${code("user_scripts/api_script.js")}
205
+ - ${code('icons/*')} ${code('icons/')} (feature-specific icon folders preserved where applicable)
168
206
 
169
207
  Public & Special Folders (Output Behavior)
170
208
  - ${external_pintor_default().underline(code('public/'))} is the web root in output. Authors can use ${code('/foo')}, ${code('/public/foo')}, ${code('public/foo')}, or ${code('./public/foo')} and they all emit as ${code('dist/<browser>/foo')}.
@@ -237,7 +275,7 @@ Source Inspection & Real-Time Monitoring
237
275
  - Example: ${code('extension dev --source=' + arg('https://example.com'))}
238
276
 
239
277
  Non-Destructive Testing in CI
240
- - Prefer ${code('EXTENSION_ENV=development')} to copy local templates and avoid network.
278
+ - Prefer ${code('EXTENSION_AUTHOR_MODE=development')} to copy local templates and avoid network.
241
279
  - Reuse Playwright's Chromium via ${code('--chromium-binary')} path when available.
242
280
  - Set ${code(arg('EXTENSION_AUTO_EXIT_MS'))} and ${code(arg('EXTENSION_FORCE_KILL_MS'))} for non-interactive dev sessions.
243
281
 
@@ -271,7 +309,7 @@ async function check_updates_checkUpdates(packageJson) {
271
309
  try {
272
310
  update = await external_update_check_default()(packageJson);
273
311
  } catch (err) {
274
- if ('development' === process.env.EXTENSION_ENV) console.error(updateFailed(err));
312
+ if ('true' === process.env.EXTENSION_AUTHOR_MODE) console.error(updateFailed(err));
275
313
  }
276
314
  if (update && isStableVersion(update.latest)) console.log(checkUpdates(packageJson, update));
277
315
  }
@@ -412,29 +450,28 @@ class Telemetry {
412
450
  this.track('cli_telemetry_consent', {
413
451
  value: 'implicit_opt_in'
414
452
  });
415
- console.log('[extension] anonymous telemetry helps us improve. Pass --no-telemetry to opt out. Read more in TELEMETRY.md.');
453
+ console.log(`${external_pintor_default().gray('►►► system')} [extension] anonymous telemetry helps us improve. Pass --no-telemetry to opt out. Read more in TELEMETRY.md.`);
416
454
  }
417
455
  }
418
456
  }
419
457
  }
420
458
  function summarizeManifest(manifest) {
421
- var _manifest_action;
422
- const mv = (null == manifest ? void 0 : manifest.manifest_version) === 2 ? 2 : 3;
423
- const permissions = Array.isArray(null == manifest ? void 0 : manifest.permissions) ? manifest.permissions : [];
424
- const optionalPermissions = Array.isArray(null == manifest ? void 0 : manifest.optional_permissions) ? manifest.optional_permissions : [];
425
- const hostPermissions = Array.isArray(null == manifest ? void 0 : manifest.host_permissions) ? manifest.host_permissions : [];
459
+ const mv = manifest?.manifest_version === 2 ? 2 : 3;
460
+ const permissions = Array.isArray(manifest?.permissions) ? manifest.permissions : [];
461
+ const optionalPermissions = Array.isArray(manifest?.optional_permissions) ? manifest.optional_permissions : [];
462
+ const hostPermissions = Array.isArray(manifest?.host_permissions) ? manifest.host_permissions : [];
426
463
  const usesAllUrls = [
427
464
  ...permissions,
428
465
  ...hostPermissions
429
466
  ].includes('<all_urls>');
430
467
  const usesDeclarativeNetRequest = permissions.includes('declarativeNetRequest') || permissions.includes('declarativeNetRequestWithHostAccess');
431
- const background = null == manifest ? void 0 : manifest.background;
468
+ const background = manifest?.background;
432
469
  let backgroundType = 'none';
433
- if (3 === mv && (null == background ? void 0 : background.service_worker)) backgroundType = 'service_worker';
434
- else if (2 === mv && (Array.isArray(null == background ? void 0 : background.scripts) && background.scripts.length > 0 || (null == background ? void 0 : background.page))) backgroundType = 'event_page';
435
- const contentScriptsCount = Array.isArray(null == manifest ? void 0 : manifest.content_scripts) ? manifest.content_scripts.length : 0;
436
- const hasDevtoolsPage = Boolean(null == manifest ? void 0 : manifest.devtools_page);
437
- const hasActionPopup = Boolean(null == manifest ? void 0 : null == (_manifest_action = manifest.action) ? void 0 : _manifest_action.default_popup);
470
+ if (3 === mv && background?.service_worker) backgroundType = 'service_worker';
471
+ else if (2 === mv && (Array.isArray(background?.scripts) && background.scripts.length > 0 || background?.page)) backgroundType = 'event_page';
472
+ const contentScriptsCount = Array.isArray(manifest?.content_scripts) ? manifest.content_scripts.length : 0;
473
+ const hasDevtoolsPage = Boolean(manifest?.devtools_page);
474
+ const hasActionPopup = Boolean(manifest?.action?.default_popup);
438
475
  return {
439
476
  mv,
440
477
  permissions_count: permissions.length,
@@ -452,6 +489,28 @@ function isTelemetryDisabledFromArgs(argv) {
452
489
  return argv.includes('--no-telemetry');
453
490
  }
454
491
  const telemetryDisabled = isTelemetryDisabledFromArgs(process.argv);
492
+ function findManifestJson(projectRoot) {
493
+ const stack = [
494
+ projectRoot
495
+ ];
496
+ while(stack.length > 0){
497
+ const dir = stack.pop();
498
+ if (!dir) continue;
499
+ let entries;
500
+ try {
501
+ entries = external_fs_default().readdirSync(dir, {
502
+ withFileTypes: true
503
+ });
504
+ } catch {
505
+ continue;
506
+ }
507
+ for (const entry of entries){
508
+ if (entry.isFile() && 'manifest.json' === entry.name) return external_path_default().join(dir, entry.name);
509
+ if (entry.isDirectory() && !entry.name.startsWith('.') && 'node_modules' !== entry.name && 'dist' !== entry.name) stack.push(external_path_default().join(dir, entry.name));
510
+ }
511
+ }
512
+ return null;
513
+ }
455
514
  const telemetry_cli_telemetry = new Telemetry({
456
515
  app: 'extension',
457
516
  version: package_namespaceObject.version,
@@ -471,9 +530,8 @@ if (!telemetryDisabled) {
471
530
  telemetry_cli_telemetry.track('cli_boot', {
472
531
  command_guess: invoked
473
532
  });
474
- const cwd = process.cwd();
475
- const manifestPath = external_path_default().join(cwd, 'manifest.json');
476
- if (external_fs_default().existsSync(manifestPath)) {
533
+ const manifestPath = findManifestJson(process.cwd());
534
+ if (manifestPath) {
477
535
  const raw = external_fs_default().readFileSync(manifestPath, 'utf8');
478
536
  const json = JSON.parse(raw);
479
537
  const summary = summarizeManifest(json);
@@ -490,19 +548,17 @@ if (!telemetryDisabled) {
490
548
  process.on('uncaughtException', function(err) {
491
549
  telemetry_cli_telemetry.track('cli_error', {
492
550
  command_guess: invoked,
493
- error_name: String((null == err ? void 0 : err.name) || 'Error').slice(0, 64)
551
+ error_name: String(err?.name || 'Error').slice(0, 64)
494
552
  });
495
553
  });
496
554
  process.on('unhandledRejection', function(reason) {
497
555
  telemetry_cli_telemetry.track('cli_error', {
498
556
  command_guess: invoked,
499
- error_name: String((null == reason ? void 0 : reason.name) || 'PromiseRejection').slice(0, 64)
557
+ error_name: String(reason?.name || 'PromiseRejection').slice(0, 64)
500
558
  });
501
559
  });
502
560
  }
503
- const external_extension_create_namespaceObject = require("extension-create");
504
- const external_node_child_process_namespaceObject = require("node:child_process");
505
- const external_node_url_namespaceObject = require("node:url");
561
+ require("node:url");
506
562
  function parseOptionalBoolean(value) {
507
563
  if (void 0 === value) return true;
508
564
  const normalized = String(value).trim().toLowerCase();
@@ -513,87 +569,6 @@ function parseOptionalBoolean(value) {
513
569
  'off'
514
570
  ].includes(normalized);
515
571
  }
516
- async function requireOrDlx(moduleName, versionHint) {
517
- try {
518
- return await import(moduleName);
519
- } catch {}
520
- const spec = versionHint ? `${moduleName}@${versionHint}` : moduleName;
521
- const cacheDir = external_node_path_default().join(external_node_os_default().tmpdir(), 'extensionjs-cache', spec);
522
- const modulePath = external_node_path_default().join(cacheDir, 'node_modules', moduleName);
523
- const prefer = String(process.env.EXTJS_DLX || '').trim().toLowerCase();
524
- const isWin = 'win32' === process.platform;
525
- const npmCmd = isWin ? 'npm.cmd' : 'npm';
526
- const pnpmCmd = isWin ? 'pnpm.cmd' : 'pnpm';
527
- const bunCmd = isWin ? 'bun.exe' : 'bun';
528
- try {
529
- external_node_fs_default().mkdirSync(cacheDir, {
530
- recursive: true
531
- });
532
- } catch {}
533
- try {
534
- var _pkgJson_exports_, _pkgJson_exports, _pkgJson_exports_1, _pkgJson_exports1;
535
- const pkgJson = JSON.parse(external_node_fs_default().readFileSync(external_node_path_default().join(modulePath, 'package.json'), 'utf8'));
536
- const main = pkgJson.main || (null == (_pkgJson_exports = pkgJson.exports) ? void 0 : null == (_pkgJson_exports_ = _pkgJson_exports['.']) ? void 0 : _pkgJson_exports_.import) || (null == (_pkgJson_exports1 = pkgJson.exports) ? void 0 : null == (_pkgJson_exports_1 = _pkgJson_exports1['.']) ? void 0 : _pkgJson_exports_1.require);
537
- if (main) {
538
- const resolved = (0, external_node_url_namespaceObject.pathToFileURL)(external_node_path_default().join(modulePath, main)).href;
539
- return await import(resolved);
540
- }
541
- } catch {}
542
- if ('pnpm' === prefer) try {
543
- external_node_fs_default().writeFileSync(external_node_path_default().join(cacheDir, 'package.json'), JSON.stringify({
544
- name: 'extensionjs-cache',
545
- private: true
546
- }, null, 2));
547
- } catch {}
548
- let status = 0;
549
- if ('pnpm' === prefer) {
550
- const args = [
551
- 'add',
552
- spec,
553
- '--reporter',
554
- 'silent',
555
- '--no-frozen-lockfile'
556
- ];
557
- status = (0, external_node_child_process_namespaceObject.spawnSync)(pnpmCmd, args, {
558
- cwd: cacheDir,
559
- stdio: 'ignore'
560
- }).status || 0;
561
- } else if ('bun' === prefer) {
562
- const args = [
563
- 'add',
564
- spec
565
- ];
566
- status = (0, external_node_child_process_namespaceObject.spawnSync)(bunCmd, args, {
567
- cwd: cacheDir,
568
- stdio: 'ignore'
569
- }).status || 0;
570
- } else {
571
- const args = [
572
- 'i',
573
- spec,
574
- '--no-fund',
575
- '--no-audit',
576
- '--prefer-online',
577
- '--omit=dev',
578
- '--no-package-lock'
579
- ];
580
- status = (0, external_node_child_process_namespaceObject.spawnSync)(npmCmd, args, {
581
- cwd: cacheDir,
582
- stdio: 'ignore'
583
- }).status || 0;
584
- }
585
- if (0 !== status) throw new Error(`Failed to install ${spec}`);
586
- try {
587
- var _pkgJson_exports_2, _pkgJson_exports2, _pkgJson_exports_3, _pkgJson_exports3;
588
- const pkgJson = JSON.parse(external_node_fs_default().readFileSync(external_node_path_default().join(modulePath, 'package.json'), 'utf8'));
589
- const main = pkgJson.main || (null == (_pkgJson_exports2 = pkgJson.exports) ? void 0 : null == (_pkgJson_exports_2 = _pkgJson_exports2['.']) ? void 0 : _pkgJson_exports_2.import) || (null == (_pkgJson_exports3 = pkgJson.exports) ? void 0 : null == (_pkgJson_exports_3 = _pkgJson_exports3['.']) ? void 0 : _pkgJson_exports_3.require);
590
- if (main) {
591
- const resolved = (0, external_node_url_namespaceObject.pathToFileURL)(external_node_path_default().join(modulePath, main)).href;
592
- return await import(resolved);
593
- }
594
- } catch {}
595
- return await import((0, external_node_url_namespaceObject.pathToFileURL)(external_node_path_default().join(modulePath, 'dist', 'module.js')).href);
596
- }
597
572
  const vendors = (browser)=>{
598
573
  const value = browser ?? 'chromium';
599
574
  return 'all' === value ? [
@@ -618,7 +593,7 @@ function validateVendorsOrExit(vendorsList, onInvalid) {
618
593
  }
619
594
  }
620
595
  function registerCreateCommand(program, telemetry) {
621
- program.command('create').arguments('<project-name|project-path>').usage('create <project-name|project-path> [options]').description('Creates a new extension.').option('-t, --template <template-name>', 'specify a template for the created project').option('--install [boolean]', 'whether or not to install the dependencies after creating the project (disabled by default)', parseOptionalBoolean, false).action(async function(pathOrRemoteUrl, { template, install }) {
596
+ program.command('create').arguments('<project-name|project-path>').usage('create <project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', 'specify a template for the created project').option('--install [boolean]', 'whether or not to install the dependencies after creating the project (enabled by default)', parseOptionalBoolean, true).action(async function(pathOrRemoteUrl, { template, install }) {
622
597
  const startedAt = Date.now();
623
598
  telemetry.track('cli_command_start', {
624
599
  command: 'create',
@@ -626,11 +601,21 @@ function registerCreateCommand(program, telemetry) {
626
601
  install: Boolean(install)
627
602
  });
628
603
  try {
629
- await (0, external_extension_create_namespaceObject.extensionCreate)(pathOrRemoteUrl, {
604
+ const { extensionCreate } = await import("extension-create");
605
+ const { ensureDependencies, preflightOptionalDependenciesForProject } = await import("extension-develop");
606
+ const projectPath = external_path_namespaceObject.isAbsolute(pathOrRemoteUrl) ? pathOrRemoteUrl : external_path_namespaceObject.join(process.cwd(), pathOrRemoteUrl);
607
+ await extensionCreate(pathOrRemoteUrl, {
630
608
  template,
631
609
  install,
632
610
  cliVersion: package_namespaceObject.version
633
611
  });
612
+ if (install) {
613
+ await ensureDependencies(projectPath, {
614
+ skipProjectInstall: true,
615
+ showRunAgainMessage: false
616
+ });
617
+ await preflightOptionalDependenciesForProject(projectPath, 'development');
618
+ }
634
619
  telemetry.track('cli_command_finish', {
635
620
  command: 'create',
636
621
  duration_ms: Date.now() - startedAt,
@@ -648,9 +633,30 @@ function registerCreateCommand(program, telemetry) {
648
633
  }
649
634
  });
650
635
  }
636
+ function normalizeSourceOption(source, startingUrl) {
637
+ if (!source) return;
638
+ const hasExplicitSourceString = 'string' == typeof source && 'true' !== String(source).trim().toLowerCase();
639
+ const hasStartingUrl = 'string' == typeof startingUrl && String(startingUrl).trim().length > 0;
640
+ if (!hasExplicitSourceString) return hasStartingUrl ? String(startingUrl) : 'https://example.com';
641
+ return String(source);
642
+ }
643
+ function parseLogContexts(raw) {
644
+ if (!raw || 0 === String(raw).trim().length) return;
645
+ if ('all' === String(raw).trim().toLowerCase()) return;
646
+ const allowed = [
647
+ 'background',
648
+ 'content',
649
+ 'page',
650
+ 'sidebar',
651
+ 'popup',
652
+ 'options',
653
+ 'devtools'
654
+ ];
655
+ const values = String(raw).split(',').map((s)=>s.trim()).filter((s)=>s.length > 0).filter((c)=>allowed.includes(c));
656
+ return values.length > 0 ? values : void 0;
657
+ }
651
658
  function registerDevCommand(program, telemetry) {
652
- program.command('dev').arguments('[project-path|remote-url]').usage('dev [project-path|remote-url] [options]').description('Starts the development server (development mode)').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--no-open', 'do not open the browser automatically (default: open)').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...devOptions }) {
653
- var _devOptions_polyfill;
659
+ program.command('dev').arguments('[project-path|remote-url]').usage('dev [project-path|remote-url] [options]').description(commandDescriptions.dev).option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--no-open', 'do not open the browser automatically (default: open)').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...devOptions }) {
654
660
  if (devOptions.author || devOptions['authorMode']) {
655
661
  process.env.EXTENSION_AUTHOR_MODE = 'true';
656
662
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -659,7 +665,7 @@ function registerDevCommand(program, telemetry) {
659
665
  telemetry.track('cli_command_start', {
660
666
  command: 'dev',
661
667
  vendors: vendors(browser),
662
- polyfill_used: (null == (_devOptions_polyfill = devOptions.polyfill) ? void 0 : _devOptions_polyfill.toString()) !== 'false',
668
+ polyfill_used: devOptions.polyfill?.toString() !== 'false',
663
669
  log_level: devOptions.logLevel || 'off',
664
670
  log_format: devOptions.logFormat || 'pretty',
665
671
  custom_binary_used: Boolean(devOptions.chromiumBinary || devOptions.geckoBinary)
@@ -668,22 +674,13 @@ function registerDevCommand(program, telemetry) {
668
674
  validateVendorsOrExit(list, (invalid, supported)=>{
669
675
  console.error(unsupportedBrowserFlag(invalid, supported));
670
676
  });
671
- if (devOptions.source) {
672
- const hasExplicitSourceString = 'string' == typeof devOptions.source && 'true' !== String(devOptions.source).trim().toLowerCase();
673
- const hasStartingUrl = 'string' == typeof devOptions.startingUrl && String(devOptions.startingUrl).trim().length > 0;
674
- if (!hasExplicitSourceString) devOptions.source = hasStartingUrl ? String(devOptions.startingUrl) : 'https://example.com';
677
+ const normalizedSource = normalizeSourceOption(devOptions.source, devOptions.startingUrl);
678
+ if (normalizedSource) {
679
+ devOptions.source = normalizedSource;
675
680
  devOptions.watchSource = true;
676
681
  }
677
- const versionExact = String(package_namespaceObject.version);
678
- const major = String(package_namespaceObject.version).split('.')[0] || '2';
679
- let extensionDev;
680
- try {
681
- ({ extensionDev } = await requireOrDlx('extension-develop', versionExact));
682
- } catch {
683
- ({ extensionDev } = await requireOrDlx('extension-develop', major));
684
- }
682
+ const { extensionDev } = await import("extension-develop");
685
683
  for (const vendor of list){
686
- var _devOptions_polyfill1;
687
684
  const vendorStart = Date.now();
688
685
  telemetry.track('cli_vendor_start', {
689
686
  command: 'dev',
@@ -697,28 +694,13 @@ function registerDevCommand(program, telemetry) {
697
694
  browser: vendor,
698
695
  chromiumBinary: devOptions.chromiumBinary,
699
696
  geckoBinary: devOptions.geckoBinary,
700
- polyfill: (null == (_devOptions_polyfill1 = devOptions.polyfill) ? void 0 : _devOptions_polyfill1.toString()) !== 'false',
697
+ polyfill: devOptions.polyfill?.toString() !== 'false',
701
698
  open: devOptions.open,
702
699
  startingUrl: devOptions.startingUrl,
703
700
  source: devOptions.source,
704
701
  watchSource: devOptions.watchSource,
705
702
  logLevel: logsOption || devOptions.logLevel || 'off',
706
- logContexts: (()=>{
707
- const raw = logContextOption || devOptions.logContexts;
708
- if (!raw || 0 === String(raw).trim().length) return;
709
- if ('all' === String(raw).trim().toLowerCase()) return;
710
- const allowed = [
711
- 'background',
712
- 'content',
713
- 'page',
714
- 'sidebar',
715
- 'popup',
716
- 'options',
717
- 'devtools'
718
- ];
719
- const values = String(raw).split(',').map((s)=>s.trim()).filter((s)=>s.length > 0).filter((c)=>allowed.includes(c));
720
- return values.length ? values : void 0;
721
- })(),
703
+ logContexts: parseLogContexts(logContextOption),
722
704
  logFormat: devOptions.logFormat || 'pretty',
723
705
  logTimestamps: false !== devOptions.logTimestamps,
724
706
  logColor: false !== devOptions.logColor,
@@ -741,9 +723,8 @@ function registerDevCommand(program, telemetry) {
741
723
  });
742
724
  }
743
725
  function registerStartCommand(program, telemetry) {
744
- program.command('start').arguments('[project-path|remote-url]').usage('start [project-path|remote-url] [options]').description('Starts the development server (production mode)').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...startOptions }) {
745
- var _startOptions_polyfill;
746
- if (startOptions.author || startOptions['authorMode']) {
726
+ program.command('start').arguments('[project-path|remote-url]').usage('start [project-path|remote-url] [options]').description(commandDescriptions.start).option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...startOptions }) {
727
+ if (startOptions.author || startOptions.authorMode) {
747
728
  process.env.EXTENSION_AUTHOR_MODE = 'true';
748
729
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
749
730
  }
@@ -751,14 +732,13 @@ function registerStartCommand(program, telemetry) {
751
732
  telemetry.track('cli_command_start', {
752
733
  command: 'start',
753
734
  vendors: vendors(browser),
754
- polyfill_used: (null == (_startOptions_polyfill = startOptions.polyfill) ? void 0 : _startOptions_polyfill.toString()) !== 'false'
735
+ polyfill_used: startOptions.polyfill?.toString() !== 'false'
755
736
  });
756
737
  const list = vendors(browser);
757
738
  validateVendorsOrExit(list, (invalid, supported)=>{
758
739
  console.error(unsupportedBrowserFlag(invalid, supported));
759
740
  });
760
- const major = String(package_namespaceObject.version).split('.')[0] || '2';
761
- const { extensionStart } = await requireOrDlx('extension-develop', major);
741
+ const { extensionStart } = await import("extension-develop");
762
742
  for (const vendor of list){
763
743
  const vendorStart = Date.now();
764
744
  telemetry.track('cli_vendor_start', {
@@ -767,22 +747,7 @@ function registerStartCommand(program, telemetry) {
767
747
  });
768
748
  const logsOption = startOptions.logs;
769
749
  const logContextOption = startOptions.logContext;
770
- const logContexts = (()=>{
771
- const raw = logContextOption || startOptions.logContexts;
772
- if (!raw || 0 === String(raw).trim().length) return;
773
- if ('all' === String(raw).trim().toLowerCase()) return;
774
- const allowed = [
775
- 'background',
776
- 'content',
777
- 'page',
778
- 'sidebar',
779
- 'popup',
780
- 'options',
781
- 'devtools'
782
- ];
783
- const values = String(raw).split(',').map((s)=>s.trim()).filter((s)=>s.length > 0).filter((c)=>allowed.includes(c));
784
- return values.length ? values : void 0;
785
- })();
750
+ const logContexts = parseLogContexts(logContextOption);
786
751
  await extensionStart(pathOrRemoteUrl, {
787
752
  mode: 'production',
788
753
  profile: startOptions.profile,
@@ -816,7 +781,7 @@ function registerStartCommand(program, telemetry) {
816
781
  });
817
782
  }
818
783
  function registerPreviewCommand(program, telemetry) {
819
- program.command('preview').arguments('[project-name]').usage('preview [path-to-remote-extension] [options]').description('Preview the extension in production mode').option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...previewOptions }) {
784
+ program.command('preview').arguments('[project-name]').usage('preview [path-to-remote-extension] [options]').description(commandDescriptions.preview).option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). Use `all` to include all contexts (default)').option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...previewOptions }) {
820
785
  if (previewOptions.author || previewOptions['authorMode']) {
821
786
  process.env.EXTENSION_AUTHOR_MODE = 'true';
822
787
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -834,8 +799,7 @@ function registerPreviewCommand(program, telemetry) {
834
799
  const isRemote = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
835
800
  if (isRemote) process.env.EXTJS_LIGHT = '1';
836
801
  }
837
- const major = String(package_namespaceObject.version).split('.')[0] || '2';
838
- const { extensionPreview } = await requireOrDlx('extension-develop', major);
802
+ const { extensionPreview } = await import("extension-develop");
839
803
  for (const vendor of list){
840
804
  const vendorStart = Date.now();
841
805
  telemetry.track('cli_vendor_start', {
@@ -844,22 +808,7 @@ function registerPreviewCommand(program, telemetry) {
844
808
  });
845
809
  const logsOption = previewOptions.logs;
846
810
  const logContextOption = previewOptions.logContext;
847
- const logContexts = (()=>{
848
- const raw = logContextOption || previewOptions.logContexts;
849
- if (!raw || 0 === String(raw).trim().length) return;
850
- if ('all' === String(raw).trim().toLowerCase()) return;
851
- const allowed = [
852
- 'background',
853
- 'content',
854
- 'page',
855
- 'sidebar',
856
- 'popup',
857
- 'options',
858
- 'devtools'
859
- ];
860
- const values = String(raw).split(',').map((s)=>s.trim()).filter((s)=>s.length > 0).filter((c)=>allowed.includes(c));
861
- return values.length ? values : void 0;
862
- })();
811
+ const logContexts = parseLogContexts(logContextOption);
863
812
  await extensionPreview(pathOrRemoteUrl, {
864
813
  mode: 'production',
865
814
  profile: previewOptions.profile,
@@ -893,7 +842,7 @@ function registerPreviewCommand(program, telemetry) {
893
842
  });
894
843
  }
895
844
  function registerBuildCommand(program, telemetry) {
896
- program.command('build').arguments('[project-name]').usage('build [path-to-remote-extension] [options]').description('Builds the extension for production').option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`').option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`').option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'whether or not to open the browser automatically. Defaults to `false`').option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...buildOptions }) {
845
+ program.command('build').arguments('[project-name]').usage('build [path-to-remote-extension] [options]').description(commandDescriptions.build).option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`').option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`').option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'whether or not to open the browser automatically. Defaults to `false`').option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...buildOptions }) {
897
846
  if (buildOptions.author || buildOptions['authorMode']) {
898
847
  process.env.EXTENSION_AUTHOR_MODE = 'true';
899
848
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -910,8 +859,7 @@ function registerBuildCommand(program, telemetry) {
910
859
  validateVendorsOrExit(list, (invalid, supported)=>{
911
860
  console.error(unsupportedBrowserFlag(invalid, supported));
912
861
  });
913
- const major = String(package_namespaceObject.version).split('.')[0] || '2';
914
- const { extensionBuild } = await requireOrDlx('extension-develop', major);
862
+ const { extensionBuild } = await import("extension-develop");
915
863
  for (const vendor of list){
916
864
  const vendorStart = Date.now();
917
865
  telemetry.track('cli_vendor_start', {
@@ -959,8 +907,11 @@ if (process.argv.length <= 2) {
959
907
  extensionJs.outputHelp();
960
908
  process.exit(0);
961
909
  }
962
- extensionJs.parse();
963
- for(var __webpack_i__ in __webpack_exports__)exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
910
+ extensionJs.parseAsync().catch((err)=>{
911
+ console.error(unhandledError(err));
912
+ process.exit(1);
913
+ });
914
+ for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
964
915
  Object.defineProperty(exports, '__esModule', {
965
916
  value: true
966
917
  });
@@ -0,0 +1,2 @@
1
+ export declare function normalizeSourceOption(source: boolean | string | undefined, startingUrl?: string): string | undefined;
2
+ export declare function parseLogContexts(raw: string | undefined): Array<'background' | 'content' | 'page' | 'sidebar' | 'popup' | 'options' | 'devtools'> | undefined;
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
+ export declare function resolveModuleEntry(modulePath: string, pkgJson: any): string | undefined;
1
2
  export type Browser = 'chrome' | 'edge' | 'firefox' | 'chromium' | 'chromium-based' | 'gecko-based' | 'firefox-based';
2
3
  export declare function parseOptionalBoolean(value?: string): boolean;
3
- export declare function requireOrDlx(moduleName: string, versionHint?: string): Promise<any>;
4
4
  export declare const vendors: (browser?: Browser | "all") => string[];
5
5
  export declare function validateVendorsOrExit(vendorsList: string[], onInvalid: (invalid: string, supported: string[]) => void): void;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "license": "MIT",
3
3
  "repository": {
4
4
  "type": "git",
5
- "url": "https://github.com/extension-js/extension.js",
5
+ "url": "git+https://github.com/extension-js/extension.js.git",
6
6
  "directory": "programs/cli"
7
7
  },
8
8
  "engines": {
@@ -35,9 +35,12 @@
35
35
  "extension": "./dist/cli.js"
36
36
  },
37
37
  "name": "extension",
38
- "version": "3.0.0-next.9",
38
+ "version": "3.1.0-next.10",
39
39
  "description": "Create cross-browser extensions with no build configuration.",
40
40
  "homepage": "https://extension.js.org/",
41
+ "bugs": {
42
+ "url": "https://github.com/extension-js/extension.js/issues"
43
+ },
41
44
  "author": {
42
45
  "name": "Cezar Augusto",
43
46
  "email": "boss@cezaraugusto.net",
@@ -45,12 +48,10 @@
45
48
  },
46
49
  "publishConfig": {
47
50
  "access": "public",
48
- "registry": "https://registry.npmjs.org",
49
- "tag": "latest"
51
+ "registry": "https://registry.npmjs.org"
50
52
  },
51
53
  "scripts": {
52
- "prepare": "rslib build >/dev/null 2>&1 || true",
53
- "postinstall": "rslib build >/dev/null 2>&1 || true",
54
+ "prepublishOnly": "pnpm run compile",
54
55
  "compile": "rslib build",
55
56
  "watch": "rslib build --watch",
56
57
  "test": "vitest run"
@@ -87,25 +88,26 @@
87
88
  "cli"
88
89
  ],
89
90
  "dependencies": {
90
- "commander": "^12.1.0",
91
- "extension-create": "^2.2.0",
91
+ "extension-create": "^3.1.0-next.10",
92
+ "extension-develop": "^3.1.0-next.10",
93
+ "commander": "^14.0.2",
92
94
  "pintor": "0.3.0",
93
- "semver": "^7.6.3",
95
+ "semver": "^7.7.3",
94
96
  "update-check": "^1.5.4"
95
97
  },
96
98
  "devDependencies": {
97
- "@rslib/core": "^0.6.9",
98
- "@types/chrome": "^0.0.287",
99
- "@types/node": "^22.10.1",
100
- "@types/react": "^19.0.1",
101
- "@types/react-dom": "^19.0.1",
102
- "@types/webextension-polyfill": "0.12.3",
99
+ "@rslib/core": "^0.19.2",
100
+ "@types/chrome": "^0.1.33",
101
+ "@types/node": "^25.0.9",
102
+ "@types/react": "^19.2.8",
103
+ "@types/react-dom": "^19.2.3",
104
+ "@types/webextension-polyfill": "0.12.4",
103
105
  "@types/mock-fs": "^4.13.4",
104
- "@types/semver": "^7.5.8",
105
- "mock-fs": "^5.4.1",
106
+ "@types/semver": "^7.7.1",
107
+ "mock-fs": "^5.5.0",
106
108
  "webextension-polyfill": "^0.12.0",
107
109
  "tsconfig": "*",
108
- "typescript": "5.7.2",
109
- "vitest": "^3.2.4"
110
+ "typescript": "5.9.3",
111
+ "vitest": "^4.0.17"
110
112
  }
111
113
  }
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  type CSSContentData = Readonly<Record<string, string>>
2
10
 
3
11
  declare module '*.css' {
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  type CSSModuleData = Readonly<Record<string, string>>
2
10
 
3
11
  declare module '*.module.css' {
@@ -0,0 +1,24 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
9
+ declare module 'extension-create' {
10
+ // These types mirror the public surface of programs/create/module.ts,
11
+ // but are intentionally loose on the CLI side. The real, precise types
12
+ // come from the installed `extension-create` package when consumers
13
+ // depend on it directly.
14
+ export interface CreateOptions {
15
+ template: string
16
+ install?: boolean
17
+ cliVersion?: string
18
+ }
19
+
20
+ export function extensionCreate(
21
+ projectNameInput: string | undefined,
22
+ options: CreateOptions
23
+ ): Promise<void>
24
+ }
@@ -0,0 +1,103 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
9
+ declare module 'extension-develop' {
10
+ // These types mirror the public surface of programs/develop/module.ts,
11
+ // but are intentionally loose on the CLI side. The real, precise types
12
+ // come from the installed `extension-develop` package when consumers
13
+ // depend on it directly.
14
+
15
+ export type ExtensionBrowser =
16
+ | 'chrome'
17
+ | 'edge'
18
+ | 'firefox'
19
+ | 'chromium'
20
+ | 'chromium-based'
21
+ | 'gecko-based'
22
+ | 'firefox-based'
23
+
24
+ export type ExtensionMode = 'development' | 'production'
25
+
26
+ export interface BuildOptions {
27
+ browser?: ExtensionBrowser | 'all'
28
+ polyfill?: boolean
29
+ zip?: boolean
30
+ zipSource?: boolean
31
+ zipFilename?: string
32
+ silent?: boolean
33
+ }
34
+
35
+ export interface DevOptions {
36
+ browser?: ExtensionBrowser | 'all'
37
+ profile?: string | boolean
38
+ persistProfile?: boolean
39
+ chromiumBinary?: string
40
+ geckoBinary?: string
41
+ polyfill?: boolean | string
42
+ open?: boolean
43
+ startingUrl?: string
44
+ source?: boolean | string
45
+ watchSource?: boolean
46
+ logLevel?: string
47
+ logFormat?: 'pretty' | 'json'
48
+ logTimestamps?: boolean
49
+ logColor?: boolean
50
+ logUrl?: string
51
+ logTab?: string | number
52
+ }
53
+
54
+ export interface PreviewOptions extends DevOptions {}
55
+
56
+ export interface StartOptions extends DevOptions {}
57
+
58
+ export interface FileConfig {
59
+ [key: string]: unknown
60
+ }
61
+
62
+ export interface Manifest {
63
+ [key: string]: unknown
64
+ }
65
+
66
+ export function extensionBuild(
67
+ pathOrRemoteUrl: string,
68
+ options: BuildOptions
69
+ ): Promise<any>
70
+
71
+ export function extensionDev(
72
+ pathOrRemoteUrl: string,
73
+ options: DevOptions
74
+ ): Promise<any>
75
+
76
+ export function extensionStart(
77
+ pathOrRemoteUrl: string,
78
+ options: StartOptions
79
+ ): Promise<any>
80
+
81
+ export function extensionPreview(
82
+ pathOrRemoteUrl: string,
83
+ options: PreviewOptions
84
+ ): Promise<any>
85
+
86
+ export function ensureDependencies(
87
+ projectPath?: string,
88
+ opts?: {
89
+ skipProjectInstall?: boolean
90
+ exitOnInstall?: boolean
91
+ showRunAgainMessage?: boolean
92
+ }
93
+ ): Promise<{
94
+ installed: boolean
95
+ installedBuild: boolean
96
+ installedUser: boolean
97
+ }>
98
+
99
+ export function preflightOptionalDependenciesForProject(
100
+ pathOrRemoteUrl: string,
101
+ mode?: ExtensionMode
102
+ ): Promise<void>
103
+ }
package/types/images.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  declare module '*.png' {
2
10
  const content: string
3
11
 
package/types/index.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  /// <reference types="node" />
2
10
  /// <reference types="chrome" />
3
11
  /// <reference types="./js-frameworks.d.ts" />
@@ -20,8 +28,7 @@ interface ExtensionEnv {
20
28
  EXTENSION_PUBLIC_BROWSER: ExtensionBrowser
21
29
  EXTENSION_PUBLIC_MODE: ExtensionMode
22
30
  EXTENSION_PUBLIC_DESCRIPTION_TEXT: string
23
- EXTENSION_PUBLIC_OPENAI_API_KEY: string
24
- EXTENSION_ENV: ExtensionMode
31
+ EXTENSION_PUBLIC_LLM_API_KEY: string
25
32
  EXTENSION_AUTHOR_MODE: string
26
33
  EXTENSION_PUBLIC_AUTHOR_MODE: string
27
34
  }
package/types/index.ts CHANGED
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  /// <reference types="node" />
2
10
  /// <reference types="react" />
3
11
  /// <reference types="react-dom" />
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  /// <reference types="react" />
2
10
  /// <reference types="react-dom" />
3
11
  /// <reference types="svelte" />
@@ -1,3 +1,11 @@
1
+ // ██████╗██╗ ██╗
2
+ // ██╔════╝██║ ██║
3
+ // ██║ ██║ ██║
4
+ // ██║ ██║ ██║
5
+ // ╚██████╗███████╗██║
6
+ // ╚═════╝╚══════╝╚═╝
7
+ // MIT License (c) 2020–present Cezar Augusto & the Extension.js authors — presence implies inheritance
8
+
1
9
  /// <reference types="webextension-polyfill" />
2
10
 
3
11
  declare global {