extension-develop 2.0.4 → 2.1.1

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.
@@ -125,13 +125,17 @@ class ReactContentScriptWrapper {
125
125
  // Create shadow root for style isolation
126
126
  this.shadowRoot = this.rootElement.attachShadow({ mode: 'open' })
127
127
 
128
+ // Create a host element inside the shadow root for rendering
129
+ const host = document.createElement('div')
130
+ this.shadowRoot.appendChild(host)
131
+
128
132
  // Inject styles FIRST
129
133
  console.log('[Extension.js] About to inject styles')
130
134
  await this.injectStyles()
131
135
 
132
136
  // Render React content
133
137
  console.log('[Extension.js] About to render React content')
134
- const result = this.renderFunction(this.shadowRoot as any)
138
+ const result = this.renderFunction(host)
135
139
  if (typeof result === 'function') {
136
140
  this.unmountFunction = result
137
141
  }
@@ -198,8 +202,8 @@ class ReactContentScriptWrapper {
198
202
  // Check if we have hardcoded content for this stylesheet
199
203
  if (cssContentMap[stylesheet]) {
200
204
  const cssContent = cssContentMap[stylesheet]
201
- allCSS += cssContent + '\\n'
202
- console.log(\`[Extension.js] Successfully injected React \${stylesheet} content\`)
205
+ allCSS += cssContent + '\n'
206
+ console.log('[Extension.js] Successfully injected React', stylesheet, 'content')
203
207
  continue
204
208
  }
205
209
 
@@ -208,7 +212,7 @@ class ReactContentScriptWrapper {
208
212
  const response = await fetch(cssUrl)
209
213
  const text = await response.text()
210
214
  if (response.ok) {
211
- allCSS += text + '\\n'
215
+ allCSS += text + '\n'
212
216
  console.log('[Extension.js] Successfully fetched stylesheet:', stylesheet)
213
217
  } else {
214
218
  console.warn('[Extension.js] Failed to fetch CSS:', stylesheet)
@@ -405,13 +409,17 @@ class VueContentScriptWrapper {
405
409
  // Create shadow root for style isolation
406
410
  this.shadowRoot = this.rootElement.attachShadow({ mode: 'open' })
407
411
 
412
+ // Create a host element inside the shadow root for rendering
413
+ const host = document.createElement('div')
414
+ this.shadowRoot.appendChild(host)
415
+
408
416
  // Inject styles FIRST
409
417
  console.log('[Extension.js] About to inject styles')
410
418
  await this.injectStyles()
411
419
 
412
420
  // Render Vue content
413
421
  console.log('[Extension.js] About to render Vue content')
414
- const result = this.renderFunction(this.shadowRoot as any)
422
+ const result = this.renderFunction(host)
415
423
  if (typeof result === 'function') {
416
424
  this.unmountFunction = result
417
425
  }
@@ -478,8 +486,8 @@ class VueContentScriptWrapper {
478
486
  // Check if we have hardcoded content for this stylesheet
479
487
  if (cssContentMap[stylesheet]) {
480
488
  const cssContent = cssContentMap[stylesheet]
481
- allCSS += cssContent + '\\n'
482
- console.log(\`[Extension.js] Successfully injected Vue \${stylesheet} content\`)
489
+ allCSS += cssContent + '\n'
490
+ console.log('[Extension.js] Successfully injected Vue', stylesheet, 'content')
483
491
  continue
484
492
  }
485
493
 
@@ -488,7 +496,7 @@ class VueContentScriptWrapper {
488
496
  const response = await fetch(cssUrl)
489
497
  const text = await response.text()
490
498
  if (response.ok) {
491
- allCSS += text + '\\n'
499
+ allCSS += text + '\n'
492
500
  console.log('[Extension.js] Successfully fetched stylesheet:', stylesheet)
493
501
  } else {
494
502
  console.warn('[Extension.js] Failed to fetch CSS:', stylesheet)
@@ -683,13 +691,17 @@ class SvelteContentScriptWrapper {
683
691
  // Create shadow root for style isolation
684
692
  this.shadowRoot = this.rootElement.attachShadow({ mode: 'open' })
685
693
 
694
+ // Create a host element inside the shadow root for rendering
695
+ const host = document.createElement('div')
696
+ this.shadowRoot.appendChild(host)
697
+
686
698
  // Inject styles FIRST
687
699
  console.log('[Extension.js] About to inject styles')
688
700
  await this.injectStyles()
689
701
 
690
702
  // Render Svelte content
691
703
  console.log('[Extension.js] About to render Svelte content')
692
- const result = this.renderFunction(this.shadowRoot as any)
704
+ const result = this.renderFunction(host)
693
705
  if (typeof result === 'function') {
694
706
  this.unmountFunction = result
695
707
  }
@@ -756,8 +768,8 @@ class SvelteContentScriptWrapper {
756
768
  // Check if we have hardcoded content for this stylesheet
757
769
  if (cssContentMap[stylesheet]) {
758
770
  const cssContent = cssContentMap[stylesheet]
759
- allCSS += cssContent + '\\n'
760
- console.log(\`[Extension.js] Successfully injected Svelte \${stylesheet} content\`)
771
+ allCSS += cssContent + '\n'
772
+ console.log('[Extension.js] Successfully injected Svelte', stylesheet, 'content')
761
773
  continue
762
774
  }
763
775
 
@@ -766,7 +778,7 @@ class SvelteContentScriptWrapper {
766
778
  const response = await fetch(cssUrl)
767
779
  const text = await response.text()
768
780
  if (response.ok) {
769
- allCSS += text + '\\n'
781
+ allCSS += text + '\n'
770
782
  console.log('[Extension.js] Successfully fetched stylesheet:', stylesheet)
771
783
  } else {
772
784
  console.warn('[Extension.js] Failed to fetch CSS:', stylesheet)
@@ -64,6 +64,7 @@ function add_hmr_accept_code(source) {
64
64
  name: "scripts:add-hmr-accept-code",
65
65
  baseDataPath: 'options'
66
66
  });
67
+ if (source.includes('import.meta.webpackHot')) return source;
67
68
  const url = (0, external_loader_utils_namespaceObject.urlToRequest)(this.resourcePath);
68
69
  const reloadCode = `
69
70
  // TODO: cezaraugusto re-visit this
@@ -34,6 +34,7 @@ export interface BuildOptions {
34
34
  zipSource?: boolean;
35
35
  polyfill?: boolean;
36
36
  silent?: boolean;
37
+ exitOnError?: boolean;
37
38
  }
38
39
  export interface PreviewOptions extends BrowserOptionsBase {
39
40
  mode: 'production';
@@ -1,6 +1,6 @@
1
1
  export interface ProjectStructure {
2
2
  manifestPath: string;
3
- packageJsonPath: string;
3
+ packageJsonPath?: string;
4
4
  }
5
5
  export declare function getProjectPath(pathOrRemoteUrl: string | undefined): Promise<string>;
6
6
  export declare function getProjectStructure(pathOrRemoteUrl: string | undefined): Promise<ProjectStructure>;
@@ -25,6 +25,7 @@ export declare function downloadingText(url: string): string;
25
25
  export declare function unpackagingExtension(zipFilePath: string): string;
26
26
  export declare function unpackagedSuccessfully(): string;
27
27
  export declare function failedToDownloadOrExtractZIPFileError(error: any): string;
28
+ export declare function invalidRemoteZip(url: string, contentType: string): string;
28
29
  export declare function isUsingExperimentalConfig(integration: any): string;
29
30
  export declare function installingDependencies(): string;
30
31
  export declare function installingDependenciesFailed(gitCommand: string, gitArgs: string[], code: number | null): string;
@@ -4,9 +4,14 @@ import {connect, disconnect, keepAlive} from './reload-service.js'
4
4
  function bgGreen(str) {
5
5
  return `background: transparent; color: #0971fe; ${str}`
6
6
  }
7
- chrome.tabs.query({active: true}, async ([initialTab]) => {
8
- console.log(
9
- `%c
7
+
8
+ async function initManagerUI() {
9
+ try {
10
+ chrome.tabs.query({active: true, currentWindow: true}, async (tabs) => {
11
+ const initialTab = Array.isArray(tabs) ? tabs[0] : undefined
12
+
13
+ console.log(
14
+ `%c
10
15
  ██████████████████████████████████████████████████████████
11
16
  ██████████████████████████████████████████████████████████
12
17
  ████████████████████████████ ██████████████████████████
@@ -32,22 +37,43 @@ chrome.tabs.query({active: true}, async ([initialTab]) => {
32
37
  ██████████████████████████████████████████████████████████
33
38
  MIT (c) ${new Date().getFullYear()} - Cezar Augusto and the Extension.js Authors.
34
39
  `,
35
- bgGreen('')
36
- )
37
-
38
- if (
39
- initialTab.url === 'chrome://newtab/' ||
40
- initialTab.url === 'chrome://welcome/'
41
- ) {
42
- await handleFirstRun()
43
- } else {
44
- createExtensionsPageTab(initialTab, 'chrome://extensions/')
45
- }
40
+ bgGreen('')
41
+ )
42
+
43
+ if (!initialTab) {
44
+ try {
45
+ await handleFirstRun()
46
+ } catch {
47
+ try {
48
+ chrome.tabs.create({url: 'chrome://extensions/'})
49
+ } catch {}
50
+ }
51
+ return
52
+ }
53
+
54
+ if (
55
+ initialTab.url === 'chrome://newtab/' ||
56
+ initialTab.url === 'chrome://welcome/'
57
+ ) {
58
+ await handleFirstRun()
59
+ } else {
60
+ createExtensionsPageTab(initialTab, 'chrome://extensions/')
61
+ }
62
+ })
63
+ } catch {}
64
+ }
65
+
66
+ // Guard tab access and run after startup
67
+ chrome.runtime.onStartup.addListener(async () => {
68
+ await initManagerUI()
46
69
  })
47
70
 
48
71
  chrome.runtime.onInstalled.addListener(async () => {
49
72
  let isConnected = false
50
73
 
74
+ // Ensure UI setup also runs on install (first run)
75
+ await initManagerUI()
76
+
51
77
  if (isConnected) {
52
78
  disconnect()
53
79
  } else {
@@ -20,7 +20,12 @@ export async function connect() {
20
20
  const maxBackoffMs = 5000
21
21
 
22
22
  const establish = () => {
23
- webSocket = new WebSocket(`ws://127.0.0.1:${port}`)
23
+ try {
24
+ webSocket = new WebSocket(`ws://127.0.0.1:${port}`)
25
+ } catch (err) {
26
+ webSocket = null
27
+ return
28
+ }
24
29
 
25
30
  webSocket.onerror = (_event) => {
26
31
  try {
@@ -37,7 +42,12 @@ export async function connect() {
37
42
 
38
43
  let reloadDebounce
39
44
  webSocket.onmessage = async (event) => {
40
- const message = JSON.parse(event.data)
45
+ let message = null
46
+ try {
47
+ message = JSON.parse(event.data)
48
+ } catch {
49
+ return
50
+ }
41
51
 
42
52
  // Only process messages for this instance
43
53
  if (message.instanceId && message.instanceId !== instanceId) {
@@ -77,6 +87,18 @@ export function disconnect() {
77
87
  }
78
88
  }
79
89
 
90
+ // Ensure sockets are closed when the worker is suspended
91
+ try {
92
+ chrome.runtime.onSuspend.addListener(() => {
93
+ if (webSocket) {
94
+ try {
95
+ webSocket.close()
96
+ } catch {}
97
+ webSocket = null
98
+ }
99
+ })
100
+ } catch {}
101
+
80
102
  async function requestInitialLoadData() {
81
103
  const devExtensions = await getDevExtensions()
82
104
 
@@ -4,9 +4,14 @@ import {connect, disconnect, keepAlive} from './reload-service.js'
4
4
  function bgGreen(str) {
5
5
  return `background: transparent; color: #0971fe; ${str}`
6
6
  }
7
- chrome.tabs.query({active: true}, async ([initialTab]) => {
8
- console.log(
9
- `%c
7
+
8
+ async function initManagerUI() {
9
+ try {
10
+ chrome.tabs.query({active: true, currentWindow: true}, async (tabs) => {
11
+ const initialTab = Array.isArray(tabs) ? tabs[0] : undefined
12
+
13
+ console.log(
14
+ `%c
10
15
  ██████████████████████████████████████████████████████████
11
16
  ██████████████████████████████████████████████████████████
12
17
  ████████████████████████████ ██████████████████████████
@@ -32,22 +37,43 @@ chrome.tabs.query({active: true}, async ([initialTab]) => {
32
37
  ██████████████████████████████████████████████████████████
33
38
  MIT (c) ${new Date().getFullYear()} - Cezar Augusto and the Extension.js Authors.
34
39
  `,
35
- bgGreen('')
36
- )
37
-
38
- if (
39
- initialTab.url === 'chrome://newtab/' ||
40
- initialTab.url === 'chrome://welcome/'
41
- ) {
42
- await handleFirstRun()
43
- } else {
44
- createExtensionsPageTab(initialTab, 'chrome://extensions/')
45
- }
40
+ bgGreen('')
41
+ )
42
+
43
+ if (!initialTab) {
44
+ try {
45
+ await handleFirstRun()
46
+ } catch {
47
+ try {
48
+ chrome.tabs.create({url: 'chrome://extensions/'})
49
+ } catch {}
50
+ }
51
+ return
52
+ }
53
+
54
+ if (
55
+ initialTab.url === 'chrome://newtab/' ||
56
+ initialTab.url === 'chrome://welcome/'
57
+ ) {
58
+ await handleFirstRun()
59
+ } else {
60
+ createExtensionsPageTab(initialTab, 'chrome://extensions/')
61
+ }
62
+ })
63
+ } catch {}
64
+ }
65
+
66
+ // Guard tab access and run after startup
67
+ chrome.runtime.onStartup.addListener(async () => {
68
+ await initManagerUI()
46
69
  })
47
70
 
48
71
  chrome.runtime.onInstalled.addListener(async () => {
49
72
  let isConnected = false
50
73
 
74
+ // Ensure UI setup also runs on install (first run)
75
+ await initManagerUI()
76
+
51
77
  if (isConnected) {
52
78
  disconnect()
53
79
  } else {
@@ -17,7 +17,12 @@ export async function connect() {
17
17
  const maxBackoffMs = 5000
18
18
 
19
19
  const establish = () => {
20
- webSocket = new WebSocket(`ws://127.0.0.1:${port}`)
20
+ try {
21
+ webSocket = new WebSocket(`ws://127.0.0.1:${port}`)
22
+ } catch (err) {
23
+ webSocket = null
24
+ return
25
+ }
21
26
 
22
27
  webSocket.onerror = (_event) => {
23
28
  try {
@@ -34,7 +39,12 @@ export async function connect() {
34
39
 
35
40
  let reloadDebounce
36
41
  webSocket.onmessage = async (event) => {
37
- const message = JSON.parse(event.data)
42
+ let message = null
43
+ try {
44
+ message = JSON.parse(event.data)
45
+ } catch {
46
+ return
47
+ }
38
48
 
39
49
  if (message.status === 'serverReady') {
40
50
  await requestInitialLoadData()
@@ -69,6 +79,18 @@ export function disconnect() {
69
79
  }
70
80
  }
71
81
 
82
+ // Ensure sockets are closed when the worker is suspended
83
+ try {
84
+ chrome.runtime.onSuspend.addListener(() => {
85
+ if (webSocket) {
86
+ try {
87
+ webSocket.close()
88
+ } catch {}
89
+ webSocket = null
90
+ }
91
+ })
92
+ } catch {}
93
+
72
94
  async function getDevExtensions() {
73
95
  const allExtensions = await new Promise((resolve) => {
74
96
  chrome.management.getAll(resolve)
@@ -4,9 +4,14 @@ import {connect, disconnect, keepAlive} from './reload-service.js'
4
4
  function bgGreen(str) {
5
5
  return `background: transparent; color: #0971fe; ${str}`
6
6
  }
7
- chrome.tabs.query({active: true}, async ([initialTab]) => {
8
- console.log(
9
- `%c
7
+
8
+ async function initManagerUI() {
9
+ try {
10
+ chrome.tabs.query({active: true, currentWindow: true}, async (tabs) => {
11
+ const initialTab = Array.isArray(tabs) ? tabs[0] : undefined
12
+
13
+ console.log(
14
+ `%c
10
15
  ██████████████████████████████████████████████████████████
11
16
  ██████████████████████████████████████████████████████████
12
17
  ████████████████████████████ ██████████████████████████
@@ -32,22 +37,41 @@ chrome.tabs.query({active: true}, async ([initialTab]) => {
32
37
  ██████████████████████████████████████████████████████████
33
38
  MIT (c) ${new Date().getFullYear()} - Cezar Augusto and the Extension.js Authors.
34
39
  `,
35
- bgGreen('')
36
- )
37
-
38
- if (
39
- initialTab.url === 'chrome://newtab/' ||
40
- initialTab.url === 'chrome://welcome/'
41
- ) {
42
- await handleFirstRun()
43
- } else {
44
- createExtensionsPageTab(initialTab, 'chrome://extensions/')
45
- }
40
+ bgGreen('')
41
+ )
42
+
43
+ if (!initialTab) {
44
+ try {
45
+ await handleFirstRun()
46
+ } catch {
47
+ try {
48
+ chrome.tabs.create({url: 'chrome://extensions/'})
49
+ } catch {}
50
+ }
51
+ return
52
+ }
53
+
54
+ if (
55
+ initialTab.url === 'chrome://newtab/' ||
56
+ initialTab.url === 'chrome://welcome/'
57
+ ) {
58
+ await handleFirstRun()
59
+ } else {
60
+ createExtensionsPageTab(initialTab, 'chrome://extensions/')
61
+ }
62
+ })
63
+ } catch {}
64
+ }
65
+
66
+ chrome.runtime.onStartup.addListener(async () => {
67
+ await initManagerUI()
46
68
  })
47
69
 
48
70
  chrome.runtime.onInstalled.addListener(async () => {
49
71
  let isConnected = false
50
72
 
73
+ await initManagerUI()
74
+
51
75
  if (isConnected) {
52
76
  disconnect()
53
77
  } else {
@@ -20,7 +20,12 @@ export async function connect() {
20
20
  const maxBackoffMs = 5000
21
21
 
22
22
  const establish = () => {
23
- webSocket = new WebSocket(`ws://127.0.0.1:${port}`)
23
+ try {
24
+ webSocket = new WebSocket(`ws://127.0.0.1:${port}`)
25
+ } catch (err) {
26
+ webSocket = null
27
+ return
28
+ }
24
29
 
25
30
  webSocket.onerror = (_event) => {
26
31
  try {
@@ -37,7 +42,12 @@ export async function connect() {
37
42
 
38
43
  let reloadDebounce
39
44
  webSocket.onmessage = async (event) => {
40
- const message = JSON.parse(event.data)
45
+ let message = null
46
+ try {
47
+ message = JSON.parse(event.data)
48
+ } catch {
49
+ return
50
+ }
41
51
 
42
52
  // Only process messages for this instance
43
53
  if (message.instanceId && message.instanceId !== instanceId) {
@@ -77,6 +87,18 @@ export function disconnect() {
77
87
  }
78
88
  }
79
89
 
90
+ // Ensure sockets are closed when the worker is suspended
91
+ try {
92
+ chrome.runtime.onSuspend.addListener(() => {
93
+ if (webSocket) {
94
+ try {
95
+ webSocket.close()
96
+ } catch {}
97
+ webSocket = null
98
+ }
99
+ })
100
+ } catch {}
101
+
80
102
  async function requestInitialLoadData() {
81
103
  const devExtensions = await getDevExtensions()
82
104
 
@@ -17,7 +17,12 @@ async function connect() {
17
17
  const maxBackoffMs = 5000
18
18
 
19
19
  const connectTo = (url) => {
20
- webSocket = new WebSocket(url)
20
+ try {
21
+ webSocket = new WebSocket(url)
22
+ } catch (err) {
23
+ webSocket = null
24
+ return
25
+ }
21
26
 
22
27
  webSocket.onerror = (_event) => {
23
28
  try {
@@ -38,7 +43,12 @@ async function connect() {
38
43
 
39
44
  let reloadDebounce
40
45
  webSocket.onmessage = async (event) => {
41
- const message = JSON.parse(event.data)
46
+ let message = null
47
+ try {
48
+ message = JSON.parse(event.data)
49
+ } catch {
50
+ return
51
+ }
42
52
 
43
53
  // Only process messages for this instance
44
54
  if (message.instanceId && message.instanceId !== instanceId) {
@@ -55,3 +55,13 @@ browser.runtime.onInstalled.addListener(async () => {
55
55
  isConnected = true
56
56
  }
57
57
  })
58
+
59
+ // Also initialize on browser startup for parity with Chromium behavior
60
+ browser.runtime.onStartup.addListener(async () => {
61
+ try {
62
+ await handleTabOnExtensionLoad()
63
+ } catch {}
64
+ try {
65
+ await connect()
66
+ } catch {}
67
+ })
@@ -15,7 +15,12 @@ export async function connect() {
15
15
  const maxBackoffMs = 5000
16
16
 
17
17
  const connectTo = (url) => {
18
- webSocket = new WebSocket(url)
18
+ try {
19
+ webSocket = new WebSocket(url)
20
+ } catch (err) {
21
+ webSocket = null
22
+ return
23
+ }
19
24
 
20
25
  webSocket.onerror = (_event) => {
21
26
  try {
@@ -36,12 +41,20 @@ export async function connect() {
36
41
 
37
42
  let reloadDebounce
38
43
  webSocket.onmessage = async (event) => {
39
- const message = JSON.parse(event.data)
44
+ let message = null
45
+ try {
46
+ message = JSON.parse(event.data)
47
+ } catch {
48
+ return
49
+ }
40
50
 
41
51
  if (message.status === 'serverReady') {
42
52
  console.info(
43
53
  `[Extension.js] Server ready. Requesting initial load data...`
44
54
  )
55
+ try {
56
+ await requestInitialLoadData()
57
+ } catch {}
45
58
  }
46
59
 
47
60
  if (message.changedFile) {