extension-create 2.2.1 → 3.1.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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>;
@@ -2,7 +2,7 @@ export declare function destinationNotWriteable(workingDir: string): string;
2
2
  export declare function directoryHasConflicts(projectPath: string, conflictingFiles: string[]): Promise<string>;
3
3
  export declare function noProjectName(): string;
4
4
  export declare function noUrlAllowed(): string;
5
- export declare function successfullInstall(projectPath: string, projectName: string): Promise<string>;
5
+ export declare function successfullInstall(projectPath: string, projectName: string, depsInstalled: boolean): Promise<string>;
6
6
  export declare function startingNewExtension(projectName: string): string;
7
7
  export declare function checkingIfPathIsWriteable(): string;
8
8
  export declare function scanningPossiblyConflictingFiles(): 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
- async function successfullInstall(projectPath, projectName) {
66
+ async function successfullInstall(projectPath, projectName, depsInstalled) {
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,88 @@ 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
+ const steps = depsInstalled ? ` 1. ${external_pintor_default().blue('cd')} ${external_pintor_default().underline(relativePath)}\n 2. ${external_pintor_default().blue(command)} (runs a fresh browser profile with your extension loaded)\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
+ const depsNote = depsInstalled ? `\n${external_pintor_default().gray('Dependencies installed. You can start developing now.')}\n` : '\n';
92
+ return `${external_pintor_default().green('Created')} ${external_pintor_default().blue(projectName)}\n\nNext steps:\n\n` + steps + depsNote;
91
93
  }
92
94
  function startingNewExtension(projectName) {
93
- return `\u{1F423} - Starting a new browser extension named ${external_pintor_default().blue(projectName)}...`;
95
+ return `Creating ${external_pintor_default().blue(projectName)}...`;
94
96
  }
95
97
  function checkingIfPathIsWriteable() {
96
- return `\u{1F91E} - Checking if destination path is writeable...`;
98
+ return 'Checking if the destination path is writable...';
97
99
  }
98
100
  function scanningPossiblyConflictingFiles() {
99
- return "\uD83D\uDD0E - Scanning for potential conflicting files...";
101
+ return 'Scanning for conflicting files...';
100
102
  }
101
103
  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))}`;
104
+ 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
105
  }
104
106
  function writingTypeDefinitions(projectName) {
105
- return `\u{1F537} - Writing type definitions for ${external_pintor_default().blue(projectName)}...`;
107
+ return `Writing type definitions for ${external_pintor_default().blue(projectName)}...`;
106
108
  }
107
109
  function writingTypeDefinitionsError(error) {
108
- return `${external_pintor_default().red('ERROR')} Failed to write the extension type definition.\n${external_pintor_default().red(String(error))}`;
110
+ 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
111
  }
110
112
  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)}...`;
113
+ if ('init' === templateName) return `Installing ${external_pintor_default().blue(projectName)}...`;
114
+ return `Installing ${external_pintor_default().blue(projectName)} from template ${external_pintor_default().yellow(templateName)}...`;
113
115
  }
114
116
  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))}`;
117
+ 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
118
  }
117
119
  function initializingGitForRepository(projectName) {
118
- return `\u{1F332} - Initializing git repository for ${external_pintor_default().blue(projectName)}...`;
120
+ return `Initializing git repository for ${external_pintor_default().blue(projectName)}...`;
119
121
  }
120
122
  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))}`)}`;
123
+ 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
124
  }
123
125
  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))}`;
126
+ 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
127
  }
126
128
  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))}`;
129
+ 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
130
  }
129
131
  function installingDependencies() {
130
- return "\uD83D\uDEE0 - Installing dependencies... (takes a moment)";
132
+ return 'Installing dependencies (this may take a moment)...';
131
133
  }
132
134
  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))}`)}`;
135
+ 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
136
  }
135
137
  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))}`;
138
+ 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
139
  }
138
140
  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))}`;
141
+ 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
142
  }
141
143
  function writingPackageJsonMetadata() {
142
- return `\u{1F4DD} - Writing ${external_pintor_default().yellow('package.json')} metadata...`;
144
+ return `Writing ${external_pintor_default().yellow('package.json')}...`;
143
145
  }
144
146
  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))}`;
147
+ 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
148
  }
147
149
  function writingManifestJsonMetadata() {
148
- return `\u{1F4DC} - Writing ${external_pintor_default().yellow('manifest.json')} metadata...`;
150
+ return `Writing ${external_pintor_default().yellow('manifest.json')}...`;
149
151
  }
150
152
  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))}`;
153
+ 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
154
  }
153
155
  function writingReadmeMetaData() {
154
- return `\u{1F4C4} - Writing ${external_pintor_default().yellow('README.md')} metadata...`;
156
+ return `Writing ${external_pintor_default().yellow('README.md')}...`;
155
157
  }
156
158
  function writingGitIgnore() {
157
- return `\u{1F648} - Writing ${external_pintor_default().yellow('.gitignore')} lines...`;
159
+ return `Writing ${external_pintor_default().yellow('.gitignore')}...`;
158
160
  }
159
161
  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))}`;
162
+ 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
163
  }
162
164
  function folderExists(projectName) {
163
- return `\u{1F91D} - Ensuring ${external_pintor_default().blue(projectName)} folder exists...`;
165
+ return `Ensuring ${external_pintor_default().blue(projectName)} exists...`;
164
166
  }
165
167
  function writingDirectoryError(error) {
166
- return `${external_pintor_default().red('ERROR')} Error while checking directory writability.\n${external_pintor_default().red(String(error))}`;
168
+ 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
169
  }
168
170
  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))}`;
171
+ 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
172
  }
171
173
  const promises_namespaceObject = require("fs/promises");
172
174
  const external_url_namespaceObject = require("url");
@@ -225,7 +227,7 @@ async function getInstallCommand() {
225
227
  if (process.env.npm_config_user_agent) {
226
228
  if (process.env.npm_config_user_agent.includes('pnpm')) return 'pnpm';
227
229
  }
228
- switch(null == pm ? void 0 : pm.name){
230
+ switch(pm?.name){
229
231
  case 'yarn':
230
232
  command = 'yarn';
231
233
  break;
@@ -296,7 +298,6 @@ var external_go_git_it_default = /*#__PURE__*/ __webpack_require__.n(external_go
296
298
  const import_external_template_filename = (0, external_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__);
297
299
  const import_external_template_dirname = external_path_namespaceObject.dirname(import_external_template_filename);
298
300
  async function importExternalTemplate(projectPath, projectName, template) {
299
- external_path_namespaceObject.dirname(projectPath);
300
301
  const templateName = external_path_namespaceObject.basename(template);
301
302
  const examplesUrl = 'https://github.com/extension-js/examples/tree/main/examples';
302
303
  const templateUrl = `${examplesUrl}/${template}`;
@@ -306,7 +307,24 @@ async function importExternalTemplate(projectPath, projectName, template) {
306
307
  });
307
308
  if ('development' === process.env.EXTENSION_ENV) {
308
309
  console.log(installingFromTemplate(projectName, template));
309
- const localTemplatePath = external_path_namespaceObject.join(import_external_template_dirname, '..', '..', '..', 'examples', templateName);
310
+ async function findTemplatesRoot(startDir) {
311
+ let current = startDir;
312
+ const maxDepth = 6;
313
+ for(let i = 0; i < maxDepth; i++){
314
+ const candidate = external_path_namespaceObject.join(current, 'templates');
315
+ try {
316
+ const stats = await promises_namespaceObject.stat(candidate);
317
+ if (stats.isDirectory()) return candidate;
318
+ } catch {}
319
+ const parent = external_path_namespaceObject.dirname(current);
320
+ if (parent === current) break;
321
+ current = parent;
322
+ }
323
+ }
324
+ const localTemplatesRoot = await findTemplatesRoot(import_external_template_dirname);
325
+ if (!localTemplatesRoot) throw new Error('Local templates directory not found');
326
+ const localTemplateName = 'init' === templateName ? "javascript" : templateName;
327
+ const localTemplatePath = external_path_namespaceObject.join(localTemplatesRoot, localTemplateName);
310
328
  await copyDirectoryWithSymlinks(localTemplatePath, projectPath);
311
329
  } else {
312
330
  const tempRoot = await promises_namespaceObject.mkdtemp(external_path_namespaceObject.join(external_os_namespaceObject.tmpdir(), 'extension-js-create-'));
@@ -320,8 +338,7 @@ async function importExternalTemplate(projectPath, projectName, template) {
320
338
  const originalStdoutWrite = process.stdout.write.bind(process.stdout);
321
339
  const originalStderrWrite = process.stderr.write.bind(process.stderr);
322
340
  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)) ?? '';
341
+ const s = 'string' == typeof chunk ? chunk : chunk?.toString?.() ?? '';
325
342
  if (!s) return false;
326
343
  return /Using git version/i.test(s) || /GitHub API rate limit reached, continuing without connectivity check/i.test(s);
327
344
  };
@@ -353,7 +370,7 @@ async function importExternalTemplate(projectPath, projectName, template) {
353
370
  responseType: 'arraybuffer',
354
371
  maxRedirects: 5
355
372
  });
356
- const contentType = String((null == headers ? void 0 : headers['content-type']) || '');
373
+ const contentType = String(headers?.['content-type'] || '');
357
374
  const looksZip = /zip|octet-stream/i.test(contentType) || template.toLowerCase().endsWith('.zip');
358
375
  if (!looksZip) throw new Error(`Remote template does not appear to be a ZIP archive: ${template}`);
359
376
  const zip = new (external_adm_zip_default())(Buffer.from(data));
@@ -377,7 +394,9 @@ async function importExternalTemplate(projectPath, projectName, template) {
377
394
  const extensionJsPackageJsonScripts = {
378
395
  dev: 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension dev' : 'extension dev',
379
396
  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'
397
+ build: 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build' : 'extension build',
398
+ 'build:firefox': 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build --browser firefox' : 'extension build --browser firefox',
399
+ 'build:edge': 'development' === process.env.EXTENSION_ENV ? 'node node_modules/extension build --browser edge' : 'extension build --browser edge'
381
400
  };
382
401
  async function overridePackageJson(projectPath, projectName, { template, cliVersion }) {
383
402
  const templatePath = getTemplatePath(process.cwd());
@@ -461,21 +480,62 @@ async function installDependencies(projectPath, projectName) {
461
480
  throw error;
462
481
  }
463
482
  }
483
+ const manifestSearchMaxDepth = 3;
484
+ const ignoredManifestDirs = new Set([
485
+ 'node_modules',
486
+ '.git'
487
+ ]);
488
+ async function findManifestJsonPath(projectPath) {
489
+ const candidates = [
490
+ external_path_namespaceObject.join(projectPath, 'manifest.json'),
491
+ external_path_namespaceObject.join(projectPath, 'src', 'manifest.json'),
492
+ external_path_namespaceObject.join(projectPath, 'extension', 'manifest.json'),
493
+ external_path_namespaceObject.join(projectPath, 'extension', 'src', 'manifest.json')
494
+ ];
495
+ for (const candidate of candidates)try {
496
+ await external_fs_namespaceObject.promises.access(candidate);
497
+ return candidate;
498
+ } catch {}
499
+ const queue = [
500
+ {
501
+ dir: projectPath,
502
+ depth: 0
503
+ }
504
+ ];
505
+ while(queue.length > 0){
506
+ const current = queue.shift();
507
+ if (!current) continue;
508
+ let entries;
509
+ try {
510
+ entries = await external_fs_namespaceObject.promises.readdir(current.dir, {
511
+ withFileTypes: true
512
+ });
513
+ } catch {
514
+ continue;
515
+ }
516
+ for (const entry of entries){
517
+ if (entry.isFile() && 'manifest.json' === entry.name) return external_path_namespaceObject.join(current.dir, entry.name);
518
+ if (entry.isDirectory() && current.depth < manifestSearchMaxDepth && !ignoredManifestDirs.has(entry.name)) queue.push({
519
+ dir: external_path_namespaceObject.join(current.dir, entry.name),
520
+ depth: current.depth + 1
521
+ });
522
+ }
523
+ }
524
+ throw new Error(`Could not locate manifest.json under ${projectPath}. Checked common paths and searched up to depth ${manifestSearchMaxDepth}.`);
525
+ }
464
526
  async function writeReadmeFile(projectPath, projectName) {
465
527
  try {
466
528
  await promises_namespaceObject.access(external_path_namespaceObject.join(projectPath, 'README.md'));
467
529
  return;
468
530
  } catch {}
469
531
  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>
532
+ <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
533
 
472
534
  # [projectName]
473
535
 
474
536
  > [templateDescription]
475
537
 
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.
538
+ This project was created with Extension.js. Use the commands below to run and build it.
479
539
 
480
540
  ## Installation
481
541
 
@@ -489,18 +549,26 @@ npm install
489
549
 
490
550
  ### dev
491
551
 
492
- Run the extension in development mode.
552
+ Run the extension in development mode. You can target a specific browser using the
553
+ \`--browser <browser>\` flag. Supported values: \`chrome\`, \`firefox\`, \`edge\`.
493
554
 
494
555
  \`\`\`bash
495
- [runCommand] dev
556
+ [runCommand] dev --browser chrome
557
+ # or
558
+ [runCommand] dev --browser firefox
559
+ # or
560
+ [runCommand] dev --browser edge
496
561
  \`\`\`
497
562
 
498
563
  ### build
499
564
 
500
- Build the extension for production.
565
+ Build the extension for production. Use \`--browser <browser>\` to select a target.
501
566
 
502
567
  \`\`\`bash
503
- [runCommand] build
568
+ [runCommand] build (defaults to Chrome)
569
+ # or use convenience scripts
570
+ [runCommand] build:firefox (Firefox)
571
+ [runCommand] build:edge (Edge)
504
572
  \`\`\`
505
573
 
506
574
  ### Preview
@@ -513,10 +581,10 @@ Preview the extension in the browser.
513
581
 
514
582
  ## Learn more
515
583
 
516
- Learn more about this and other examples at @https://extension.js.org/
584
+ Learn more in the [Extension.js docs](https://extension.js.org).
517
585
  `;
518
586
  const installCommand = await getInstallCommand();
519
- const manifestJsonPath = external_path_namespaceObject.join(projectPath, 'manifest.json');
587
+ const manifestJsonPath = await findManifestJsonPath(projectPath);
520
588
  const manifestJson = JSON.parse(await promises_namespaceObject.readFile(manifestJsonPath, 'utf-8'));
521
589
  const readmeFileEdited = initTemplateReadme.replaceAll('[projectName]', projectName).replaceAll("[templateDescription]", manifestJson.description).replaceAll('[runCommand]', installCommand);
522
590
  try {
@@ -531,7 +599,7 @@ Learn more about this and other examples at @https://extension.js.org/
531
599
  }
532
600
  }
533
601
  async function writeManifestJson(projectPath, projectName) {
534
- const manifestJsonPath = external_path_namespaceObject.join(projectPath, 'manifest.json');
602
+ const manifestJsonPath = await findManifestJsonPath(projectPath);
535
603
  const manifestJsonContent = await promises_namespaceObject.readFile(manifestJsonPath);
536
604
  const manifestJson = JSON.parse(manifestJsonContent.toString());
537
605
  const manifestMetadata = {
@@ -541,7 +609,7 @@ async function writeManifestJson(projectPath, projectName) {
541
609
  };
542
610
  try {
543
611
  console.log(writingManifestJsonMetadata());
544
- await promises_namespaceObject.writeFile(external_path_namespaceObject.join(projectPath, 'manifest.json'), JSON.stringify(manifestMetadata, null, 2));
612
+ await promises_namespaceObject.writeFile(manifestJsonPath, JSON.stringify(manifestMetadata, null, 2));
545
613
  } catch (error) {
546
614
  console.error(writingManifestJsonMetadataError(projectName, error));
547
615
  throw error;
@@ -693,7 +761,7 @@ async function extensionCreate(projectNameInput, { cliVersion, template = 'init'
693
761
  await writeGitignore(projectPath);
694
762
  await setupBuiltInTests(projectPath, projectName);
695
763
  if (isTypeScriptTemplate(template)) await generateExtensionTypes(projectPath, projectName);
696
- const successfulInstall = await successfullInstall(projectPath, projectName);
764
+ const successfulInstall = await successfullInstall(projectPath, projectName, Boolean(install));
697
765
  console.log(successfulInstall);
698
766
  } catch (error) {
699
767
  console.error(error);
@@ -701,9 +769,9 @@ async function extensionCreate(projectNameInput, { cliVersion, template = 'init'
701
769
  }
702
770
  }
703
771
  exports.extensionCreate = __webpack_exports__.extensionCreate;
704
- for(var __webpack_i__ in __webpack_exports__)if (-1 === [
772
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
705
773
  "extensionCreate"
706
- ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__];
774
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
707
775
  Object.defineProperty(exports, '__esModule', {
708
776
  value: true
709
777
  });
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.11",
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
- }