@lvce-editor/extension-management-worker 4.72.1 → 4.74.0

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.
@@ -34,12 +34,12 @@ const state$4 = {
34
34
  extensionsState: createInitialState(),
35
35
  nextApplicationGeneration: 0
36
36
  };
37
- const applications$1 = new Map();
37
+ const applications$2 = new Map();
38
38
  const createApplication = (applicationId, platform, webExtensions) => {
39
- if (!applicationId || applications$1.has(applicationId)) {
39
+ if (!applicationId || applications$2.has(applicationId)) {
40
40
  throw new Error(`Invalid or duplicate extension application: ${applicationId}`);
41
41
  }
42
- applications$1.set(applicationId, {
42
+ applications$2.set(applicationId, {
43
43
  ...createInitialState(),
44
44
  applicationGeneration: ++state$4.nextApplicationGeneration,
45
45
  applicationId,
@@ -48,13 +48,13 @@ const createApplication = (applicationId, platform, webExtensions) => {
48
48
  });
49
49
  };
50
50
  const removeApplication = applicationId => {
51
- applications$1.delete(applicationId);
51
+ applications$2.delete(applicationId);
52
52
  };
53
53
  const isCurrentApplication = application => {
54
54
  if (application.applicationId === undefined) {
55
55
  return true;
56
56
  }
57
- const current = applications$1.get(application.applicationId);
57
+ const current = applications$2.get(application.applicationId);
58
58
  return current !== undefined && current.applicationGeneration === application.applicationGeneration;
59
59
  };
60
60
  const assertCurrentApplication = application => {
@@ -64,7 +64,7 @@ const assertCurrentApplication = application => {
64
64
  };
65
65
  const get$7 = applicationId => {
66
66
  if (applicationId !== undefined) {
67
- const application = applications$1.get(applicationId);
67
+ const application = applications$2.get(applicationId);
68
68
  if (!application) {
69
69
  throw new Error(`Extension application not found: ${applicationId}`);
70
70
  }
@@ -78,7 +78,7 @@ const set$d = newState => {
78
78
  if (newState.applicationGeneration !== currentState.applicationGeneration) {
79
79
  throw new Error(`Stale extension application state: ${newState.applicationId}`);
80
80
  }
81
- applications$1.set(newState.applicationId, newState);
81
+ applications$2.set(newState.applicationId, newState);
82
82
  return;
83
83
  }
84
84
  state$4.extensionsState = newState;
@@ -770,7 +770,7 @@ let CommandNotFoundError$1 = class CommandNotFoundError extends Error {
770
770
  }
771
771
  };
772
772
  const commands = Object.create(null);
773
- const register$1 = commandMap => {
773
+ const register$2 = commandMap => {
774
774
  Object.assign(commands, commandMap);
775
775
  };
776
776
  const getCommand = key => {
@@ -1293,7 +1293,7 @@ const create$7 = async ({
1293
1293
  messagePort
1294
1294
  }) => {
1295
1295
  // TODO create a commandMap per rpc instance
1296
- register$1(commandMap);
1296
+ register$2(commandMap);
1297
1297
  const rawIpc = await IpcParentWithMessagePort$1.create({
1298
1298
  isMessagePortOpen,
1299
1299
  messagePort
@@ -1361,7 +1361,7 @@ const create$4 = async ({
1361
1361
  webSocket
1362
1362
  }) => {
1363
1363
  // TODO create a commandMap per rpc instance
1364
- register$1(commandMap);
1364
+ register$2(commandMap);
1365
1365
  let rawIpc;
1366
1366
  try {
1367
1367
  rawIpc = await IpcParentWithWebSocket$1.create({
@@ -1436,7 +1436,7 @@ const create$2 = async ({
1436
1436
  messagePort
1437
1437
  }) => {
1438
1438
  // TODO create a commandMap per rpc instance
1439
- register$1(commandMap);
1439
+ register$2(commandMap);
1440
1440
  const rawIpc = await IpcParentWithMessagePort$1.create({
1441
1441
  isMessagePortOpen,
1442
1442
  messagePort
@@ -1451,7 +1451,7 @@ const create$1 = async ({
1451
1451
  commandMap
1452
1452
  }) => {
1453
1453
  // TODO create a commandMap per rpc instance
1454
- register$1(commandMap);
1454
+ register$2(commandMap);
1455
1455
  const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
1456
1456
  handleIpc(ipc);
1457
1457
  const rpc = createRpc(ipc);
@@ -1687,35 +1687,35 @@ const createNodeRpcMessagePort = async (extensionId, rpcId, port) => {
1687
1687
  };
1688
1688
 
1689
1689
  const extensionIds = new Set();
1690
- const applications = new Map();
1691
- const register = (extensionId, applicationId) => {
1690
+ const applications$1 = new Map();
1691
+ const register$1 = (extensionId, applicationId) => {
1692
1692
  if (applicationId === undefined) {
1693
1693
  extensionIds.add(extensionId);
1694
1694
  return;
1695
1695
  }
1696
- const ids = applications.get(applicationId) || new Set();
1696
+ const ids = applications$1.get(applicationId) || new Set();
1697
1697
  ids.add(extensionId);
1698
- applications.set(applicationId, ids);
1698
+ applications$1.set(applicationId, ids);
1699
1699
  };
1700
1700
  const unregister = (extensionId, applicationId) => {
1701
1701
  if (applicationId === undefined) {
1702
1702
  extensionIds.delete(extensionId);
1703
1703
  return;
1704
1704
  }
1705
- const ids = applications.get(applicationId);
1705
+ const ids = applications$1.get(applicationId);
1706
1706
  ids?.delete(extensionId);
1707
1707
  if (ids?.size === 0) {
1708
- applications.delete(applicationId);
1708
+ applications$1.delete(applicationId);
1709
1709
  }
1710
1710
  };
1711
1711
  const getRegisteredExtensionIds = applicationId => {
1712
- return [...(applicationId === undefined ? extensionIds : applications.get(applicationId) || [])];
1712
+ return [...(applicationId === undefined ? extensionIds : applications$1.get(applicationId) || [])];
1713
1713
  };
1714
1714
  const reset = applicationId => {
1715
1715
  if (applicationId === undefined) {
1716
1716
  extensionIds.clear();
1717
1717
  } else {
1718
- applications.delete(applicationId);
1718
+ applications$1.delete(applicationId);
1719
1719
  }
1720
1720
  };
1721
1721
 
@@ -1957,7 +1957,7 @@ const createExtensionCommandMap = (extensionId, invokeCommand = invokeGlobalComm
1957
1957
  return getSecret(extensionId, key);
1958
1958
  },
1959
1959
  'Extensions.registerFileChangeHandler'() {
1960
- register(extensionId);
1960
+ register$1(extensionId);
1961
1961
  },
1962
1962
  'Extensions.sendMessagePortToElectron'(port, initialCommand) {
1963
1963
  if (initialCommand !== allowedElectronPortCommand) {
@@ -1986,6 +1986,269 @@ const createExtensionCommandExecutor = commandMap => {
1986
1986
  };
1987
1987
  };
1988
1988
 
1989
+ const sourcePathMarker = '/extension-management-worker/src/';
1990
+ const getExtensionHostSubWorkerUrl = (currentUrl = import.meta.url) => {
1991
+ const relativePath = currentUrl.includes(sourcePathMarker) ? '../../../../extension-host-sub-worker/src/extensionHostSubWorkerMain.js' : '../../extension-host-sub-worker/dist/extensionHostSubWorkerMain.js';
1992
+ return new URL(relativePath, currentUrl).href;
1993
+ };
1994
+ const extensionHostSubWorkerUrl = getExtensionHostSubWorkerUrl();
1995
+
1996
+ // TODO
1997
+
1998
+ const getOrigin = () => {
1999
+ return globalThis.location?.origin || 'http://localhost';
2000
+ };
2001
+
2002
+ /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
2003
+
2004
+ const allowedScriptSources = new Set([`'self'`, `'unsafe-eval'`]);
2005
+ const allowedConnectSchemeSources = new Set(['https:', 'wss:']);
2006
+ const reservedDirectives = new Set(['child-src', 'connect-src', 'default-src', 'script-src', 'worker-src']);
2007
+ const nodeProcessType = 'node-process';
2008
+ const loopbackWildcardPortSourceRegex = /^(?:http|ws):\/\/(?:127\.0\.0\.1|localhost):\*$/;
2009
+ const parseDirective = directive => {
2010
+ if (directive.includes('\n') || directive.includes('\r')) {
2011
+ throw new Error('content security policy directives cannot contain newlines');
2012
+ }
2013
+ return directive.replace(/;$/, '').trim().split(/\s+/);
2014
+ };
2015
+ const getWorkerUrls = absolutePath => {
2016
+ const applicationUrl = new URL(getOrigin());
2017
+ const workerUrl = new URL(absolutePath, applicationUrl);
2018
+ if (workerUrl.protocol !== 'http:' && workerUrl.protocol !== 'https:') {
2019
+ return {
2020
+ origin: applicationUrl.origin
2021
+ };
2022
+ }
2023
+ const webSocketProtocol = applicationUrl.protocol === 'https:' ? 'wss:' : 'ws:';
2024
+ return {
2025
+ assetSource: new URL('./', workerUrl).href,
2026
+ capabilitySource: `${webSocketProtocol}//${applicationUrl.host}/websocket/capability`,
2027
+ nodeProcessSource: `${webSocketProtocol}//${applicationUrl.host}/websocket/extension-node-process`,
2028
+ origin: applicationUrl.origin
2029
+ };
2030
+ };
2031
+ const hasNodeProcess = rpcInfos => {
2032
+ return rpcInfos?.some(rpcInfo => typeof rpcInfo === 'object' && rpcInfo !== null && rpcInfo.type === nodeProcessType) === true;
2033
+ };
2034
+ const validateExternalConnectSource = (source, applicationOrigin) => {
2035
+ if (allowedConnectSchemeSources.has(source) || loopbackWildcardPortSourceRegex.test(source)) {
2036
+ return source;
2037
+ }
2038
+ if (source.includes('*') || source === `'none'` || source === 'http:' || source === 'ws:') {
2039
+ throw new Error(`invalid isolated extension connect source ${source}`);
2040
+ }
2041
+ let url;
2042
+ try {
2043
+ url = new URL(source);
2044
+ } catch {
2045
+ throw new Error(`isolated extension connect source must be an absolute URL. Invalid value: ${JSON.stringify(source)}`);
2046
+ }
2047
+ if (!['http:', 'https:', 'ws:', 'wss:'].includes(url.protocol) || !url.hostname || url.username || url.password) {
2048
+ throw new Error(`invalid isolated extension connect source ${source}`);
2049
+ }
2050
+ const applicationUrl = new URL(applicationOrigin);
2051
+ if (url.host === applicationUrl.host) {
2052
+ throw new Error(`isolated extensions cannot allow the application origin in connect-src`);
2053
+ }
2054
+ return source;
2055
+ };
2056
+ const addScriptSources = (scriptSources, sources) => {
2057
+ for (const source of sources) {
2058
+ if (!allowedScriptSources.has(source)) {
2059
+ throw new Error(`invalid isolated extension script source ${source}`);
2060
+ }
2061
+ scriptSources.add(source);
2062
+ }
2063
+ };
2064
+ const addConnectSources = (connectSources, sources, assetSource, origin) => {
2065
+ for (const source of sources) {
2066
+ if (source === `'self'`) {
2067
+ if (assetSource) {
2068
+ connectSources.add(assetSource);
2069
+ }
2070
+ } else {
2071
+ connectSources.add(validateExternalConnectSource(source, origin));
2072
+ }
2073
+ }
2074
+ };
2075
+ const validateDefaultSources = sources => {
2076
+ if (sources.length !== 1 || sources[0] !== `'none'`) {
2077
+ throw new Error(`isolated extension default-src must be 'none'`);
2078
+ }
2079
+ };
2080
+ const applyDirective = (directive, scriptSources, connectSources, assetSource, origin) => {
2081
+ const [name, ...sources] = parseDirective(directive);
2082
+ if (!name) {
2083
+ return;
2084
+ }
2085
+ if (name === 'default-src') {
2086
+ validateDefaultSources(sources);
2087
+ return;
2088
+ }
2089
+ if (name === 'script-src') {
2090
+ addScriptSources(scriptSources, sources);
2091
+ return;
2092
+ }
2093
+ if (name === 'connect-src') {
2094
+ addConnectSources(connectSources, sources, assetSource, origin);
2095
+ return;
2096
+ }
2097
+ if (reservedDirectives.has(name)) {
2098
+ throw new Error(`isolated extensions cannot override ${name}`);
2099
+ }
2100
+ };
2101
+ const getContentSecurityPolicy = (directives, absolutePath, rpcInfos) => {
2102
+ const {
2103
+ assetSource,
2104
+ capabilitySource,
2105
+ nodeProcessSource,
2106
+ origin
2107
+ } = getWorkerUrls(absolutePath);
2108
+ const scriptSources = new Set([`'self'`]);
2109
+ const connectSources = new Set();
2110
+ if (capabilitySource) {
2111
+ connectSources.add(capabilitySource);
2112
+ }
2113
+ if (assetSource) {
2114
+ connectSources.add(assetSource);
2115
+ }
2116
+ if (nodeProcessSource && hasNodeProcess(rpcInfos)) {
2117
+ connectSources.add(nodeProcessSource);
2118
+ }
2119
+ const manifestDirectives = directives || [];
2120
+ for (const directive of manifestDirectives) {
2121
+ applyDirective(directive, scriptSources, connectSources, assetSource, origin);
2122
+ }
2123
+ const connectDirective = connectSources.size > 0 ? [...connectSources].join(' ') : `'none'`;
2124
+ return `default-src 'none'; script-src ${[...scriptSources].join(' ')}; worker-src 'none'; child-src 'none'; connect-src ${connectDirective};`;
2125
+ };
2126
+
2127
+ const getUrlPrefix = (platform, extensionPath) => {
2128
+ if (extensionPath.startsWith('http://') || extensionPath.startsWith('https://')) {
2129
+ return extensionPath;
2130
+ }
2131
+ if (platform === Web) {
2132
+ return extensionPath;
2133
+ }
2134
+ if (extensionPath.startsWith('/')) {
2135
+ return `/remote${extensionPath}`;
2136
+ }
2137
+ return `/remote/${extensionPath}`;
2138
+ };
2139
+
2140
+ /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
2141
+
2142
+ const applications = new Map();
2143
+ const getServices = application => {
2144
+ assertCurrentApplication(application);
2145
+ const generation = application.applicationGeneration;
2146
+ let services = applications.get(generation);
2147
+ if (!services) {
2148
+ services = {
2149
+ children: new Map(),
2150
+ declarations: new Map(),
2151
+ extensionVersions: new Map(),
2152
+ nextChild: 0,
2153
+ ports: new Map()
2154
+ };
2155
+ applications.set(generation, services);
2156
+ }
2157
+ return services;
2158
+ };
2159
+ const register = (extension, platform) => {
2160
+ const application = get$7(extension.applicationId);
2161
+ assertCurrentApplication(extension);
2162
+ const services = getServices(application);
2163
+ const prefix = getUrlPrefix(platform, extension.path);
2164
+ const declarations = extension.rpc || [];
2165
+ for (const info of declarations) {
2166
+ if (info.type !== 'web-worker') {
2167
+ throw new Error('Application extensions only support web-worker RPCs');
2168
+ }
2169
+ services.declarations.set(info.id, {
2170
+ ...info,
2171
+ extensionId: extension.id,
2172
+ url: `${prefix}/${info.url}`
2173
+ });
2174
+ }
2175
+ };
2176
+ const getRpcInfo$1 = (application, id) => {
2177
+ const info = getServices(application).declarations.get(id);
2178
+ if (!info) throw new Error(`Rpc not found ${id}`);
2179
+ return info;
2180
+ };
2181
+ const createWorker$1 = async (application, info, port, legacy = false, extensionId) => {
2182
+ const services = getServices(application);
2183
+ const id = JSON.stringify([application.applicationId, application.applicationGeneration, 'child', ++services.nextChild]);
2184
+ services.children.set(id, extensionId);
2185
+ const url = legacy ? extensionHostSubWorkerUrl : info.url;
2186
+ try {
2187
+ const policy = getContentSecurityPolicy(info.contentSecurityPolicy || [], url);
2188
+ await invokeAndTransfer('LaunchIsolatedExtensionHostWorker.launchIsolatedExtensionHostWorker', port, id, url, info.name || '', policy);
2189
+ assertCurrentApplication(application);
2190
+ if (!services.children.has(id)) throw new Error('Extension worker was disposed during launch');
2191
+ } catch (error) {
2192
+ services.children.delete(id);
2193
+ await invoke('LaunchIsolatedExtensionHostWorker.disposeIsolatedExtensionHostWorker', id);
2194
+ throw error;
2195
+ }
2196
+ };
2197
+ const fileSystemMethods = new Set(['readFile', 'readDirWithFileTypes', 'stat', 'exists', 'writeFile', 'mkdir', 'remove', 'rename', 'copy', 'getBlob']);
2198
+ const createFileSystemPort = async (application, port, extensionId) => {
2199
+ const services = getServices(application);
2200
+ const version = extensionId === undefined ? 0 : services.extensionVersions.get(extensionId) || 0;
2201
+ const rpc = await create$7({
2202
+ commandMap: {},
2203
+ messagePort: port
2204
+ });
2205
+ // Bind only this connection: registering callbacks globally would let the
2206
+ // second IDE replace the first IDE's filesystem routing.
2207
+ rpc.ipc.execute = async (command, ...args) => {
2208
+ assertCurrentApplication(application);
2209
+ const method = command.startsWith('FileSystem.') ? command.slice('FileSystem.'.length) : '';
2210
+ if (!fileSystemMethods.has(method)) throw new Error(`Unsupported application filesystem command: ${command}`);
2211
+ const value = await invoke('Application.execute', application.applicationId, command, ...args);
2212
+ return method === 'stat' ? value.type : value;
2213
+ };
2214
+ try {
2215
+ assertCurrentApplication(application);
2216
+ if (extensionId !== undefined && (services.extensionVersions.get(extensionId) || 0) !== version) {
2217
+ throw new Error('Extension was reloaded while opening its filesystem port');
2218
+ }
2219
+ services.ports.set(rpc, extensionId);
2220
+ } catch (error) {
2221
+ await rpc.dispose();
2222
+ throw error;
2223
+ }
2224
+ };
2225
+ const dispose = async application => {
2226
+ const services = applications.get(application.applicationGeneration);
2227
+ if (!services) return;
2228
+ applications.delete(application.applicationGeneration);
2229
+ const results = await Promise.allSettled([...Array.from(services.ports.keys(), rpc => Promise.try(() => rpc.dispose())), ...Array.from(services.children.keys(), id => invoke('LaunchIsolatedExtensionHostWorker.disposeIsolatedExtensionHostWorker', id))]);
2230
+ services.ports.clear();
2231
+ services.children.clear();
2232
+ services.declarations.clear();
2233
+ const errors = results.filter(result => result.status === 'rejected').map(result => result.reason);
2234
+ if (errors.length > 0) throw new AggregateError(errors, 'Failed to dispose application services');
2235
+ };
2236
+ const disposeExtension = async (application, extensionId) => {
2237
+ const services = applications.get(application.applicationGeneration);
2238
+ if (!services) return;
2239
+ services.extensionVersions.set(extensionId, (services.extensionVersions.get(extensionId) || 0) + 1);
2240
+ const ports = [...services.ports].filter(([, owner]) => owner === extensionId).map(([rpc]) => rpc);
2241
+ const children = [...services.children].filter(([, owner]) => owner === extensionId).map(([id]) => id);
2242
+ for (const rpc of ports) services.ports.delete(rpc);
2243
+ for (const id of children) services.children.delete(id);
2244
+ for (const [id, info] of services.declarations) {
2245
+ if (info.extensionId === extensionId) services.declarations.delete(id);
2246
+ }
2247
+ const results = await Promise.allSettled([...ports.map(rpc => Promise.try(() => rpc.dispose())), ...children.map(id => invoke('LaunchIsolatedExtensionHostWorker.disposeIsolatedExtensionHostWorker', id))]);
2248
+ const errors = results.filter(result => result.status === 'rejected').map(result => result.reason);
2249
+ if (errors.length > 0) throw new AggregateError(errors, `Failed to dispose extension services: ${extensionId}`);
2250
+ };
2251
+
1989
2252
  const rpcs$1 = Object.create(null);
1990
2253
  const applicationRpcs = new Map();
1991
2254
  const get$3 = (extensionId, applicationId) => {
@@ -2016,6 +2279,15 @@ const set$2 = (extensionId, rpc, applicationId) => {
2016
2279
  rpcs$1[extensionId] = rpc;
2017
2280
  };
2018
2281
  const remove$1 = (extensionId, applicationId) => {
2282
+ if (applicationId !== undefined) {
2283
+ const entries = applicationRpcs.get(applicationId);
2284
+ const rpc = entries?.get(extensionId);
2285
+ entries?.delete(extensionId);
2286
+ if (entries?.size === 0) {
2287
+ applicationRpcs.delete(applicationId);
2288
+ }
2289
+ return rpc;
2290
+ }
2019
2291
  const rpc = rpcs$1[extensionId];
2020
2292
  delete rpcs$1[extensionId];
2021
2293
  return rpc;
@@ -2053,11 +2325,17 @@ const createIsolatedExtensionHostWorker = async (extensionId, absolutePath, work
2053
2325
  const invokeCommand = application === undefined ? undefined : (method, ...args) => {
2054
2326
  assertCurrentApplication(application);
2055
2327
  if (method === 'Extensions.registerFileChangeHandler') {
2056
- return register(extensionId, application.applicationId);
2328
+ return register$1(extensionId, application.applicationId);
2057
2329
  }
2058
2330
  if (method === 'Extensions.unregisterFileChangeHandler') {
2059
2331
  return unregister(extensionId, application.applicationId);
2060
2332
  }
2333
+ if (method === 'Extensions.sendMessagePortToFileSystemWorker') {
2334
+ return createFileSystemPort(application, args[0], extensionId);
2335
+ }
2336
+ if (method === 'Extensions.createWebViewWorkerRpc' || method === 'Extensions.createWebViewWorkerRpc2') {
2337
+ return createWorker$1(application, args[0], args[1], method === 'Extensions.createWebViewWorkerRpc', extensionId);
2338
+ }
2061
2339
  const invokeApplication = commandMapRef['Extensions.invokeForApplication'];
2062
2340
  if (!invokeApplication) {
2063
2341
  throw new Error('Application extension command routing is not initialized');
@@ -2158,135 +2436,6 @@ const activateIsolatedExtension = async (extensionId, absolutePath, workerName,
2158
2436
  }
2159
2437
  };
2160
2438
 
2161
- const getOrigin = () => {
2162
- return globalThis.location?.origin || 'http://localhost';
2163
- };
2164
-
2165
- /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
2166
-
2167
- const allowedScriptSources = new Set([`'self'`, `'unsafe-eval'`]);
2168
- const allowedConnectSchemeSources = new Set(['https:', 'wss:']);
2169
- const reservedDirectives = new Set(['child-src', 'connect-src', 'default-src', 'script-src', 'worker-src']);
2170
- const nodeProcessType = 'node-process';
2171
- const loopbackWildcardPortSourceRegex = /^(?:http|ws):\/\/(?:127\.0\.0\.1|localhost):\*$/;
2172
- const parseDirective = directive => {
2173
- if (directive.includes('\n') || directive.includes('\r')) {
2174
- throw new Error('content security policy directives cannot contain newlines');
2175
- }
2176
- return directive.replace(/;$/, '').trim().split(/\s+/);
2177
- };
2178
- const getWorkerUrls = absolutePath => {
2179
- const applicationUrl = new URL(getOrigin());
2180
- const workerUrl = new URL(absolutePath, applicationUrl);
2181
- if (workerUrl.protocol !== 'http:' && workerUrl.protocol !== 'https:') {
2182
- return {
2183
- origin: applicationUrl.origin
2184
- };
2185
- }
2186
- const webSocketProtocol = applicationUrl.protocol === 'https:' ? 'wss:' : 'ws:';
2187
- return {
2188
- assetSource: new URL('./', workerUrl).href,
2189
- capabilitySource: `${webSocketProtocol}//${applicationUrl.host}/websocket/capability`,
2190
- nodeProcessSource: `${webSocketProtocol}//${applicationUrl.host}/websocket/extension-node-process`,
2191
- origin: applicationUrl.origin
2192
- };
2193
- };
2194
- const hasNodeProcess = rpcInfos => {
2195
- return rpcInfos?.some(rpcInfo => typeof rpcInfo === 'object' && rpcInfo !== null && rpcInfo.type === nodeProcessType) === true;
2196
- };
2197
- const validateExternalConnectSource = (source, applicationOrigin) => {
2198
- if (allowedConnectSchemeSources.has(source) || loopbackWildcardPortSourceRegex.test(source)) {
2199
- return source;
2200
- }
2201
- if (source.includes('*') || source === `'none'` || source === 'http:' || source === 'ws:') {
2202
- throw new Error(`invalid isolated extension connect source ${source}`);
2203
- }
2204
- let url;
2205
- try {
2206
- url = new URL(source);
2207
- } catch {
2208
- throw new Error(`isolated extension connect source must be an absolute URL. Invalid value: ${JSON.stringify(source)}`);
2209
- }
2210
- if (!['http:', 'https:', 'ws:', 'wss:'].includes(url.protocol) || !url.hostname || url.username || url.password) {
2211
- throw new Error(`invalid isolated extension connect source ${source}`);
2212
- }
2213
- const applicationUrl = new URL(applicationOrigin);
2214
- if (url.host === applicationUrl.host) {
2215
- throw new Error(`isolated extensions cannot allow the application origin in connect-src`);
2216
- }
2217
- return source;
2218
- };
2219
- const addScriptSources = (scriptSources, sources) => {
2220
- for (const source of sources) {
2221
- if (!allowedScriptSources.has(source)) {
2222
- throw new Error(`invalid isolated extension script source ${source}`);
2223
- }
2224
- scriptSources.add(source);
2225
- }
2226
- };
2227
- const addConnectSources = (connectSources, sources, assetSource, origin) => {
2228
- for (const source of sources) {
2229
- if (source === `'self'`) {
2230
- if (assetSource) {
2231
- connectSources.add(assetSource);
2232
- }
2233
- } else {
2234
- connectSources.add(validateExternalConnectSource(source, origin));
2235
- }
2236
- }
2237
- };
2238
- const validateDefaultSources = sources => {
2239
- if (sources.length !== 1 || sources[0] !== `'none'`) {
2240
- throw new Error(`isolated extension default-src must be 'none'`);
2241
- }
2242
- };
2243
- const applyDirective = (directive, scriptSources, connectSources, assetSource, origin) => {
2244
- const [name, ...sources] = parseDirective(directive);
2245
- if (!name) {
2246
- return;
2247
- }
2248
- if (name === 'default-src') {
2249
- validateDefaultSources(sources);
2250
- return;
2251
- }
2252
- if (name === 'script-src') {
2253
- addScriptSources(scriptSources, sources);
2254
- return;
2255
- }
2256
- if (name === 'connect-src') {
2257
- addConnectSources(connectSources, sources, assetSource, origin);
2258
- return;
2259
- }
2260
- if (reservedDirectives.has(name)) {
2261
- throw new Error(`isolated extensions cannot override ${name}`);
2262
- }
2263
- };
2264
- const getContentSecurityPolicy = (directives, absolutePath, rpcInfos) => {
2265
- const {
2266
- assetSource,
2267
- capabilitySource,
2268
- nodeProcessSource,
2269
- origin
2270
- } = getWorkerUrls(absolutePath);
2271
- const scriptSources = new Set([`'self'`]);
2272
- const connectSources = new Set();
2273
- if (capabilitySource) {
2274
- connectSources.add(capabilitySource);
2275
- }
2276
- if (assetSource) {
2277
- connectSources.add(assetSource);
2278
- }
2279
- if (nodeProcessSource && hasNodeProcess(rpcInfos)) {
2280
- connectSources.add(nodeProcessSource);
2281
- }
2282
- const manifestDirectives = directives || [];
2283
- for (const directive of manifestDirectives) {
2284
- applyDirective(directive, scriptSources, connectSources, assetSource, origin);
2285
- }
2286
- const connectDirective = connectSources.size > 0 ? [...connectSources].join(' ') : `'none'`;
2287
- return `default-src 'none'; script-src ${[...scriptSources].join(' ')}; worker-src 'none'; child-src 'none'; connect-src ${connectDirective};`;
2288
- };
2289
-
2290
2439
  const rpcs = Object.create(null);
2291
2440
  const add = (id, rpc) => {
2292
2441
  rpcs[id] = rpc;
@@ -2295,23 +2444,10 @@ const get$2 = id => {
2295
2444
  return rpcs[id];
2296
2445
  };
2297
2446
 
2298
- const getUrlPrefix = (platform, extensionPath) => {
2299
- if (extensionPath.startsWith('http://') || extensionPath.startsWith('https://')) {
2300
- return extensionPath;
2301
- }
2302
- if (platform === Web) {
2303
- return extensionPath;
2304
- }
2305
- if (extensionPath.startsWith('/')) {
2306
- return `/remote${extensionPath}`;
2307
- }
2308
- return `/remote/${extensionPath}`;
2309
- };
2310
-
2311
2447
  const handleRpcInfos = (extension, platform) => {
2312
2448
  if (extension?.applicationId !== undefined) {
2313
2449
  if (Array.isArray(extension.rpc) && extension.rpc.length > 0) {
2314
- throw new Error('Declared RPCs do not support application context');
2450
+ register(extension, platform);
2315
2451
  }
2316
2452
  return;
2317
2453
  }
@@ -3088,15 +3224,6 @@ const createWebViewWorkerRpc2 = async (rpcInfo, port) => {
3088
3224
  });
3089
3225
  };
3090
3226
 
3091
- const sourcePathMarker = '/extension-management-worker/src/';
3092
- const getExtensionHostSubWorkerUrl = (currentUrl = import.meta.url) => {
3093
- const relativePath = currentUrl.includes(sourcePathMarker) ? '../../../../extension-host-sub-worker/src/extensionHostSubWorkerMain.js' : '../../extension-host-sub-worker/dist/extensionHostSubWorkerMain.js';
3094
- return new URL(relativePath, currentUrl).href;
3095
- };
3096
- const extensionHostSubWorkerUrl = getExtensionHostSubWorkerUrl();
3097
-
3098
- // TODO
3099
-
3100
3227
  /**
3101
3228
  * @deprecated use createWebViewWorkerRpc2 which passes the worker url as a parameter
3102
3229
  */
@@ -3296,7 +3423,7 @@ const disposeExtensionApplication = async applicationId => {
3296
3423
  clear(applicationId);
3297
3424
  resetAllExtensionActivations(application);
3298
3425
  reset(applicationId);
3299
- const results = await Promise.allSettled(runtimes.map(async ({
3426
+ const results = await Promise.allSettled([dispose(application), ...runtimes.map(async ({
3300
3427
  id,
3301
3428
  rpc
3302
3429
  }) => {
@@ -3306,7 +3433,7 @@ const disposeExtensionApplication = async applicationId => {
3306
3433
  if (errors.length > 0) {
3307
3434
  throw new AggregateError(errors, `Failed to dispose extension ${id}`);
3308
3435
  }
3309
- }));
3436
+ })]);
3310
3437
  const errors = results.filter(result => result.status === 'rejected').map(result => result.reason);
3311
3438
  if (errors.length > 0) {
3312
3439
  throw new AggregateError(errors, `Failed to dispose extension application ${applicationId}`);
@@ -5716,6 +5843,69 @@ const getLanguages = async (platform, assetDir) => {
5716
5843
  }
5717
5844
  };
5718
5845
 
5846
+ /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
5847
+
5848
+ const queues = new Map();
5849
+ const replace = async (application, extensionId, extension) => {
5850
+ assertCurrentApplication(application);
5851
+ if (!extension || typeof extension.id !== 'string' || !extension.id || typeof extension.browser !== 'string' || extension.isolated !== true) {
5852
+ throw new Error('Expected an isolated web extension');
5853
+ }
5854
+ const applicationId = application.applicationId;
5855
+ const current = get$7(applicationId);
5856
+ if (current.webExtensions.every(({
5857
+ id
5858
+ }) => id !== extensionId)) {
5859
+ throw new Error(`Application extension not found: ${extensionId}`);
5860
+ }
5861
+ if (extension.id !== extensionId && current.webExtensions.some(({
5862
+ id
5863
+ }) => id === extension.id)) {
5864
+ throw new Error(`Duplicate application extension: ${extension.id}`);
5865
+ }
5866
+ // Finish pending startup before removing its RPC, including failed activations.
5867
+ try {
5868
+ await waitForExtensionActivations(current);
5869
+ } catch {
5870
+ // Failed startup must still allow replacing the broken extension.
5871
+ }
5872
+ assertCurrentApplication(application);
5873
+ const rpc = remove$1(extensionId, applicationId);
5874
+ unregister(extensionId, applicationId);
5875
+ const results = await Promise.allSettled([disposeExtension(application, extensionId), Promise.try(() => rpc?.dispose()), invoke('LaunchIsolatedExtensionHostWorker.disposeIsolatedExtensionHostWorker', getRuntimeId(extensionId, application))]);
5876
+ assertCurrentApplication(application);
5877
+ resetExtensionActivation(extensionId, application);
5878
+ resetExtensionRuntimeState(extensionId, applicationId);
5879
+ const errors = results.filter(result => result.status === 'rejected').map(result => result.reason);
5880
+ if (errors.length > 0) throw new AggregateError(errors, `Failed to reload extension ${extensionId}`);
5881
+ update({
5882
+ cachedExtensions: undefined,
5883
+ webExtensions: get$7(applicationId).webExtensions.map(previous => previous.id === extensionId ? {
5884
+ ...extension
5885
+ } : previous)
5886
+ }, applicationId);
5887
+ };
5888
+ const run = async (previous, application, extensionId, extension) => {
5889
+ try {
5890
+ await previous;
5891
+ } catch {
5892
+ // A later save can recover from an earlier reload failure.
5893
+ }
5894
+ await replace(application, extensionId, extension);
5895
+ };
5896
+ const reloadApplicationExtension = async (applicationId, extensionId, extension) => {
5897
+ const application = get$7(applicationId);
5898
+ const key = application.applicationGeneration;
5899
+ const previous = queues.get(key) || Promise.resolve();
5900
+ const operation = run(previous, application, extensionId, extension);
5901
+ queues.set(key, operation);
5902
+ try {
5903
+ await operation;
5904
+ } finally {
5905
+ if (queues.get(key) === operation) queues.delete(key);
5906
+ }
5907
+ };
5908
+
5719
5909
  const sendMessagePortToElectron = async (port, initialCommand) => {
5720
5910
  await invokeAndTransfer$1('SendMessagePortToElectron.sendMessagePortToElectron', port, initialCommand, EmbedsWorker);
5721
5911
  };
@@ -5784,10 +5974,16 @@ const invokeForApplication = async (applicationId, method, ...args) => {
5784
5974
  return invoke('Application.execute', applicationId, 'FileSystem.readFile', ...args);
5785
5975
  case 'Extensions.activateByEvent':
5786
5976
  return activateByEvent(args[0], args[1], args[2] ?? application.platform, application);
5977
+ case 'Extensions.createWebViewWorkerRpc':
5978
+ return createWorker$1(application, args[0], args[1], true);
5979
+ case 'Extensions.createWebViewWorkerRpc2':
5980
+ return createWorker$1(application, args[0], args[1]);
5787
5981
  case 'Extensions.getAllExtensions':
5788
5982
  return getAllExtensionsWithState(application, args[0] || '', args[1] ?? application.platform);
5789
5983
  case 'Extensions.getDynamicWebExtensions':
5790
5984
  return application.webExtensions;
5985
+ case 'Extensions.getRpcInfo':
5986
+ return getRpcInfo$1(application, args[0]);
5791
5987
  case 'Extensions.getRuntimeStatus':
5792
5988
  return getRuntimeStatus$1(args[0], applicationId);
5793
5989
  case 'Extensions.getStatusBarItems':
@@ -5799,6 +5995,8 @@ const invokeForApplication = async (applicationId, method, ...args) => {
5799
5995
  }
5800
5996
  case 'Extensions.handleFileChanges':
5801
5997
  return handleFileChanges(args[0], applicationId);
5998
+ case 'Extensions.sendMessagePortToFileSystemWorker':
5999
+ return createFileSystemPort(application, args[0]);
5802
6000
  default:
5803
6001
  throw new Error(`Extension command does not support application context: ${method}`);
5804
6002
  }
@@ -5897,6 +6095,7 @@ const commandMap = {
5897
6095
  'Extensions.invalidateExtensionsCache': invalidateExtensionsCache,
5898
6096
  'Extensions.invokeForApplication': invokeForApplication,
5899
6097
  'Extensions.readOutputChannel': wrapCommand(readOutputChannel),
6098
+ 'Extensions.reloadApplicationExtension': reloadApplicationExtension,
5900
6099
  'Extensions.renderViewInstance': renderViewInstance,
5901
6100
  'Extensions.requestViewRerender': requestViewRerender,
5902
6101
  'Extensions.saveViewInstanceState': saveViewInstanceState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/extension-management-worker",
3
- "version": "4.72.1",
3
+ "version": "4.74.0",
4
4
  "description": "Webworker for the Extension Management functionality in Lvce Editor.",
5
5
  "keywords": [
6
6
  "web-worker"