npm package diff

Package: @forge/bundler

Versions: 4.19.7-next.14 - 4.20.0-next.15

File: package/out/config/node.js

Index: package/out/config/node.js
===================================================================
--- package/out/config/node.js
+++ package/out/config/node.js
@@ -5,8 +5,9 @@
 const cheerio_1 = tslib_1.__importDefault(require("cheerio"));
 const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
 const cli_shared_1 = require("@forge/cli-shared");
 const common_1 = require("./common");
+const path_1 = tslib_1.__importDefault(require("path"));
 exports.NODE_WEBPACK_CONFIG_NAME = 'node-runtime';
 exports.NODE_WEBPACK_USER_CODE_DIR = 'bundled';
 exports.NODE_RUNTIME_VERSION_FILE = 'runtime.json';
 var RuntimeCDN;
@@ -34,76 +35,106 @@
         super(requestId, message);
     }
 }
 exports.ParseWrapperCDNIndexError = ParseWrapperCDNIndexError;
+var ScriptType;
+(function (ScriptType) {
+    ScriptType["WRAPPER"] = "wrapper";
+    ScriptType["LOADER"] = "loader";
+})(ScriptType || (ScriptType = {}));
 class LocalWrapperProvider {
     filesystemReader;
-    path;
-    constructor(filesystemReader, path) {
+    runtimePath;
+    constructor(filesystemReader, runtimePath) {
         this.filesystemReader = filesystemReader;
-        this.path = path;
+        this.runtimePath = runtimePath;
     }
     async getNodeRuntimeWrapper() {
-        const wrapper = await this.filesystemReader.readFileAsync(this.path);
+        const wrapper = await this.filesystemReader.readFileAsync(path_1.default.join(this.runtimePath, 'dist/wrapper.js'));
         if (!wrapper) {
             throw new LocalWrapperNotFoundError();
         }
         return {
             script: wrapper,
-            version: 'local'
+            version: 'local-wrapper'
         };
     }
+    async getNodeRuntimeLoader() {
+        const loader = await this.filesystemReader.readFileAsync(path_1.default.join(this.runtimePath, 'dist/loader.js'));
+        if (!loader) {
+            throw new LocalWrapperNotFoundError();
+        }
+        return {
+            script: loader,
+            version: 'local-loader'
+        };
+    }
 }
 exports.LocalWrapperProvider = LocalWrapperProvider;
 class NetworkWrapperProvider {
+    statsigService;
     wrapper;
+    loader;
     cdnUrl;
-    constructor() {
+    constructor(statsigService) {
+        this.statsigService = statsigService;
         this.cdnUrl = (0, cli_shared_1.getEnvironmentConfig)(RuntimeCDN);
     }
-    async getWrapperPathFromIndex(htmlContent, requestId) {
+    async getScriptPathFromIndex(htmlContent, requestId, scriptType) {
         const html = cheerio_1.default.load(htmlContent);
-        const wrapperPath = html('script')?.get()?.[0]?.attribs['src'];
-        if (typeof wrapperPath !== 'string') {
-            throw new ParseWrapperCDNIndexError('Unable to parse source of runtime component.', requestId);
+        const scriptPath = html('script')
+            ?.get()
+            ?.find((asset) => asset.attribs['src']?.includes(scriptType))?.attribs['src'];
+        if (typeof scriptPath !== 'string') {
+            throw new ParseWrapperCDNIndexError(`Unable to parse source of runtime ${scriptType}.`, requestId);
         }
-        return new URL(wrapperPath, this.cdnUrl).toString();
+        return new URL(scriptPath, this.cdnUrl).toString();
     }
-    async getNodeRuntimeWrapper() {
-        if (this.wrapper) {
-            return this.wrapper;
-        }
+    getFileFromCDN = async (scriptType) => {
         try {
             const indexResponse = await (0, node_fetch_1.default)(this.cdnUrl);
             if (!indexResponse.ok) {
                 throw new WrapperNetworkError(`Failed to fetch runtime component: ${this.cdnUrl} ${indexResponse.status}.`, (0, cli_shared_1.getAtlassianTraceId)(indexResponse.headers));
             }
-            const wrapperUrl = await this.getWrapperPathFromIndex(await indexResponse.text(), (0, cli_shared_1.getAtlassianTraceId)(indexResponse.headers));
-            const response = await (0, node_fetch_1.default)(wrapperUrl);
+            const scriptUrl = await this.getScriptPathFromIndex(await indexResponse.text(), (0, cli_shared_1.getAtlassianTraceId)(indexResponse.headers), scriptType);
+            const response = await (0, node_fetch_1.default)(scriptUrl);
             if (!response.ok) {
-                throw new WrapperNetworkError(`Failed to fetch runtime component: ${wrapperUrl.toString()} ${response.status}.`, (0, cli_shared_1.getAtlassianTraceId)(response.headers));
+                throw new WrapperNetworkError(`Failed to fetch runtime component: ${scriptUrl.toString()} ${response.status}.`, (0, cli_shared_1.getAtlassianTraceId)(response.headers));
             }
             const script = await response.text();
-            this.wrapper = {
+            return {
                 script,
-                version: new URL(wrapperUrl).pathname
+                version: new URL(scriptUrl).pathname
             };
-            return this.wrapper;
         }
         catch (e) {
             if (e instanceof ParseWrapperCDNIndexError) {
                 throw e;
             }
             throw new WrapperNetworkError(e instanceof Error ? e.message : 'Networking error when retrieving runtime component, retry the command.');
         }
+    };
+    async getNodeRuntimeWrapper() {
+        if (!this.wrapper) {
+            this.wrapper = await this.getFileFromCDN(ScriptType.WRAPPER);
+        }
+        return this.wrapper;
     }
+    async getNodeRuntimeLoader() {
+        if (!this.loader) {
+            if (await this.statsigService.testForgeCliBundleRuntimeLoaderGate()) {
+                this.loader = await this.getFileFromCDN(ScriptType.LOADER);
+            }
+        }
+        return this.loader;
+    }
 }
 exports.NetworkWrapperProvider = NetworkWrapperProvider;
-const getWrapperProvider = ({ fileSystemReader }) => {
-    if (process.env.FORGE_WRAPPER_PATH) {
-        return new LocalWrapperProvider(fileSystemReader, process.env.FORGE_WRAPPER_PATH);
+const getWrapperProvider = ({ fileSystemReader, statsigService }) => {
+    if (process.env.FORGE_RUNTIME_PATH) {
+        return new LocalWrapperProvider(fileSystemReader, process.env.FORGE_RUNTIME_PATH);
     }
-    return new NetworkWrapperProvider();
+    return new NetworkWrapperProvider(statsigService);
 };
 exports.getWrapperProvider = getWrapperProvider;
 const getNodeRuntimeBuildConfig = (wrapperProvider) => (entrypoints, config) => {
     const webpackConfig = (0, common_1.getCommonWebpackConfig)(entrypoints, config);
@@ -125,14 +156,25 @@
         apply: (compiler) => {
             compiler.hooks.make.tapPromise('AfterEmitPlugin', async (compilation) => {
                 const { RawSource } = compiler.webpack.sources;
                 const wrapper = await wrapperProvider.getNodeRuntimeWrapper();
-                const source = new RawSource(wrapper.script);
-                for (const entrypoint of entrypoints) {
-                    compilation.emitAsset(`${entrypoint.name}.cjs`, source);
+                const loader = await wrapperProvider.getNodeRuntimeLoader();
+                if (loader) {
+                    const loaderSource = new RawSource(loader.script);
+                    for (const entrypoint of entrypoints) {
+                        compilation.emitAsset(`${entrypoint.name}.cjs`, loaderSource);
+                    }
+                    const wrapperSource = new RawSource(wrapper.script);
+                    compilation.emitAsset('__forge_wrapper__.cjs', wrapperSource);
                 }
+                else {
+                    const source = new RawSource(wrapper.script);
+                    for (const entrypoint of entrypoints) {
+                        compilation.emitAsset(`${entrypoint.name}.cjs`, source);
+                    }
+                }
                 compilation.emitAsset(exports.NODE_RUNTIME_VERSION_FILE, new RawSource(JSON.stringify({
-                    version: wrapper.version
+                    version: loader ? loader.version : wrapper.version
                 }, null, 2)));
             });
         }
     });