@theia/core 1.77.0-next.1 → 1.77.0-next.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"backend-application-module.d.ts","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAwB,MAAM,WAAW,CAAC;AAgElE,eAAO,MAAM,wBAAwB,iBAqGnC,CAAC"}
1
+ {"version":3,"file":"backend-application-module.d.ts","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAwB,MAAM,WAAW,CAAC;AAiElE,eAAO,MAAM,wBAAwB,iBAwGnC,CAAC"}
@@ -40,6 +40,7 @@ const performance_1 = require("./performance");
40
40
  const os_backend_provider_1 = require("./os-backend-provider");
41
41
  const backend_request_facade_1 = require("./request/backend-request-facade");
42
42
  const filesystem_locking_1 = require("./filesystem-locking");
43
+ const bundled_resource_provider_1 = require("./bundled-resource-provider");
43
44
  const backend_remote_service_1 = require("./remote/backend-remote-service");
44
45
  const remote_cli_contribution_1 = require("./remote/remote-cli-contribution");
45
46
  const setting_service_1 = require("./setting-service");
@@ -115,6 +116,8 @@ exports.backendApplicationModule = new inversify_1.ContainerModule(bind => {
115
116
  (0, performance_1.bindNodeStopwatch)(bind);
116
117
  (0, performance_1.bindBackendStopwatchServer)(bind);
117
118
  bind(filesystem_locking_1.FileSystemLocking).to(filesystem_locking_1.FileSystemLockingImpl).inSingletonScope();
119
+ bind(bundled_resource_provider_1.BundledResourceProviderImpl).toSelf().inSingletonScope();
120
+ bind(bundled_resource_provider_1.BundledResourceProvider).toService(bundled_resource_provider_1.BundledResourceProviderImpl);
118
121
  bind(setting_service_1.SettingServiceImpl).toSelf().inSingletonScope();
119
122
  bind(setting_service_1.SettingService).toService(setting_service_1.SettingServiceImpl);
120
123
  (0, common_1.bindPreferenceConfigurations)(bind);
@@ -1 +1 @@
1
- {"version":3,"file":"backend-application-module.js","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backend-application-module.js","sourceRoot":"","sources":["../../src/node/backend-application-module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import * as fs from 'fs';
2
+ import { interfaces } from 'inversify';
3
+ import { EnvVariablesServer } from '../common/env-variables';
4
+ import { ILogger } from '../common/logger';
5
+ import { FileSystemLocking } from './filesystem-locking';
6
+ export declare const BundledResourceProvider: symbol & interfaces.Abstract<BundledResourceProvider>;
7
+ /**
8
+ * Provides paths to resources that are bundled with the application, in a form that can also be used by
9
+ * processes which do not run inside the application, such as shells, debug adapters or other external tools.
10
+ *
11
+ * When an Electron application is packaged with `asar: true`, the resources of the application are stored in
12
+ * an `app.asar` archive. Paths pointing into such an archive can only be read through Electron's patched `fs`
13
+ * module, so handing them to an external process fails. Therefore, always resolve a bundled resource through
14
+ * this service before passing its path to a process outside of the application.
15
+ */
16
+ export interface BundledResourceProvider {
17
+ /**
18
+ * Resolve the given path of a bundled file or directory to a path that external processes can read.
19
+ *
20
+ * If the resource is not packaged into an archive, its path is returned unchanged. Otherwise the copy that
21
+ * the packaging step has left outside of the archive is used, if it is complete, and the resource is
22
+ * extracted from the archive into the configuration directory as a last resort.
23
+ *
24
+ * Results are cached, so that a resource is extracted at most once per application version.
25
+ *
26
+ * @param resourcePath the path of the bundled resource, typically resolved against `__dirname`.
27
+ * @returns the path to use outside of the application.
28
+ * @throws if the resource does not exist or cannot be made available.
29
+ */
30
+ resolveExternalPath(resourcePath: string): Promise<string>;
31
+ }
32
+ export declare class BundledResourceProviderImpl implements BundledResourceProvider {
33
+ protected readonly logger: ILogger;
34
+ protected readonly envVariablesServer: EnvVariablesServer;
35
+ protected readonly fileSystemLocking: FileSystemLocking;
36
+ /** The folder within the configuration directory into which resources are extracted. */
37
+ protected readonly extractionFolder = "bundled-resources";
38
+ /** Resources extracted for another application version are removed when they are older than this. */
39
+ protected readonly staleExtractionAge: number;
40
+ protected readonly resolved: Map<string, Promise<string>>;
41
+ protected temporaryExtractionPath: Promise<string> | undefined;
42
+ resolveExternalPath(resourcePath: string): Promise<string>;
43
+ protected doResolveExternalPath(resourcePath: string): Promise<string>;
44
+ /**
45
+ * Find the archive that the given resource is packaged into, if any.
46
+ *
47
+ * @returns the path of the archive, i.e. the shortest prefix of the given path ending in an `.asar` segment,
48
+ * which is also how Electron itself determines the archive that a path refers to.
49
+ */
50
+ protected findArchivePath(resourcePath: string): string | undefined;
51
+ /**
52
+ * Whether every file of the given resource is already available at the given target path. Packaging tools
53
+ * only unpack the files that the application configured them to unpack, so a partial copy must be ignored.
54
+ */
55
+ protected isExtracted(resourcePath: string, targetPath: string): Promise<boolean>;
56
+ protected extract(resourcePath: string, targetPath: string): Promise<void>;
57
+ /**
58
+ * Collect the files of the given resource as paths relative to it. The relative path of a resource that is
59
+ * a plain file is the empty string.
60
+ */
61
+ protected collectFiles(resourcePath: string, relativePath?: string): Promise<string[]>;
62
+ protected copyFile(sourcePath: string, targetPath: string): Promise<void>;
63
+ protected isUpToDate(targetPath: string, sourceStat: fs.Stats): Promise<boolean>;
64
+ /**
65
+ * The directory into which resources of the given archive are extracted. It is specific to the content of
66
+ * the archive, so that updating the application invalidates previously extracted copies.
67
+ */
68
+ protected getExtractionPath(archivePath: string): Promise<string>;
69
+ /**
70
+ * Fallback for applications whose configuration directory cannot be written to. The directory is unique to
71
+ * this run of the application, so that resources are extracted again whenever the application is started.
72
+ */
73
+ protected getTemporaryExtractionPath(): Promise<string>;
74
+ /**
75
+ * Identify the content of the given archive. `process.noAsar` is toggled around the synchronous `stat` call
76
+ * to get the stats of the archive file itself rather than of the directory that it appears as.
77
+ */
78
+ protected getArchiveStamp(archivePath: string): string;
79
+ /**
80
+ * Remove resources that were extracted from an earlier version of the archive, unless they were used
81
+ * recently, because another application instance may still be running on that version.
82
+ */
83
+ protected removeStaleExtractions(extractionRoot: string, prefix: string, currentPath: string): void;
84
+ protected exists(targetPath: string): Promise<boolean>;
85
+ }
86
+ //# sourceMappingURL=bundled-resource-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundled-resource-provider.d.ts","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAGzB,OAAO,EAAsB,UAAU,EAAS,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,eAAO,MAAM,uBAAuB,EAAwC,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;AAClI;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9D;AAED,qBACa,2BAA4B,YAAW,uBAAuB;IAGvE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAGnC,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAG1D,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAExD,wFAAwF;IACxF,SAAS,CAAC,QAAQ,CAAC,gBAAgB,uBAAuB;IAE1D,qGAAqG;IACrG,SAAS,CAAC,QAAQ,CAAC,kBAAkB,SAA2B;IAEhE,SAAS,CAAC,QAAQ,CAAC,QAAQ,+BAAsC;IACjE,SAAS,CAAC,uBAAuB,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAEzD,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;cAmBhD,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB5E;;;;;OAKG;IACH,SAAS,CAAC,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMnE;;;OAGG;cACa,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;cASvE,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhF;;;OAGG;cACa,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;cAYhF,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAyB/D,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAQtF;;;OAGG;cACa,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcvE;;;OAGG;IACH,SAAS,CAAC,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvD;;;OAGG;IACH,SAAS,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAYtD;;;OAGG;IACH,SAAS,CAAC,sBAAsB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;cAiBnF,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAS/D"}
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 EclipseSource GmbH and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.BundledResourceProviderImpl = exports.BundledResourceProvider = void 0;
19
+ const tslib_1 = require("tslib");
20
+ const crypto = require("crypto");
21
+ const fs = require("fs");
22
+ const os = require("os");
23
+ const path = require("path");
24
+ const inversify_1 = require("inversify");
25
+ const env_variables_1 = require("../common/env-variables");
26
+ const file_uri_1 = require("../common/file-uri");
27
+ const logger_1 = require("../common/logger");
28
+ const filesystem_locking_1 = require("./filesystem-locking");
29
+ exports.BundledResourceProvider = Symbol('BundledResourceProvider');
30
+ let BundledResourceProviderImpl = class BundledResourceProviderImpl {
31
+ constructor() {
32
+ /** The folder within the configuration directory into which resources are extracted. */
33
+ this.extractionFolder = 'bundled-resources';
34
+ /** Resources extracted for another application version are removed when they are older than this. */
35
+ this.staleExtractionAge = 7 * 24 * 60 * 60 * 1000;
36
+ this.resolved = new Map();
37
+ }
38
+ async resolveExternalPath(resourcePath) {
39
+ const normalizedPath = path.resolve(resourcePath);
40
+ const pending = this.resolved.get(normalizedPath);
41
+ if (pending) {
42
+ try {
43
+ const resolvedPath = await pending;
44
+ if (await this.exists(resolvedPath)) {
45
+ return resolvedPath;
46
+ }
47
+ }
48
+ catch {
49
+ // the previous attempt failed, so try again below
50
+ }
51
+ this.resolved.delete(normalizedPath);
52
+ }
53
+ const result = this.doResolveExternalPath(normalizedPath);
54
+ this.resolved.set(normalizedPath, result);
55
+ return result;
56
+ }
57
+ async doResolveExternalPath(resourcePath) {
58
+ if (!await this.exists(resourcePath)) {
59
+ throw new Error(`Bundled resource does not exist: ${resourcePath}`);
60
+ }
61
+ const archivePath = this.findArchivePath(resourcePath);
62
+ if (!archivePath) {
63
+ // The resource is not packaged into an archive, so external processes can read it directly.
64
+ return resourcePath;
65
+ }
66
+ const relativePath = path.relative(archivePath, resourcePath);
67
+ const unpackedPath = path.join(`${archivePath}.unpacked`, relativePath);
68
+ if (await this.isExtracted(resourcePath, unpackedPath)) {
69
+ return unpackedPath;
70
+ }
71
+ const extractionPath = path.join(await this.getExtractionPath(archivePath), relativePath);
72
+ await this.fileSystemLocking.lockPath(archivePath, () => this.extract(resourcePath, extractionPath));
73
+ this.logger.info(`Extracted bundled resource '${resourcePath}' to '${extractionPath}'.`);
74
+ return extractionPath;
75
+ }
76
+ /**
77
+ * Find the archive that the given resource is packaged into, if any.
78
+ *
79
+ * @returns the path of the archive, i.e. the shortest prefix of the given path ending in an `.asar` segment,
80
+ * which is also how Electron itself determines the archive that a path refers to.
81
+ */
82
+ findArchivePath(resourcePath) {
83
+ const segments = resourcePath.split(/[\\/]/);
84
+ const archiveIndex = segments.findIndex(segment => segment.toLowerCase().endsWith('.asar'));
85
+ return archiveIndex < 0 ? undefined : segments.slice(0, archiveIndex + 1).join(path.sep);
86
+ }
87
+ /**
88
+ * Whether every file of the given resource is already available at the given target path. Packaging tools
89
+ * only unpack the files that the application configured them to unpack, so a partial copy must be ignored.
90
+ */
91
+ async isExtracted(resourcePath, targetPath) {
92
+ for (const file of await this.collectFiles(resourcePath)) {
93
+ if (!await this.exists(path.join(targetPath, file))) {
94
+ return false;
95
+ }
96
+ }
97
+ return true;
98
+ }
99
+ async extract(resourcePath, targetPath) {
100
+ for (const file of await this.collectFiles(resourcePath)) {
101
+ await this.copyFile(path.join(resourcePath, file), path.join(targetPath, file));
102
+ }
103
+ }
104
+ /**
105
+ * Collect the files of the given resource as paths relative to it. The relative path of a resource that is
106
+ * a plain file is the empty string.
107
+ */
108
+ async collectFiles(resourcePath, relativePath = '') {
109
+ const currentPath = path.join(resourcePath, relativePath);
110
+ if (!(await fs.promises.stat(currentPath)).isDirectory()) {
111
+ return [relativePath];
112
+ }
113
+ const files = [];
114
+ for (const entry of await fs.promises.readdir(currentPath)) {
115
+ files.push(...await this.collectFiles(resourcePath, path.join(relativePath, entry)));
116
+ }
117
+ return files;
118
+ }
119
+ async copyFile(sourcePath, targetPath) {
120
+ const sourceStat = await fs.promises.stat(sourcePath);
121
+ if (await this.isUpToDate(targetPath, sourceStat)) {
122
+ return;
123
+ }
124
+ await fs.promises.mkdir(path.dirname(targetPath), { recursive: true, mode: 0o700 });
125
+ // Write to a temporary file and move it into place, so that a concurrently starting application
126
+ // instance never reads partially written content.
127
+ const temporaryPath = `${targetPath}.${process.pid}.tmp`;
128
+ try {
129
+ // Electron reports the files of an asar archive as not executable, even those that the archive marks as
130
+ // executable, so every extracted file is made executable for the owner to keep bundled executables usable.
131
+ await fs.promises.writeFile(temporaryPath, await fs.promises.readFile(sourcePath), { mode: sourceStat.mode & 0o777 | 0o700 });
132
+ try {
133
+ await fs.promises.rename(temporaryPath, targetPath);
134
+ }
135
+ catch {
136
+ // renaming onto an existing file is not supported on all platforms
137
+ await fs.promises.rm(targetPath, { force: true });
138
+ await fs.promises.rename(temporaryPath, targetPath);
139
+ }
140
+ }
141
+ finally {
142
+ await fs.promises.rm(temporaryPath, { force: true });
143
+ }
144
+ }
145
+ async isUpToDate(targetPath, sourceStat) {
146
+ try {
147
+ return (await fs.promises.stat(targetPath)).size === sourceStat.size;
148
+ }
149
+ catch {
150
+ return false;
151
+ }
152
+ }
153
+ /**
154
+ * The directory into which resources of the given archive are extracted. It is specific to the content of
155
+ * the archive, so that updating the application invalidates previously extracted copies.
156
+ */
157
+ async getExtractionPath(archivePath) {
158
+ const archiveName = path.basename(archivePath, path.extname(archivePath));
159
+ try {
160
+ const extractionRoot = path.join(file_uri_1.FileUri.fsPath(await this.envVariablesServer.getConfigDirUri()), this.extractionFolder);
161
+ const extractionPath = path.join(extractionRoot, `${archiveName}-${this.getArchiveStamp(archivePath)}`);
162
+ await fs.promises.mkdir(extractionPath, { recursive: true, mode: 0o700 });
163
+ this.removeStaleExtractions(extractionRoot, `${archiveName}-`, extractionPath);
164
+ return extractionPath;
165
+ }
166
+ catch (error) {
167
+ this.logger.warn('Could not extract bundled resources into the configuration directory, using a temporary directory instead.', error);
168
+ return this.getTemporaryExtractionPath();
169
+ }
170
+ }
171
+ /**
172
+ * Fallback for applications whose configuration directory cannot be written to. The directory is unique to
173
+ * this run of the application, so that resources are extracted again whenever the application is started.
174
+ */
175
+ getTemporaryExtractionPath() {
176
+ return this.temporaryExtractionPath ??= fs.promises.mkdtemp(path.join(os.tmpdir(), 'theia-bundled-resources-'));
177
+ }
178
+ /**
179
+ * Identify the content of the given archive. `process.noAsar` is toggled around the synchronous `stat` call
180
+ * to get the stats of the archive file itself rather than of the directory that it appears as.
181
+ */
182
+ getArchiveStamp(archivePath) {
183
+ const asarProcess = process;
184
+ const noAsar = asarProcess.noAsar;
185
+ try {
186
+ asarProcess.noAsar = true;
187
+ const stat = fs.statSync(archivePath);
188
+ return crypto.createHash('sha256').update(`${archivePath}:${stat.size}:${stat.mtimeMs}`).digest('hex').substring(0, 12);
189
+ }
190
+ finally {
191
+ asarProcess.noAsar = noAsar;
192
+ }
193
+ }
194
+ /**
195
+ * Remove resources that were extracted from an earlier version of the archive, unless they were used
196
+ * recently, because another application instance may still be running on that version.
197
+ */
198
+ removeStaleExtractions(extractionRoot, prefix, currentPath) {
199
+ const removeStale = async () => {
200
+ for (const entry of await fs.promises.readdir(extractionRoot)) {
201
+ const entryPath = path.join(extractionRoot, entry);
202
+ if (!entry.startsWith(prefix) || entryPath === currentPath) {
203
+ continue;
204
+ }
205
+ const stat = await fs.promises.stat(entryPath);
206
+ if (Date.now() - stat.mtimeMs > this.staleExtractionAge) {
207
+ await fs.promises.rm(entryPath, { recursive: true, force: true });
208
+ this.logger.info(`Removed stale extracted resources: ${entryPath}`);
209
+ }
210
+ }
211
+ };
212
+ removeStale().catch(error => this.logger.warn(`Could not remove stale extracted resources in '${extractionRoot}'.`, error));
213
+ }
214
+ async exists(targetPath) {
215
+ try {
216
+ await fs.promises.stat(targetPath);
217
+ return true;
218
+ }
219
+ catch {
220
+ return false;
221
+ }
222
+ }
223
+ };
224
+ exports.BundledResourceProviderImpl = BundledResourceProviderImpl;
225
+ tslib_1.__decorate([
226
+ (0, inversify_1.inject)(logger_1.ILogger),
227
+ (0, inversify_1.named)('core:BundledResourceProviderImpl'),
228
+ tslib_1.__metadata("design:type", Object)
229
+ ], BundledResourceProviderImpl.prototype, "logger", void 0);
230
+ tslib_1.__decorate([
231
+ (0, inversify_1.inject)(env_variables_1.EnvVariablesServer),
232
+ tslib_1.__metadata("design:type", Object)
233
+ ], BundledResourceProviderImpl.prototype, "envVariablesServer", void 0);
234
+ tslib_1.__decorate([
235
+ (0, inversify_1.inject)(filesystem_locking_1.FileSystemLocking),
236
+ tslib_1.__metadata("design:type", Object)
237
+ ], BundledResourceProviderImpl.prototype, "fileSystemLocking", void 0);
238
+ exports.BundledResourceProviderImpl = BundledResourceProviderImpl = tslib_1.__decorate([
239
+ (0, inversify_1.injectable)()
240
+ ], BundledResourceProviderImpl);
241
+ //# sourceMappingURL=bundled-resource-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundled-resource-provider.js","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import 'reflect-metadata';
2
+ //# sourceMappingURL=bundled-resource-provider.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundled-resource-provider.spec.d.ts","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.spec.ts"],"names":[],"mappings":"AAgBA,OAAO,kBAAkB,CAAC"}
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 EclipseSource GmbH and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ require("reflect-metadata");
19
+ const chai_1 = require("chai");
20
+ const fs = require("fs");
21
+ const os = require("os");
22
+ const path = require("path");
23
+ const temp = require("temp");
24
+ const inversify_1 = require("inversify");
25
+ const env_variables_1 = require("../common/env-variables");
26
+ const logger_1 = require("../common/logger");
27
+ const mock_logger_1 = require("../common/test/mock-logger");
28
+ const file_uri_1 = require("../common/file-uri");
29
+ const bundled_resource_provider_1 = require("./bundled-resource-provider");
30
+ const filesystem_locking_1 = require("./filesystem-locking");
31
+ /**
32
+ * The provider recognizes archives by their `.asar` path segment and reads them through `fs`, which Electron
33
+ * patches to transparently read from the archive. Plain directories named `*.asar` therefore behave like
34
+ * archives from the point of view of the provider and let us test it outside of Electron.
35
+ */
36
+ describe('BundledResourceProvider', () => {
37
+ const track = temp.track();
38
+ let configDir;
39
+ let appDir;
40
+ let provider;
41
+ beforeEach(() => {
42
+ const root = track.mkdirSync();
43
+ configDir = path.join(root, 'config');
44
+ appDir = path.join(root, 'app');
45
+ fs.mkdirSync(configDir);
46
+ fs.mkdirSync(appDir);
47
+ provider = createProvider();
48
+ });
49
+ /** Each provider instance stands for one run of the application, as resolved paths are cached. */
50
+ function createProvider() {
51
+ const container = new inversify_1.Container();
52
+ container.bind(logger_1.ILogger).toConstantValue(new mock_logger_1.MockLogger());
53
+ container.bind(filesystem_locking_1.FileSystemLocking).to(filesystem_locking_1.FileSystemLockingImpl).inSingletonScope();
54
+ container.bind(env_variables_1.EnvVariablesServer).toConstantValue({
55
+ getConfigDirUri: async () => file_uri_1.FileUri.create(configDir).toString()
56
+ });
57
+ container.bind(bundled_resource_provider_1.BundledResourceProviderImpl).toSelf().inSingletonScope();
58
+ container.bind(bundled_resource_provider_1.BundledResourceProvider).toService(bundled_resource_provider_1.BundledResourceProviderImpl);
59
+ return container.get(bundled_resource_provider_1.BundledResourceProvider);
60
+ }
61
+ afterEach(() => track.cleanupSync());
62
+ /**
63
+ * Assert that the given path is nested in the given directory. The provider derives the configuration
64
+ * directory from a URI, which on Windows yields a lower-case drive letter, so the paths cannot simply be
65
+ * compared by prefix. `path.relative` ignores the case of a path on Windows.
66
+ */
67
+ function expectNestedIn(directoryPath, nestedPath) {
68
+ const relativePath = path.relative(directoryPath, nestedPath);
69
+ (0, chai_1.expect)(relativePath).to.not.be.empty;
70
+ (0, chai_1.expect)(relativePath.split(path.sep)).to.not.contain('..');
71
+ }
72
+ function writeResources(rootPath, files) {
73
+ for (const [relativePath, content] of Object.entries(files)) {
74
+ const filePath = path.join(rootPath, relativePath);
75
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
76
+ fs.writeFileSync(filePath, content);
77
+ }
78
+ return rootPath;
79
+ }
80
+ it('returns the path of a resource that is not packaged into an archive', async () => {
81
+ const resourcePath = path.join(writeResources(appDir, { 'scripts/greet.sh': 'echo hello' }), 'scripts');
82
+ (0, chai_1.expect)(await provider.resolveExternalPath(resourcePath)).to.equal(resourcePath);
83
+ });
84
+ it('rejects for a resource that does not exist', async () => {
85
+ const resourcePath = path.join(appDir, 'scripts');
86
+ await provider.resolveExternalPath(resourcePath).then(() => chai_1.expect.fail('should have been rejected'), error => (0, chai_1.expect)(String(error)).to.contain(resourcePath));
87
+ });
88
+ it('extracts a packaged resource into the configuration directory', async () => {
89
+ const archivePath = path.join(appDir, 'app.asar');
90
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/nested/.hidden': 'secret' });
91
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
92
+ (0, chai_1.expect)(resolvedPath).to.not.contain('.asar');
93
+ expectNestedIn(configDir, resolvedPath);
94
+ (0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
95
+ (0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'nested', '.hidden'), 'utf8')).to.equal('secret');
96
+ });
97
+ it('extracts a packaged resource that is a plain file', async () => {
98
+ const archivePath = path.join(appDir, 'app.asar');
99
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
100
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts', 'greet.sh'));
101
+ expectNestedIn(configDir, resolvedPath);
102
+ (0, chai_1.expect)(fs.readFileSync(resolvedPath, 'utf8')).to.equal('echo hello');
103
+ });
104
+ it('extracts a packaged file as executable', async function () {
105
+ if (process.platform === 'win32') {
106
+ this.skip();
107
+ }
108
+ // Electron reports the files of an asar archive with this mode, even executables.
109
+ const archivePath = path.join(appDir, 'app.asar');
110
+ writeResources(archivePath, { 'native/tool': 'binary' });
111
+ fs.chmodSync(path.join(archivePath, 'native', 'tool'), 0o644);
112
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'native', 'tool'));
113
+ (0, chai_1.expect)(fs.statSync(resolvedPath).mode & 0o700).to.equal(0o700);
114
+ });
115
+ it('prefers the copy that the packaging step has left outside of the archive', async () => {
116
+ const archivePath = path.join(appDir, 'app.asar');
117
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
118
+ const unpackedPath = writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
119
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
120
+ (0, chai_1.expect)(resolvedPath).to.equal(path.join(unpackedPath, 'scripts'));
121
+ });
122
+ it('extracts a packaged resource that was only unpacked partially', async () => {
123
+ const archivePath = path.join(appDir, 'app.asar');
124
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/farewell.sh': 'echo bye' });
125
+ writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
126
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
127
+ expectNestedIn(configDir, resolvedPath);
128
+ (0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'farewell.sh'), 'utf8')).to.equal('echo bye');
129
+ });
130
+ it('re-extracts a resource that was removed from the configuration directory', async () => {
131
+ const archivePath = path.join(appDir, 'app.asar');
132
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
133
+ const resourcePath = path.join(archivePath, 'scripts');
134
+ const resolvedPath = await provider.resolveExternalPath(resourcePath);
135
+ fs.rmSync(resolvedPath, { recursive: true });
136
+ (0, chai_1.expect)(await provider.resolveExternalPath(resourcePath)).to.equal(resolvedPath);
137
+ (0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
138
+ });
139
+ it('extracts into a temporary directory if the configuration directory cannot be written to', async () => {
140
+ const archivePath = path.join(appDir, 'app.asar');
141
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
142
+ // a configuration directory that is a regular file cannot hold the extracted resources
143
+ configDir = path.join(appDir, 'not-a-directory');
144
+ fs.writeFileSync(configDir, '');
145
+ const resolvedPath = await createProvider().resolveExternalPath(path.join(archivePath, 'scripts'));
146
+ expectNestedIn(os.tmpdir(), resolvedPath);
147
+ (0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
148
+ fs.rmSync(resolvedPath, { recursive: true, force: true });
149
+ });
150
+ it('updates an extracted resource when the application has been updated', async () => {
151
+ const archivePath = path.join(appDir, 'app.asar');
152
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
153
+ const resourcePath = path.join(archivePath, 'scripts');
154
+ await provider.resolveExternalPath(resourcePath);
155
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello again' });
156
+ const resolvedPath = await createProvider().resolveExternalPath(resourcePath);
157
+ (0, chai_1.expect)(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello again');
158
+ });
159
+ });
160
+ //# sourceMappingURL=bundled-resource-provider.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundled-resource-provider.spec.js","sourceRoot":"","sources":["../../src/node/bundled-resource-provider.spec.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ export * from './messaging';
6
6
  export * from './cli';
7
7
  export * from './setting-service';
8
8
  export { FileSystemLocking } from './filesystem-locking';
9
+ export { BundledResourceProvider } from './bundled-resource-provider';
9
10
  export { BackendRequestAllowedContribution } from './request/backend-request-facade';
10
11
  export { HttpConnectionValidator } from './hosting/browser-connection-token';
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":"AAgBA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,OAAO,CAAC;AACtB,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,iCAAiC,EAAE,MAAM,kCAAkC,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC"}
package/lib/node/index.js CHANGED
@@ -15,7 +15,7 @@
15
15
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
16
  // *****************************************************************************
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.HttpConnectionValidator = exports.BackendRequestAllowedContribution = exports.FileSystemLocking = void 0;
18
+ exports.HttpConnectionValidator = exports.BackendRequestAllowedContribution = exports.BundledResourceProvider = exports.FileSystemLocking = void 0;
19
19
  const tslib_1 = require("tslib");
20
20
  tslib_1.__exportStar(require("./backend-application"), exports);
21
21
  tslib_1.__exportStar(require("./backend-global"), exports);
@@ -26,6 +26,8 @@ tslib_1.__exportStar(require("./cli"), exports);
26
26
  tslib_1.__exportStar(require("./setting-service"), exports);
27
27
  var filesystem_locking_1 = require("./filesystem-locking");
28
28
  Object.defineProperty(exports, "FileSystemLocking", { enumerable: true, get: function () { return filesystem_locking_1.FileSystemLocking; } });
29
+ var bundled_resource_provider_1 = require("./bundled-resource-provider");
30
+ Object.defineProperty(exports, "BundledResourceProvider", { enumerable: true, get: function () { return bundled_resource_provider_1.BundledResourceProvider; } });
29
31
  var backend_request_facade_1 = require("./request/backend-request-facade");
30
32
  Object.defineProperty(exports, "BackendRequestAllowedContribution", { enumerable: true, get: function () { return backend_request_facade_1.BackendRequestAllowedContribution; } });
31
33
  var browser_connection_token_1 = require("./hosting/browser-connection-token");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAEhF,gEAAsC;AACtC,2DAAiC;AACjC,kDAAwB;AACxB,6DAAmC;AACnC,sDAA4B;AAC5B,gDAAsB;AACtB,4DAAkC;AAClC,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,2EAAqF;AAA5E,2IAAA,iCAAiC,OAAA;AAC1C,+EAA6E;AAApE,mIAAA,uBAAuB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/node/index.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;AAEhF,gEAAsC;AACtC,2DAAiC;AACjC,kDAAwB;AACxB,6DAAmC;AACnC,sDAA4B;AAC5B,gDAAsB;AACtB,4DAAkC;AAClC,2DAAyD;AAAhD,uHAAA,iBAAiB,OAAA;AAC1B,yEAAsE;AAA7D,oIAAA,uBAAuB,OAAA;AAChC,2EAAqF;AAA5E,2IAAA,iCAAiC,OAAA;AAC1C,+EAA6E;AAApE,mIAAA,uBAAuB,OAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theia/core",
3
- "version": "1.77.0-next.1+8b94967c4",
3
+ "version": "1.77.0-next.4+4f24ee401",
4
4
  "description": "Theia is a cloud & desktop IDE framework implemented in TypeScript.",
5
5
  "main": "lib/common/index.js",
6
6
  "typings": "lib/common/index.d.ts",
@@ -17,8 +17,8 @@
17
17
  "@lumino/virtualdom": "^2.0.5",
18
18
  "@lumino/widgets": "2.7.5",
19
19
  "@parcel/watcher": "^2.6.0",
20
- "@theia/application-package": "1.77.0-next.1+8b94967c4",
21
- "@theia/request": "1.77.0-next.1+8b94967c4",
20
+ "@theia/application-package": "1.77.0-next.4+4f24ee401",
21
+ "@theia/request": "1.77.0-next.4+4f24ee401",
22
22
  "@types/body-parser": "^1.19.6",
23
23
  "@types/express": "^4.17.25",
24
24
  "@types/fs-extra": "^4.0.15",
@@ -233,5 +233,5 @@
233
233
  "nyc": {
234
234
  "extends": "../../configs/nyc.json"
235
235
  },
236
- "gitHead": "8b94967c4cfa0dcf688a345d28b3ac2e0d7e298a"
236
+ "gitHead": "4f24ee40105b8c53808c8293c41387304d15960c"
237
237
  }
@@ -57,6 +57,7 @@ import { bindNodeStopwatch, bindBackendStopwatchServer } from './performance';
57
57
  import { OSBackendProviderImpl } from './os-backend-provider';
58
58
  import { BackendRequestFacade, BackendRequestAllowedContribution } from './request/backend-request-facade';
59
59
  import { FileSystemLocking, FileSystemLockingImpl } from './filesystem-locking';
60
+ import { BundledResourceProvider, BundledResourceProviderImpl } from './bundled-resource-provider';
60
61
  import { BackendRemoteService } from './remote/backend-remote-service';
61
62
  import { RemoteCliContribution } from './remote/remote-cli-contribution';
62
63
  import { SettingService, SettingServiceImpl } from './setting-service';
@@ -164,6 +165,9 @@ export const backendApplicationModule = new ContainerModule(bind => {
164
165
 
165
166
  bind(FileSystemLocking).to(FileSystemLockingImpl).inSingletonScope();
166
167
 
168
+ bind(BundledResourceProviderImpl).toSelf().inSingletonScope();
169
+ bind(BundledResourceProvider).toService(BundledResourceProviderImpl);
170
+
167
171
  bind(SettingServiceImpl).toSelf().inSingletonScope();
168
172
  bind(SettingService).toService(SettingServiceImpl);
169
173
 
@@ -0,0 +1,196 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 EclipseSource GmbH and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import 'reflect-metadata';
18
+ import { expect } from 'chai';
19
+ import * as fs from 'fs';
20
+ import * as os from 'os';
21
+ import * as path from 'path';
22
+ import * as temp from 'temp';
23
+ import { Container } from 'inversify';
24
+ import { EnvVariablesServer } from '../common/env-variables';
25
+ import { ILogger } from '../common/logger';
26
+ import { MockLogger } from '../common/test/mock-logger';
27
+ import { FileUri } from '../common/file-uri';
28
+ import { BundledResourceProvider, BundledResourceProviderImpl } from './bundled-resource-provider';
29
+ import { FileSystemLocking, FileSystemLockingImpl } from './filesystem-locking';
30
+
31
+ /**
32
+ * The provider recognizes archives by their `.asar` path segment and reads them through `fs`, which Electron
33
+ * patches to transparently read from the archive. Plain directories named `*.asar` therefore behave like
34
+ * archives from the point of view of the provider and let us test it outside of Electron.
35
+ */
36
+ describe('BundledResourceProvider', () => {
37
+
38
+ const track = temp.track();
39
+
40
+ let configDir: string;
41
+ let appDir: string;
42
+ let provider: BundledResourceProvider;
43
+
44
+ beforeEach(() => {
45
+ const root = track.mkdirSync();
46
+ configDir = path.join(root, 'config');
47
+ appDir = path.join(root, 'app');
48
+ fs.mkdirSync(configDir);
49
+ fs.mkdirSync(appDir);
50
+ provider = createProvider();
51
+ });
52
+
53
+ /** Each provider instance stands for one run of the application, as resolved paths are cached. */
54
+ function createProvider(): BundledResourceProvider {
55
+ const container = new Container();
56
+ container.bind(ILogger).toConstantValue(new MockLogger());
57
+ container.bind(FileSystemLocking).to(FileSystemLockingImpl).inSingletonScope();
58
+ container.bind(EnvVariablesServer).toConstantValue({
59
+ getConfigDirUri: async () => FileUri.create(configDir).toString()
60
+ } as unknown as EnvVariablesServer);
61
+ container.bind(BundledResourceProviderImpl).toSelf().inSingletonScope();
62
+ container.bind(BundledResourceProvider).toService(BundledResourceProviderImpl);
63
+ return container.get(BundledResourceProvider);
64
+ }
65
+
66
+ afterEach(() => track.cleanupSync());
67
+
68
+ /**
69
+ * Assert that the given path is nested in the given directory. The provider derives the configuration
70
+ * directory from a URI, which on Windows yields a lower-case drive letter, so the paths cannot simply be
71
+ * compared by prefix. `path.relative` ignores the case of a path on Windows.
72
+ */
73
+ function expectNestedIn(directoryPath: string, nestedPath: string): void {
74
+ const relativePath = path.relative(directoryPath, nestedPath);
75
+ expect(relativePath).to.not.be.empty;
76
+ expect(relativePath.split(path.sep)).to.not.contain('..');
77
+ }
78
+
79
+ function writeResources(rootPath: string, files: Record<string, string>): string {
80
+ for (const [relativePath, content] of Object.entries(files)) {
81
+ const filePath = path.join(rootPath, relativePath);
82
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
83
+ fs.writeFileSync(filePath, content);
84
+ }
85
+ return rootPath;
86
+ }
87
+
88
+ it('returns the path of a resource that is not packaged into an archive', async () => {
89
+ const resourcePath = path.join(writeResources(appDir, { 'scripts/greet.sh': 'echo hello' }), 'scripts');
90
+ expect(await provider.resolveExternalPath(resourcePath)).to.equal(resourcePath);
91
+ });
92
+
93
+ it('rejects for a resource that does not exist', async () => {
94
+ const resourcePath = path.join(appDir, 'scripts');
95
+ await provider.resolveExternalPath(resourcePath).then(
96
+ () => expect.fail('should have been rejected'),
97
+ error => expect(String(error)).to.contain(resourcePath)
98
+ );
99
+ });
100
+
101
+ it('extracts a packaged resource into the configuration directory', async () => {
102
+ const archivePath = path.join(appDir, 'app.asar');
103
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/nested/.hidden': 'secret' });
104
+
105
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
106
+
107
+ expect(resolvedPath).to.not.contain('.asar');
108
+ expectNestedIn(configDir, resolvedPath);
109
+ expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
110
+ expect(fs.readFileSync(path.join(resolvedPath, 'nested', '.hidden'), 'utf8')).to.equal('secret');
111
+ });
112
+
113
+ it('extracts a packaged resource that is a plain file', async () => {
114
+ const archivePath = path.join(appDir, 'app.asar');
115
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
116
+
117
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts', 'greet.sh'));
118
+
119
+ expectNestedIn(configDir, resolvedPath);
120
+ expect(fs.readFileSync(resolvedPath, 'utf8')).to.equal('echo hello');
121
+ });
122
+
123
+ it('extracts a packaged file as executable', async function (): Promise<void> {
124
+ if (process.platform === 'win32') {
125
+ this.skip();
126
+ }
127
+ // Electron reports the files of an asar archive with this mode, even executables.
128
+ const archivePath = path.join(appDir, 'app.asar');
129
+ writeResources(archivePath, { 'native/tool': 'binary' });
130
+ fs.chmodSync(path.join(archivePath, 'native', 'tool'), 0o644);
131
+
132
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'native', 'tool'));
133
+
134
+ expect(fs.statSync(resolvedPath).mode & 0o700).to.equal(0o700);
135
+ });
136
+
137
+ it('prefers the copy that the packaging step has left outside of the archive', async () => {
138
+ const archivePath = path.join(appDir, 'app.asar');
139
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
140
+ const unpackedPath = writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
141
+
142
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
143
+
144
+ expect(resolvedPath).to.equal(path.join(unpackedPath, 'scripts'));
145
+ });
146
+
147
+ it('extracts a packaged resource that was only unpacked partially', async () => {
148
+ const archivePath = path.join(appDir, 'app.asar');
149
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello', 'scripts/farewell.sh': 'echo bye' });
150
+ writeResources(`${archivePath}.unpacked`, { 'scripts/greet.sh': 'echo hello' });
151
+
152
+ const resolvedPath = await provider.resolveExternalPath(path.join(archivePath, 'scripts'));
153
+
154
+ expectNestedIn(configDir, resolvedPath);
155
+ expect(fs.readFileSync(path.join(resolvedPath, 'farewell.sh'), 'utf8')).to.equal('echo bye');
156
+ });
157
+
158
+ it('re-extracts a resource that was removed from the configuration directory', async () => {
159
+ const archivePath = path.join(appDir, 'app.asar');
160
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
161
+ const resourcePath = path.join(archivePath, 'scripts');
162
+
163
+ const resolvedPath = await provider.resolveExternalPath(resourcePath);
164
+ fs.rmSync(resolvedPath, { recursive: true });
165
+
166
+ expect(await provider.resolveExternalPath(resourcePath)).to.equal(resolvedPath);
167
+ expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
168
+ });
169
+
170
+ it('extracts into a temporary directory if the configuration directory cannot be written to', async () => {
171
+ const archivePath = path.join(appDir, 'app.asar');
172
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
173
+ // a configuration directory that is a regular file cannot hold the extracted resources
174
+ configDir = path.join(appDir, 'not-a-directory');
175
+ fs.writeFileSync(configDir, '');
176
+
177
+ const resolvedPath = await createProvider().resolveExternalPath(path.join(archivePath, 'scripts'));
178
+
179
+ expectNestedIn(os.tmpdir(), resolvedPath);
180
+ expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello');
181
+ fs.rmSync(resolvedPath, { recursive: true, force: true });
182
+ });
183
+
184
+ it('updates an extracted resource when the application has been updated', async () => {
185
+ const archivePath = path.join(appDir, 'app.asar');
186
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello' });
187
+ const resourcePath = path.join(archivePath, 'scripts');
188
+
189
+ await provider.resolveExternalPath(resourcePath);
190
+ writeResources(archivePath, { 'scripts/greet.sh': 'echo hello again' });
191
+ const resolvedPath = await createProvider().resolveExternalPath(resourcePath);
192
+
193
+ expect(fs.readFileSync(path.join(resolvedPath, 'greet.sh'), 'utf8')).to.equal('echo hello again');
194
+ });
195
+
196
+ });
@@ -0,0 +1,266 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 EclipseSource GmbH and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import * as crypto from 'crypto';
18
+ import * as fs from 'fs';
19
+ import * as os from 'os';
20
+ import * as path from 'path';
21
+ import { inject, injectable, interfaces, named } from 'inversify';
22
+ import { EnvVariablesServer } from '../common/env-variables';
23
+ import { FileUri } from '../common/file-uri';
24
+ import { ILogger } from '../common/logger';
25
+ import { FileSystemLocking } from './filesystem-locking';
26
+
27
+ export const BundledResourceProvider = Symbol('BundledResourceProvider') as symbol & interfaces.Abstract<BundledResourceProvider>;
28
+ /**
29
+ * Provides paths to resources that are bundled with the application, in a form that can also be used by
30
+ * processes which do not run inside the application, such as shells, debug adapters or other external tools.
31
+ *
32
+ * When an Electron application is packaged with `asar: true`, the resources of the application are stored in
33
+ * an `app.asar` archive. Paths pointing into such an archive can only be read through Electron's patched `fs`
34
+ * module, so handing them to an external process fails. Therefore, always resolve a bundled resource through
35
+ * this service before passing its path to a process outside of the application.
36
+ */
37
+ export interface BundledResourceProvider {
38
+ /**
39
+ * Resolve the given path of a bundled file or directory to a path that external processes can read.
40
+ *
41
+ * If the resource is not packaged into an archive, its path is returned unchanged. Otherwise the copy that
42
+ * the packaging step has left outside of the archive is used, if it is complete, and the resource is
43
+ * extracted from the archive into the configuration directory as a last resort.
44
+ *
45
+ * Results are cached, so that a resource is extracted at most once per application version.
46
+ *
47
+ * @param resourcePath the path of the bundled resource, typically resolved against `__dirname`.
48
+ * @returns the path to use outside of the application.
49
+ * @throws if the resource does not exist or cannot be made available.
50
+ */
51
+ resolveExternalPath(resourcePath: string): Promise<string>;
52
+ }
53
+
54
+ @injectable()
55
+ export class BundledResourceProviderImpl implements BundledResourceProvider {
56
+
57
+ @inject(ILogger) @named('core:BundledResourceProviderImpl')
58
+ protected readonly logger: ILogger;
59
+
60
+ @inject(EnvVariablesServer)
61
+ protected readonly envVariablesServer: EnvVariablesServer;
62
+
63
+ @inject(FileSystemLocking)
64
+ protected readonly fileSystemLocking: FileSystemLocking;
65
+
66
+ /** The folder within the configuration directory into which resources are extracted. */
67
+ protected readonly extractionFolder = 'bundled-resources';
68
+
69
+ /** Resources extracted for another application version are removed when they are older than this. */
70
+ protected readonly staleExtractionAge = 7 * 24 * 60 * 60 * 1000;
71
+
72
+ protected readonly resolved = new Map<string, Promise<string>>();
73
+ protected temporaryExtractionPath: Promise<string> | undefined;
74
+
75
+ async resolveExternalPath(resourcePath: string): Promise<string> {
76
+ const normalizedPath = path.resolve(resourcePath);
77
+ const pending = this.resolved.get(normalizedPath);
78
+ if (pending) {
79
+ try {
80
+ const resolvedPath = await pending;
81
+ if (await this.exists(resolvedPath)) {
82
+ return resolvedPath;
83
+ }
84
+ } catch {
85
+ // the previous attempt failed, so try again below
86
+ }
87
+ this.resolved.delete(normalizedPath);
88
+ }
89
+ const result = this.doResolveExternalPath(normalizedPath);
90
+ this.resolved.set(normalizedPath, result);
91
+ return result;
92
+ }
93
+
94
+ protected async doResolveExternalPath(resourcePath: string): Promise<string> {
95
+ if (!await this.exists(resourcePath)) {
96
+ throw new Error(`Bundled resource does not exist: ${resourcePath}`);
97
+ }
98
+ const archivePath = this.findArchivePath(resourcePath);
99
+ if (!archivePath) {
100
+ // The resource is not packaged into an archive, so external processes can read it directly.
101
+ return resourcePath;
102
+ }
103
+ const relativePath = path.relative(archivePath, resourcePath);
104
+ const unpackedPath = path.join(`${archivePath}.unpacked`, relativePath);
105
+ if (await this.isExtracted(resourcePath, unpackedPath)) {
106
+ return unpackedPath;
107
+ }
108
+ const extractionPath = path.join(await this.getExtractionPath(archivePath), relativePath);
109
+ await this.fileSystemLocking.lockPath(archivePath, () => this.extract(resourcePath, extractionPath));
110
+ this.logger.info(`Extracted bundled resource '${resourcePath}' to '${extractionPath}'.`);
111
+ return extractionPath;
112
+ }
113
+
114
+ /**
115
+ * Find the archive that the given resource is packaged into, if any.
116
+ *
117
+ * @returns the path of the archive, i.e. the shortest prefix of the given path ending in an `.asar` segment,
118
+ * which is also how Electron itself determines the archive that a path refers to.
119
+ */
120
+ protected findArchivePath(resourcePath: string): string | undefined {
121
+ const segments = resourcePath.split(/[\\/]/);
122
+ const archiveIndex = segments.findIndex(segment => segment.toLowerCase().endsWith('.asar'));
123
+ return archiveIndex < 0 ? undefined : segments.slice(0, archiveIndex + 1).join(path.sep);
124
+ }
125
+
126
+ /**
127
+ * Whether every file of the given resource is already available at the given target path. Packaging tools
128
+ * only unpack the files that the application configured them to unpack, so a partial copy must be ignored.
129
+ */
130
+ protected async isExtracted(resourcePath: string, targetPath: string): Promise<boolean> {
131
+ for (const file of await this.collectFiles(resourcePath)) {
132
+ if (!await this.exists(path.join(targetPath, file))) {
133
+ return false;
134
+ }
135
+ }
136
+ return true;
137
+ }
138
+
139
+ protected async extract(resourcePath: string, targetPath: string): Promise<void> {
140
+ for (const file of await this.collectFiles(resourcePath)) {
141
+ await this.copyFile(path.join(resourcePath, file), path.join(targetPath, file));
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Collect the files of the given resource as paths relative to it. The relative path of a resource that is
147
+ * a plain file is the empty string.
148
+ */
149
+ protected async collectFiles(resourcePath: string, relativePath: string = ''): Promise<string[]> {
150
+ const currentPath = path.join(resourcePath, relativePath);
151
+ if (!(await fs.promises.stat(currentPath)).isDirectory()) {
152
+ return [relativePath];
153
+ }
154
+ const files: string[] = [];
155
+ for (const entry of await fs.promises.readdir(currentPath)) {
156
+ files.push(...await this.collectFiles(resourcePath, path.join(relativePath, entry)));
157
+ }
158
+ return files;
159
+ }
160
+
161
+ protected async copyFile(sourcePath: string, targetPath: string): Promise<void> {
162
+ const sourceStat = await fs.promises.stat(sourcePath);
163
+ if (await this.isUpToDate(targetPath, sourceStat)) {
164
+ return;
165
+ }
166
+ await fs.promises.mkdir(path.dirname(targetPath), { recursive: true, mode: 0o700 });
167
+ // Write to a temporary file and move it into place, so that a concurrently starting application
168
+ // instance never reads partially written content.
169
+ const temporaryPath = `${targetPath}.${process.pid}.tmp`;
170
+ try {
171
+ // Electron reports the files of an asar archive as not executable, even those that the archive marks as
172
+ // executable, so every extracted file is made executable for the owner to keep bundled executables usable.
173
+ await fs.promises.writeFile(temporaryPath, await fs.promises.readFile(sourcePath), { mode: sourceStat.mode & 0o777 | 0o700 });
174
+ try {
175
+ await fs.promises.rename(temporaryPath, targetPath);
176
+ } catch {
177
+ // renaming onto an existing file is not supported on all platforms
178
+ await fs.promises.rm(targetPath, { force: true });
179
+ await fs.promises.rename(temporaryPath, targetPath);
180
+ }
181
+ } finally {
182
+ await fs.promises.rm(temporaryPath, { force: true });
183
+ }
184
+ }
185
+
186
+ protected async isUpToDate(targetPath: string, sourceStat: fs.Stats): Promise<boolean> {
187
+ try {
188
+ return (await fs.promises.stat(targetPath)).size === sourceStat.size;
189
+ } catch {
190
+ return false;
191
+ }
192
+ }
193
+
194
+ /**
195
+ * The directory into which resources of the given archive are extracted. It is specific to the content of
196
+ * the archive, so that updating the application invalidates previously extracted copies.
197
+ */
198
+ protected async getExtractionPath(archivePath: string): Promise<string> {
199
+ const archiveName = path.basename(archivePath, path.extname(archivePath));
200
+ try {
201
+ const extractionRoot = path.join(FileUri.fsPath(await this.envVariablesServer.getConfigDirUri()), this.extractionFolder);
202
+ const extractionPath = path.join(extractionRoot, `${archiveName}-${this.getArchiveStamp(archivePath)}`);
203
+ await fs.promises.mkdir(extractionPath, { recursive: true, mode: 0o700 });
204
+ this.removeStaleExtractions(extractionRoot, `${archiveName}-`, extractionPath);
205
+ return extractionPath;
206
+ } catch (error) {
207
+ this.logger.warn('Could not extract bundled resources into the configuration directory, using a temporary directory instead.', error);
208
+ return this.getTemporaryExtractionPath();
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Fallback for applications whose configuration directory cannot be written to. The directory is unique to
214
+ * this run of the application, so that resources are extracted again whenever the application is started.
215
+ */
216
+ protected getTemporaryExtractionPath(): Promise<string> {
217
+ return this.temporaryExtractionPath ??= fs.promises.mkdtemp(path.join(os.tmpdir(), 'theia-bundled-resources-'));
218
+ }
219
+
220
+ /**
221
+ * Identify the content of the given archive. `process.noAsar` is toggled around the synchronous `stat` call
222
+ * to get the stats of the archive file itself rather than of the directory that it appears as.
223
+ */
224
+ protected getArchiveStamp(archivePath: string): string {
225
+ const asarProcess = process as NodeJS.Process & { noAsar?: boolean };
226
+ const noAsar = asarProcess.noAsar;
227
+ try {
228
+ asarProcess.noAsar = true;
229
+ const stat = fs.statSync(archivePath);
230
+ return crypto.createHash('sha256').update(`${archivePath}:${stat.size}:${stat.mtimeMs}`).digest('hex').substring(0, 12);
231
+ } finally {
232
+ asarProcess.noAsar = noAsar;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Remove resources that were extracted from an earlier version of the archive, unless they were used
238
+ * recently, because another application instance may still be running on that version.
239
+ */
240
+ protected removeStaleExtractions(extractionRoot: string, prefix: string, currentPath: string): void {
241
+ const removeStale = async () => {
242
+ for (const entry of await fs.promises.readdir(extractionRoot)) {
243
+ const entryPath = path.join(extractionRoot, entry);
244
+ if (!entry.startsWith(prefix) || entryPath === currentPath) {
245
+ continue;
246
+ }
247
+ const stat = await fs.promises.stat(entryPath);
248
+ if (Date.now() - stat.mtimeMs > this.staleExtractionAge) {
249
+ await fs.promises.rm(entryPath, { recursive: true, force: true });
250
+ this.logger.info(`Removed stale extracted resources: ${entryPath}`);
251
+ }
252
+ }
253
+ };
254
+ removeStale().catch(error => this.logger.warn(`Could not remove stale extracted resources in '${extractionRoot}'.`, error));
255
+ }
256
+
257
+ protected async exists(targetPath: string): Promise<boolean> {
258
+ try {
259
+ await fs.promises.stat(targetPath);
260
+ return true;
261
+ } catch {
262
+ return false;
263
+ }
264
+ }
265
+
266
+ }
package/src/node/index.ts CHANGED
@@ -22,5 +22,6 @@ export * from './messaging';
22
22
  export * from './cli';
23
23
  export * from './setting-service';
24
24
  export { FileSystemLocking } from './filesystem-locking';
25
+ export { BundledResourceProvider } from './bundled-resource-provider';
25
26
  export { BackendRequestAllowedContribution } from './request/backend-request-facade';
26
27
  export { HttpConnectionValidator } from './hosting/browser-connection-token';