extension-create 2.2.1 → 3.1.0-next.5

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,29 +1,24 @@
1
1
  [npm-version-image]: https://img.shields.io/npm/v/extension-create.svg?color=0971fe
2
2
  [npm-version-url]: https://www.npmjs.com/package/extension-create
3
- [downloads-image]: https://img.shields.io/npm/dm/extension-create.svg?color=2ecc40
4
- [downloads-url]: https://npmjs.org/package/extension-create
5
- [empowering-image]: https://img.shields.io/badge/Empowering-Extension.js-0971fe
6
- [empowering-url]: https://extension.js.org
3
+ [npm-downloads-image]: https://img.shields.io/npm/dm/extension-create.svg?color=0971fe
4
+ [npm-downloads-url]: https://www.npmjs.com/package/extension-create
5
+ [action-image]: https://github.com/extension-js/create/actions/workflows/ci.yml/badge.svg?branch=main
6
+ [action-url]: https://github.com/extension-js/create/actions/workflows/ci.yml
7
7
 
8
- [![Empowering][empowering-image]][empowering-url] [![Version][npm-version-image]][npm-version-url] [![Downloads][downloads-image]][downloads-url]
8
+ [![Version][npm-version-image]][npm-version-url] [![Downloads][npm-downloads-image]][npm-downloads-url] [![CI][action-image]][action-url]
9
9
 
10
10
  # extension-create
11
11
 
12
- The standalone extension creation engine from [Extension.js](https://github.com/extension-js/extension.js). It provides an intuitive API for programmatically creating browser extensions with support for multiple frameworks and templates.
12
+ The standalone extension creation engine for Extension.js.
13
+ Use it to scaffold a new extension project from a template.
13
14
 
14
- ## Installation
15
-
16
- Install the package using your preferred package manager:
15
+ ## Install
17
16
 
18
17
  ```bash
19
18
  npm install extension-create
20
- # or
21
- pnpm add extension-create
22
- # or
23
- yarn add extension-create
24
19
  ```
25
20
 
26
- ## Quick Start
21
+ ## Usage
27
22
 
28
23
  Create a new extension with a single function call:
29
24
 
@@ -42,7 +37,7 @@ await extensionCreate('my-react-extension', {
42
37
  })
43
38
  ```
44
39
 
45
- ## API Reference
40
+ ## API reference
46
41
 
47
42
  ### `extensionCreate(projectName, options)`
48
43
 
@@ -58,7 +53,7 @@ Creates a new extension project with the specified configuration.
58
53
 
59
54
  ## Templates
60
55
 
61
- Templates are sourced from the public Examples repository. See the catalog at `https://github.com/extension-js/examples` and reference templates by name, e.g. `content`, `content-react`, `content-vue`, etc.
56
+ Templates are sourced from the public examples repository. Browse the catalog in the [Extension.js examples](https://github.com/extension-js/examples) and reference templates by name (for example, `content`, `content-react`, `content-vue`).
62
57
 
63
58
  ## License
64
59
 
@@ -0,0 +1 @@
1
+ export declare function findManifestJsonPath(projectPath: string): Promise<string>;
@@ -5,7 +5,7 @@ declare namespace NodeJS {
5
5
  EXTENSION_PUBLIC_BROWSER: 'chrome' | 'edge' | 'firefox' | 'chromium-based' | 'gecko-based';
6
6
  EXTENSION_PUBLIC_MODE: 'development' | 'production';
7
7
  EXTENSION_PUBLIC_DESCRIPTION_TEXT: string;
8
- EXTENSION_PUBLIC_OPENAI_API_KEY: string;
8
+ EXTENSION_PUBLIC_LLM_API_KEY: string;
9
9
  EXTENSION_ENV: 'development' | 'production';
10
10
  }
11
11
  }
package/dist/module.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
3
- return 'undefined' == typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
3
+ return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
4
4
  }();
5
5
  var __webpack_require__ = {};
6
6
  (()=>{
@@ -25,7 +25,7 @@ var __webpack_require__ = {};
25
25
  })();
26
26
  (()=>{
27
27
  __webpack_require__.r = (exports1)=>{
28
- if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
28
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
29
29
  value: 'Module'
30
30
  });
31
31
  Object.defineProperty(exports1, '__esModule', {
@@ -45,30 +45,30 @@ var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pinto
45
45
  const external_package_manager_detector_namespaceObject = require("package-manager-detector");
46
46
  function destinationNotWriteable(workingDir) {
47
47
  const workingDirFolder = external_path_namespaceObject.basename(workingDir);
48
- return `${external_pintor_default().red('ERROR')} Failed to write in the destination directory.\n${external_pintor_default().red('Path is not writable. Ensure you have write permissions for this folder.')}\n${external_pintor_default().red('NOT WRITEABLE')} ${external_pintor_default().underline(workingDirFolder)}`;
48
+ return `${external_pintor_default().red('Error')} Couldn't write to the destination directory.\n${external_pintor_default().red('Next step: choose a writable path or update folder permissions.')}\n${external_pintor_default().red('Path')} ${external_pintor_default().underline(workingDirFolder)}`;
49
49
  }
50
50
  async function directoryHasConflicts(projectPath, conflictingFiles) {
51
51
  const projectName = external_path_namespaceObject.basename(projectPath);
52
- let message = `Conflict! Path to ${external_pintor_default().blue(projectName)} includes conflicting files.\n\n`;
52
+ let message = `Conflicting files found in ${external_pintor_default().blue(projectName)}.\n\n`;
53
53
  for (const file of conflictingFiles){
54
54
  const stats = await external_fs_namespaceObject.promises.lstat(external_path_namespaceObject.join(projectPath, file));
55
55
  message += stats.isDirectory() ? ` ${external_pintor_default().yellow('-')} ${external_pintor_default().yellow(file)}\n` : ` ${external_pintor_default().yellow('-')} ${external_pintor_default().yellow(file)}\n`;
56
56
  }
57
- message += `\n${external_pintor_default().red('You need to either rename/remove the files listed above, or choose a new directory name for your extension.')}\n\nPath to conflicting directory: ${external_pintor_default().underline(projectPath)}`;
57
+ message += `\n${external_pintor_default().red('Next step: remove or rename the files above, or choose a different directory name.')}\n\nPath: ${external_pintor_default().underline(projectPath)}`;
58
58
  return message;
59
59
  }
60
60
  function noProjectName() {
61
- return `${external_pintor_default().red('ERROR')} You need to provide an extension name to create one. See ${external_pintor_default().blue('--help')} for command info.`;
61
+ return `${external_pintor_default().red('Error')} Project name is required.\nNext step: provide a project name (for example, ${external_pintor_default().blue('my-extension')}) or run ${external_pintor_default().blue('--help')} for usage.`;
62
62
  }
63
63
  function noUrlAllowed() {
64
- return `${external_pintor_default().red('ERROR')} URLs are not allowed as a project path. Either write a name or a path to a local folder.`;
64
+ return `${external_pintor_default().red('Error')} URLs are not allowed as a project path.\nNext step: provide a project name or a local directory path.`;
65
65
  }
66
66
  async function successfullInstall(projectPath, projectName) {
67
67
  const relativePath = external_path_namespaceObject.relative(process.cwd(), projectPath);
68
68
  const pm = await (0, external_package_manager_detector_namespaceObject.detect)();
69
69
  let command = 'npm run';
70
70
  let installCmd = 'npm install';
71
- switch(null == pm ? void 0 : pm.name){
71
+ switch(pm?.name){
72
72
  case 'yarn':
73
73
  command = 'yarn dev';
74
74
  installCmd = 'yarn';
@@ -87,86 +87,86 @@ async function successfullInstall(projectPath, projectName) {
87
87
  installCmd = 'pnpm install';
88
88
  }
89
89
  }
90
- return `\u{1F9E9} - ${external_pintor_default().green('Success!')} Extension ${external_pintor_default().blue(projectName)} created.\n\nTo get started developing your extension, do the following:\n\n 1. ${external_pintor_default().blue('cd')} ${external_pintor_default().underline(relativePath)}\n 2. ${external_pintor_default().blue(installCmd)} to install dependencies\n 3. ${external_pintor_default().blue(command)} to open a new browser instance with your extension loaded\n\n${external_pintor_default().green('You are ready')}. Time to hack on your extension!\n`;
90
+ return `${external_pintor_default().green('Created')} ${external_pintor_default().blue(projectName)}\n\nNext steps:\n\n 1. ${external_pintor_default().blue('cd')} ${external_pintor_default().underline(relativePath)}\n 2. ${external_pintor_default().blue(installCmd)}\n 3. ${external_pintor_default().blue(command)} (runs a fresh browser profile with your extension loaded)\n`;
91
91
  }
92
92
  function startingNewExtension(projectName) {
93
- return `\u{1F423} - Starting a new browser extension named ${external_pintor_default().blue(projectName)}...`;
93
+ return `Creating ${external_pintor_default().blue(projectName)}...`;
94
94
  }
95
95
  function checkingIfPathIsWriteable() {
96
- return `\u{1F91E} - Checking if destination path is writeable...`;
96
+ return 'Checking if the destination path is writable...';
97
97
  }
98
98
  function scanningPossiblyConflictingFiles() {
99
- return "\uD83D\uDD0E - Scanning for potential conflicting files...";
99
+ return 'Scanning for conflicting files...';
100
100
  }
101
101
  function createDirectoryError(projectName, error) {
102
- return `${external_pintor_default().red('ERROR')} Can't create directory ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}`;
102
+ return `${external_pintor_default().red('Error')} Couldn't create directory ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: check the path and permissions, then try again.')}`;
103
103
  }
104
104
  function writingTypeDefinitions(projectName) {
105
- return `\u{1F537} - Writing type definitions for ${external_pintor_default().blue(projectName)}...`;
105
+ return `Writing type definitions for ${external_pintor_default().blue(projectName)}...`;
106
106
  }
107
107
  function writingTypeDefinitionsError(error) {
108
- return `${external_pintor_default().red('ERROR')} Failed to write the extension type definition.\n${external_pintor_default().red(String(error))}`;
108
+ return `${external_pintor_default().red('Error')} Couldn't write the extension type definitions.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: check file permissions, then try again.')}`;
109
109
  }
110
110
  function installingFromTemplate(projectName, templateName) {
111
- if ('init' === templateName) return `\u{1F9F0} - Installing ${external_pintor_default().blue(projectName)}...`;
112
- return `\u{1F9F0} - Installing ${external_pintor_default().blue(projectName)} from template ${external_pintor_default().yellow(templateName)}...`;
111
+ if ('init' === templateName) return `Installing ${external_pintor_default().blue(projectName)}...`;
112
+ return `Installing ${external_pintor_default().blue(projectName)} from template ${external_pintor_default().yellow(templateName)}...`;
113
113
  }
114
114
  function installingFromTemplateError(projectName, template, error) {
115
- return `${external_pintor_default().red('ERROR')} Can't find template ${external_pintor_default().yellow(template)} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}`;
115
+ return `${external_pintor_default().red('Error')} Couldn't find template ${external_pintor_default().yellow(template)} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: choose a valid template name or URL.')}`;
116
116
  }
117
117
  function initializingGitForRepository(projectName) {
118
- return `\u{1F332} - Initializing git repository for ${external_pintor_default().blue(projectName)}...`;
118
+ return `Initializing git repository for ${external_pintor_default().blue(projectName)}...`;
119
119
  }
120
120
  function initializingGitForRepositoryFailed(gitCommand, gitArgs, code) {
121
- return `${external_pintor_default().red('ERROR')} Command ${external_pintor_default().yellow(gitCommand)} ${external_pintor_default().yellow(gitArgs.join(' '))} failed.\n${external_pintor_default().red(`exit code ${external_pintor_default().yellow(String(code))}`)}`;
121
+ return `${external_pintor_default().red('Error')} Command ${external_pintor_default().yellow(gitCommand)} ${external_pintor_default().yellow(gitArgs.join(' '))} failed.\n${external_pintor_default().red(`Exit code: ${external_pintor_default().yellow(String(code))}`)}\n${external_pintor_default().red('Next step: run the command manually to inspect the error.')}`;
122
122
  }
123
123
  function initializingGitForRepositoryProcessError(projectName, error) {
124
- return `${external_pintor_default().red('ERROR')} Child process error: Can't initialize ${external_pintor_default().yellow('git')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String((null == error ? void 0 : error.message) || error))}`;
124
+ return `${external_pintor_default().red('Error')} Child process failed while initializing ${external_pintor_default().yellow('git')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error?.message || error))}\n${external_pintor_default().red('Next step: retry initialization or create the repository manually.')}`;
125
125
  }
126
126
  function initializingGitForRepositoryError(projectName, error) {
127
- return `${external_pintor_default().red('ERROR')} Can't initialize ${external_pintor_default().yellow('git')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String((null == error ? void 0 : error.message) || error))}`;
127
+ return `${external_pintor_default().red('Error')} Couldn't initialize ${external_pintor_default().yellow('git')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error?.message || error))}\n${external_pintor_default().red('Next step: retry initialization or create the repository manually.')}`;
128
128
  }
129
129
  function installingDependencies() {
130
- return "\uD83D\uDEE0 - Installing dependencies... (takes a moment)";
130
+ return 'Installing dependencies (this may take a moment)...';
131
131
  }
132
132
  function installingDependenciesFailed(gitCommand, gitArgs, code) {
133
- return `${external_pintor_default().red('ERROR')} Command ${external_pintor_default().yellow(gitCommand)} ${external_pintor_default().yellow(gitArgs.join(' '))} failed.\n${external_pintor_default().red(`exit code ${external_pintor_default().yellow(String(code))}`)}`;
133
+ return `${external_pintor_default().red('Error')} Command ${external_pintor_default().yellow(gitCommand)} ${external_pintor_default().yellow(gitArgs.join(' '))} failed.\n${external_pintor_default().red(`Exit code: ${external_pintor_default().yellow(String(code))}`)}\n${external_pintor_default().red('Next step: run the command manually to inspect the error.')}`;
134
134
  }
135
135
  function installingDependenciesProcessError(projectName, error) {
136
- return `${external_pintor_default().red('ERROR')} Child process error: Can't install dependencies for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}`;
136
+ return `${external_pintor_default().red('Error')} Child process failed while installing dependencies for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: run the install command manually to inspect the error.')}`;
137
137
  }
138
138
  function cantInstallDependencies(projectName, error) {
139
- return `${external_pintor_default().red('ERROR')} Can't install dependencies for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String((null == error ? void 0 : error.message) || error))}`;
139
+ return `${external_pintor_default().red('Error')} Couldn't install dependencies for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error?.message || error))}\n${external_pintor_default().red('Next step: check your package manager settings, then try again.')}`;
140
140
  }
141
141
  function writingPackageJsonMetadata() {
142
- return `\u{1F4DD} - Writing ${external_pintor_default().yellow('package.json')} metadata...`;
142
+ return `Writing ${external_pintor_default().yellow('package.json')}...`;
143
143
  }
144
144
  function writingPackageJsonMetadataError(projectName, error) {
145
- return `${external_pintor_default().red('ERROR')} Can't write ${external_pintor_default().yellow('package.json')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}`;
145
+ return `${external_pintor_default().red('Error')} Couldn't write ${external_pintor_default().yellow('package.json')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: check file permissions, then try again.')}`;
146
146
  }
147
147
  function writingManifestJsonMetadata() {
148
- return `\u{1F4DC} - Writing ${external_pintor_default().yellow('manifest.json')} metadata...`;
148
+ return `Writing ${external_pintor_default().yellow('manifest.json')}...`;
149
149
  }
150
150
  function writingManifestJsonMetadataError(projectName, error) {
151
- return `${external_pintor_default().red('ERROR')} Can't write ${external_pintor_default().yellow('manifest.json')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}`;
151
+ return `${external_pintor_default().red('Error')} Couldn't write ${external_pintor_default().yellow('manifest.json')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: check file permissions, then try again.')}`;
152
152
  }
153
153
  function writingReadmeMetaData() {
154
- return `\u{1F4C4} - Writing ${external_pintor_default().yellow('README.md')} metadata...`;
154
+ return `Writing ${external_pintor_default().yellow('README.md')}...`;
155
155
  }
156
156
  function writingGitIgnore() {
157
- return `\u{1F648} - Writing ${external_pintor_default().yellow('.gitignore')} lines...`;
157
+ return `Writing ${external_pintor_default().yellow('.gitignore')}...`;
158
158
  }
159
159
  function writingReadmeMetaDataEError(projectName, error) {
160
- return `${external_pintor_default().red('ERROR')} Can't write the ${external_pintor_default().yellow('README.md')} file for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}`;
160
+ return `${external_pintor_default().red('Error')} Couldn't write ${external_pintor_default().yellow('README.md')} for ${external_pintor_default().blue(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: check file permissions, then try again.')}`;
161
161
  }
162
162
  function folderExists(projectName) {
163
- return `\u{1F91D} - Ensuring ${external_pintor_default().blue(projectName)} folder exists...`;
163
+ return `Ensuring ${external_pintor_default().blue(projectName)} exists...`;
164
164
  }
165
165
  function writingDirectoryError(error) {
166
- return `${external_pintor_default().red('ERROR')} Error while checking directory writability.\n${external_pintor_default().red(String(error))}`;
166
+ return `${external_pintor_default().red('Error')} Couldn't check directory writability.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: check the path and permissions, then try again.')}`;
167
167
  }
168
168
  function cantSetupBuiltInTests(projectName, error) {
169
- return `${external_pintor_default().red('ERROR')} Can't setup built-in tests for ${external_pintor_default().yellow(projectName)}.\n${external_pintor_default().red(String(error))}`;
169
+ return `${external_pintor_default().red('Error')} Couldn't set up built-in tests for ${external_pintor_default().yellow(projectName)}.\n${external_pintor_default().red(String(error))}\n${external_pintor_default().red('Next step: run the setup step again or skip tests.')}`;
170
170
  }
171
171
  const promises_namespaceObject = require("fs/promises");
172
172
  const external_url_namespaceObject = require("url");
@@ -225,7 +225,7 @@ async function getInstallCommand() {
225
225
  if (process.env.npm_config_user_agent) {
226
226
  if (process.env.npm_config_user_agent.includes('pnpm')) return 'pnpm';
227
227
  }
228
- switch(null == pm ? void 0 : pm.name){
228
+ switch(pm?.name){
229
229
  case 'yarn':
230
230
  command = 'yarn';
231
231
  break;
@@ -296,7 +296,6 @@ var external_go_git_it_default = /*#__PURE__*/ __webpack_require__.n(external_go
296
296
  const import_external_template_filename = (0, external_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__);
297
297
  const import_external_template_dirname = external_path_namespaceObject.dirname(import_external_template_filename);
298
298
  async function importExternalTemplate(projectPath, projectName, template) {
299
- external_path_namespaceObject.dirname(projectPath);
300
299
  const templateName = external_path_namespaceObject.basename(template);
301
300
  const examplesUrl = 'https://github.com/extension-js/examples/tree/main/examples';
302
301
  const templateUrl = `${examplesUrl}/${template}`;
@@ -306,7 +305,9 @@ async function importExternalTemplate(projectPath, projectName, template) {
306
305
  });
307
306
  if ('development' === process.env.EXTENSION_ENV) {
308
307
  console.log(installingFromTemplate(projectName, template));
309
- const localTemplatePath = external_path_namespaceObject.join(import_external_template_dirname, '..', '..', '..', 'examples', templateName);
308
+ const localTemplatesRoot = external_path_namespaceObject.resolve(import_external_template_dirname, '..', '..', '..', '..', 'templates');
309
+ const localTemplateName = 'init' === templateName ? "javascript" : templateName;
310
+ const localTemplatePath = external_path_namespaceObject.join(localTemplatesRoot, localTemplateName);
310
311
  await copyDirectoryWithSymlinks(localTemplatePath, projectPath);
311
312
  } else {
312
313
  const tempRoot = await promises_namespaceObject.mkdtemp(external_path_namespaceObject.join(external_os_namespaceObject.tmpdir(), 'extension-js-create-'));
@@ -320,8 +321,7 @@ async function importExternalTemplate(projectPath, projectName, template) {
320
321
  const originalStdoutWrite = process.stdout.write.bind(process.stdout);
321
322
  const originalStderrWrite = process.stderr.write.bind(process.stderr);
322
323
  const shouldFilter = (chunk)=>{
323
- var _chunk_toString;
324
- const s = 'string' == typeof chunk ? chunk : (null == chunk ? void 0 : null == (_chunk_toString = chunk.toString) ? void 0 : _chunk_toString.call(chunk)) ?? '';
324
+ const s = 'string' == typeof chunk ? chunk : chunk?.toString?.() ?? '';
325
325
  if (!s) return false;
326
326
  return /Using git version/i.test(s) || /GitHub API rate limit reached, continuing without connectivity check/i.test(s);
327
327
  };
@@ -353,7 +353,7 @@ async function importExternalTemplate(projectPath, projectName, template) {
353
353
  responseType: 'arraybuffer',
354
354
  maxRedirects: 5
355
355
  });
356
- const contentType = String((null == headers ? void 0 : headers['content-type']) || '');
356
+ const contentType = String(headers?.['content-type'] || '');
357
357
  const looksZip = /zip|octet-stream/i.test(contentType) || template.toLowerCase().endsWith('.zip');
358
358
  if (!looksZip) throw new Error(`Remote template does not appear to be a ZIP archive: ${template}`);
359
359
  const zip = new (external_adm_zip_default())(Buffer.from(data));
@@ -377,7 +377,9 @@ async function importExternalTemplate(projectPath, projectName, template) {
377
377
  const extensionJsPackageJsonScripts = {
378
378
  dev: 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension dev' : 'extension dev',
379
379
  start: 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension start' : 'extension start',
380
- build: 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build' : 'extension build'
380
+ build: 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build' : 'extension build',
381
+ 'build:firefox': 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build --browser firefox' : 'extension build --browser firefox',
382
+ 'build:edge': 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build --browser edge' : 'extension build --browser edge'
381
383
  };
382
384
  async function overridePackageJson(projectPath, projectName, { template, cliVersion }) {
383
385
  const templatePath = getTemplatePath(process.cwd());
@@ -461,21 +463,62 @@ async function installDependencies(projectPath, projectName) {
461
463
  throw error;
462
464
  }
463
465
  }
466
+ const manifestSearchMaxDepth = 3;
467
+ const ignoredManifestDirs = new Set([
468
+ 'node_modules',
469
+ '.git'
470
+ ]);
471
+ async function findManifestJsonPath(projectPath) {
472
+ const candidates = [
473
+ external_path_namespaceObject.join(projectPath, 'manifest.json'),
474
+ external_path_namespaceObject.join(projectPath, 'src', 'manifest.json'),
475
+ external_path_namespaceObject.join(projectPath, 'extension', 'manifest.json'),
476
+ external_path_namespaceObject.join(projectPath, 'extension', 'src', 'manifest.json')
477
+ ];
478
+ for (const candidate of candidates)try {
479
+ await external_fs_namespaceObject.promises.access(candidate);
480
+ return candidate;
481
+ } catch {}
482
+ const queue = [
483
+ {
484
+ dir: projectPath,
485
+ depth: 0
486
+ }
487
+ ];
488
+ while(queue.length > 0){
489
+ const current = queue.shift();
490
+ if (!current) continue;
491
+ let entries;
492
+ try {
493
+ entries = await external_fs_namespaceObject.promises.readdir(current.dir, {
494
+ withFileTypes: true
495
+ });
496
+ } catch {
497
+ continue;
498
+ }
499
+ for (const entry of entries){
500
+ if (entry.isFile() && 'manifest.json' === entry.name) return external_path_namespaceObject.join(current.dir, entry.name);
501
+ if (entry.isDirectory() && current.depth < manifestSearchMaxDepth && !ignoredManifestDirs.has(entry.name)) queue.push({
502
+ dir: external_path_namespaceObject.join(current.dir, entry.name),
503
+ depth: current.depth + 1
504
+ });
505
+ }
506
+ }
507
+ throw new Error(`Could not locate manifest.json under ${projectPath}. Checked common paths and searched up to depth ${manifestSearchMaxDepth}.`);
508
+ }
464
509
  async function writeReadmeFile(projectPath, projectName) {
465
510
  try {
466
511
  await promises_namespaceObject.access(external_path_namespaceObject.join(projectPath, 'README.md'));
467
512
  return;
468
513
  } catch {}
469
514
  const initTemplateReadme = `
470
- <a href="https://extension.js.org" target="_blank"><img src="https://img.shields.io/badge/Powered%20by%20%7C%20Extension.js-0971fe" alt="Powered by Extension.js" align="right" /></a>
515
+ <a href="https://extension.js.org" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/Powered%20by%20%7C%20Extension.js-0971fe" alt="Powered by Extension.js" align="right" /></a>
471
516
 
472
517
  # [projectName]
473
518
 
474
519
  > [templateDescription]
475
520
 
476
- What this example does in the scope of a browser extension. The description should
477
- describe for an audience of developers looking to use the example. Avoid jargon and
478
- use simple language.
521
+ This project was created with Extension.js. Use the commands below to run and build it.
479
522
 
480
523
  ## Installation
481
524
 
@@ -489,18 +532,26 @@ npm install
489
532
 
490
533
  ### dev
491
534
 
492
- Run the extension in development mode.
535
+ Run the extension in development mode. You can target a specific browser using the
536
+ \`--browser <browser>\` flag. Supported values: \`chrome\`, \`firefox\`, \`edge\`.
493
537
 
494
538
  \`\`\`bash
495
- [runCommand] dev
539
+ [runCommand] dev --browser chrome
540
+ # or
541
+ [runCommand] dev --browser firefox
542
+ # or
543
+ [runCommand] dev --browser edge
496
544
  \`\`\`
497
545
 
498
546
  ### build
499
547
 
500
- Build the extension for production.
548
+ Build the extension for production. Use \`--browser <browser>\` to select a target.
501
549
 
502
550
  \`\`\`bash
503
- [runCommand] build
551
+ [runCommand] build (defaults to Chrome)
552
+ # or use convenience scripts
553
+ [runCommand] build:firefox (Firefox)
554
+ [runCommand] build:edge (Edge)
504
555
  \`\`\`
505
556
 
506
557
  ### Preview
@@ -513,10 +564,10 @@ Preview the extension in the browser.
513
564
 
514
565
  ## Learn more
515
566
 
516
- Learn more about this and other examples at @https://extension.js.org/
567
+ Learn more in the [Extension.js docs](https://extension.js.org).
517
568
  `;
518
569
  const installCommand = await getInstallCommand();
519
- const manifestJsonPath = external_path_namespaceObject.join(projectPath, 'manifest.json');
570
+ const manifestJsonPath = await findManifestJsonPath(projectPath);
520
571
  const manifestJson = JSON.parse(await promises_namespaceObject.readFile(manifestJsonPath, 'utf-8'));
521
572
  const readmeFileEdited = initTemplateReadme.replaceAll('[projectName]', projectName).replaceAll("[templateDescription]", manifestJson.description).replaceAll('[runCommand]', installCommand);
522
573
  try {
@@ -531,7 +582,7 @@ Learn more about this and other examples at @https://extension.js.org/
531
582
  }
532
583
  }
533
584
  async function writeManifestJson(projectPath, projectName) {
534
- const manifestJsonPath = external_path_namespaceObject.join(projectPath, 'manifest.json');
585
+ const manifestJsonPath = await findManifestJsonPath(projectPath);
535
586
  const manifestJsonContent = await promises_namespaceObject.readFile(manifestJsonPath);
536
587
  const manifestJson = JSON.parse(manifestJsonContent.toString());
537
588
  const manifestMetadata = {
@@ -541,7 +592,7 @@ async function writeManifestJson(projectPath, projectName) {
541
592
  };
542
593
  try {
543
594
  console.log(writingManifestJsonMetadata());
544
- await promises_namespaceObject.writeFile(external_path_namespaceObject.join(projectPath, 'manifest.json'), JSON.stringify(manifestMetadata, null, 2));
595
+ await promises_namespaceObject.writeFile(manifestJsonPath, JSON.stringify(manifestMetadata, null, 2));
545
596
  } catch (error) {
546
597
  console.error(writingManifestJsonMetadataError(projectName, error));
547
598
  throw error;
@@ -701,9 +752,9 @@ async function extensionCreate(projectNameInput, { cliVersion, template = 'init'
701
752
  }
702
753
  }
703
754
  exports.extensionCreate = __webpack_exports__.extensionCreate;
704
- for(var __webpack_i__ in __webpack_exports__)if (-1 === [
755
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
705
756
  "extensionCreate"
706
- ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
757
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
707
758
  Object.defineProperty(exports, '__esModule', {
708
759
  value: true
709
760
  });
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "license": "MIT",
3
+ "packageManager": "pnpm@10.28.0",
3
4
  "repository": {
4
5
  "type": "git",
5
- "url": "https://github.com/extension-js/create.git"
6
+ "url": "https://github.com/extension-js/extension.js.git"
6
7
  },
7
8
  "engines": {
8
9
  "node": ">=18"
9
10
  },
10
11
  "exports": {
11
12
  ".": {
13
+ "development": "./module.ts",
12
14
  "types": "./dist/module.d.ts",
13
15
  "import": "./dist/module.js",
14
16
  "require": "./dist/module.js"
@@ -20,7 +22,7 @@
20
22
  "dist"
21
23
  ],
22
24
  "name": "extension-create",
23
- "version": "2.2.1",
25
+ "version": "3.1.0-next.5",
24
26
  "description": "The standalone extension creation engine for Extension.js",
25
27
  "author": {
26
28
  "name": "Cezar Augusto",
@@ -32,6 +34,16 @@
32
34
  "registry": "https://registry.npmjs.org",
33
35
  "tag": "latest"
34
36
  },
37
+ "scripts": {
38
+ "clean": "rm -rf dist",
39
+ "watch": "rslib build --watch",
40
+ "compile": "rslib build",
41
+ "format": "prettier --write \"**/*.{ts,tsx,md,js,json}\"",
42
+ "lint": "eslint .",
43
+ "pretest:create": "pnpm compile",
44
+ "test:create": "vitest run",
45
+ "test:coverage": "vitest run --coverage"
46
+ },
35
47
  "keywords": [
36
48
  "webextension",
37
49
  "browser-extension",
@@ -55,40 +67,30 @@
55
67
  "edge-extension"
56
68
  ],
57
69
  "dependencies": {
58
- "adm-zip": "^0.5.12",
59
- "axios": "^1.12.0",
70
+ "adm-zip": "^0.5.16",
71
+ "axios": "^1.13.2",
60
72
  "cross-spawn": "^7.0.6",
61
- "go-git-it": "^5.0.0",
62
- "package-manager-detector": "^0.2.7",
73
+ "go-git-it": "^5.0.3",
74
+ "package-manager-detector": "^1.6.0",
63
75
  "pintor": "0.3.0",
64
76
  "tiny-glob": "^0.2.9"
65
77
  },
66
78
  "devDependencies": {
67
- "@changesets/cli": "^2.29.6",
68
- "@eslint/js": "^9.16.0",
69
- "@rslib/core": "^0.6.9",
70
- "@types/adm-zip": "^0.5.6",
71
- "@types/chrome": "^0.0.287",
79
+ "@changesets/cli": "^2.29.8",
80
+ "@eslint/js": "^9.39.2",
81
+ "@rslib/core": "^0.19.2",
82
+ "@types/adm-zip": "^0.5.7",
83
+ "@types/chrome": "^0.1.33",
72
84
  "@types/cross-spawn": "^6.0.6",
73
- "@types/node": "^22.10.1",
74
- "@types/webextension-polyfill": "0.12.3",
75
- "@vitest/coverage-v8": "^3.2.4",
76
- "eslint": "^9.16.0",
77
- "globals": "^15.13.0",
78
- "prettier": "^3.4.2",
85
+ "@types/node": "^25.0.9",
86
+ "@types/webextension-polyfill": "0.12.4",
87
+ "@vitest/coverage-v8": "^4.0.17",
88
+ "eslint": "^9.39.2",
89
+ "globals": "^17.0.0",
90
+ "prettier": "^3.8.0",
79
91
  "tsconfig": "*",
80
- "typescript": "5.7.2",
81
- "vitest": "^3.2.4",
92
+ "typescript": "5.9.3",
93
+ "vitest": "^4.0.17",
82
94
  "webextension-polyfill": "^0.12.0"
83
- },
84
- "scripts": {
85
- "clean": "rm -rf dist",
86
- "watch": "rslib build --watch",
87
- "compile": "rslib build",
88
- "format": "prettier --write \"**/*.{ts,tsx,md,js,json}\"",
89
- "lint": "eslint .",
90
- "pretest:create": "pnpm compile",
91
- "test:create": "vitest run",
92
- "test:coverage": "vitest run --coverage"
93
95
  }
94
- }
96
+ }
@@ -1,47 +0,0 @@
1
- <a href="https://extension.js.org" target="_blank"><img src="https://img.shields.io/badge/Powered%20by%20%7C%20Extension.js-0971fe" alt="Powered by Extension.js" align="right" /></a>
2
-
3
- # init
4
-
5
- > A basic browser extension example built with Extension.js. Perfect starting point for developers learning browser extension development with modern tooling.
6
-
7
- What this example does in the scope of a browser extension. The description should
8
- describe for an audience of developers looking to use the example. Avoid jargon and
9
- use simple language.
10
-
11
- ## Installation
12
-
13
- ```bash
14
- npx extension@latest create <project-name> --template init
15
- cd <project-name>
16
- npm install
17
- ```
18
-
19
- ## Commands
20
-
21
- ### dev
22
-
23
- Run the extension in development mode.
24
-
25
- ```bash
26
- npx extension@latest dev
27
- ```
28
-
29
- ### build
30
-
31
- Build the extension for production.
32
-
33
- ```bash
34
- npx extension@latest build
35
- ```
36
-
37
- ### Preview
38
-
39
- Preview the extension in the browser.
40
-
41
- ```bash
42
- npx extension@latest preview
43
- ```
44
-
45
- ## Learn more
46
-
47
- Learn more about this and other examples at @https://extension.js.org/
@@ -1 +0,0 @@
1
- console.log('test')
@@ -1,11 +0,0 @@
1
- {
2
- "$schema": "https://json.schemastore.org/chrome-manifest.json",
3
- "manifest_version": 3,
4
- "version": "0.0.1",
5
- "name": "test-template-init",
6
- "description": "A basic browser extension example built with Extension.js. Perfect starting point for developers learning browser extension development with modern tooling.",
7
- "icons": {
8
- "48": "images/extension_48.png"
9
- },
10
- "author": "Your Name"
11
- }
@@ -1,22 +0,0 @@
1
- {
2
- "private": true,
3
- "name": "test-template-init",
4
- "description": "A basic browser extension example built with Extension.js. Perfect starting point for developers learning browser extension development with modern tooling.",
5
- "version": "0.0.1",
6
- "license": "MIT",
7
- "type": "module",
8
- "author": {
9
- "name": "Your Name",
10
- "email": "your@email.com",
11
- "url": "https://yourwebsite.com"
12
- },
13
- "scripts": {
14
- "dev": "extension dev",
15
- "start": "extension start",
16
- "build": "extension build"
17
- },
18
- "dependencies": {},
19
- "devDependencies": {
20
- "extension": "^undefined"
21
- }
22
- }