@metamask/snaps-cli 8.3.0 → 8.4.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.
- package/CHANGELOG.md +38 -1
- package/dist/builders.cjs +11 -0
- package/dist/builders.cjs.map +1 -1
- package/dist/builders.d.cts +11 -0
- package/dist/builders.d.cts.map +1 -1
- package/dist/builders.d.mts +11 -0
- package/dist/builders.d.mts.map +1 -1
- package/dist/builders.mjs +11 -0
- package/dist/builders.mjs.map +1 -1
- package/dist/commands/build/build.cjs +15 -7
- package/dist/commands/build/build.cjs.map +1 -1
- package/dist/commands/build/build.d.cts +19 -3
- package/dist/commands/build/build.d.cts.map +1 -1
- package/dist/commands/build/build.d.mts +19 -3
- package/dist/commands/build/build.d.mts.map +1 -1
- package/dist/commands/build/build.mjs +15 -7
- package/dist/commands/build/build.mjs.map +1 -1
- package/dist/commands/build/index.cjs +15 -2
- package/dist/commands/build/index.cjs.map +1 -1
- package/dist/commands/build/index.d.cts.map +1 -1
- package/dist/commands/build/index.d.mts.map +1 -1
- package/dist/commands/build/index.mjs +15 -2
- package/dist/commands/build/index.mjs.map +1 -1
- package/dist/commands/manifest/implementation.cjs +1 -2
- package/dist/commands/manifest/implementation.cjs.map +1 -1
- package/dist/commands/manifest/implementation.d.cts.map +1 -1
- package/dist/commands/manifest/implementation.d.mts.map +1 -1
- package/dist/commands/manifest/implementation.mjs +1 -2
- package/dist/commands/manifest/implementation.mjs.map +1 -1
- package/dist/commands/sandbox/sandbox.cjs +4 -1
- package/dist/commands/sandbox/sandbox.cjs.map +1 -1
- package/dist/commands/sandbox/sandbox.d.cts.map +1 -1
- package/dist/commands/sandbox/sandbox.d.mts.map +1 -1
- package/dist/commands/sandbox/sandbox.mjs +4 -1
- package/dist/commands/sandbox/sandbox.mjs.map +1 -1
- package/dist/commands/watch/index.cjs +7 -4
- package/dist/commands/watch/index.cjs.map +1 -1
- package/dist/commands/watch/index.d.cts.map +1 -1
- package/dist/commands/watch/index.d.mts.map +1 -1
- package/dist/commands/watch/index.mjs +7 -4
- package/dist/commands/watch/index.mjs.map +1 -1
- package/dist/config.cjs +5 -0
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +71 -22
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +71 -22
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +5 -0
- package/dist/config.mjs.map +1 -1
- package/dist/utils/cli.cjs +44 -4
- package/dist/utils/cli.cjs.map +1 -1
- package/dist/utils/cli.d.cts +9 -0
- package/dist/utils/cli.d.cts.map +1 -1
- package/dist/utils/cli.d.mts +9 -0
- package/dist/utils/cli.d.mts.map +1 -1
- package/dist/utils/cli.mjs +20 -1
- package/dist/utils/cli.mjs.map +1 -1
- package/dist/webpack/config.cjs +7 -1
- package/dist/webpack/config.cjs.map +1 -1
- package/dist/webpack/config.d.cts +16 -4
- package/dist/webpack/config.d.cts.map +1 -1
- package/dist/webpack/config.d.mts +16 -4
- package/dist/webpack/config.d.mts.map +1 -1
- package/dist/webpack/config.mjs +8 -2
- package/dist/webpack/config.mjs.map +1 -1
- package/dist/webpack/plugins.cjs +90 -2
- package/dist/webpack/plugins.cjs.map +1 -1
- package/dist/webpack/plugins.d.cts +36 -2
- package/dist/webpack/plugins.d.cts.map +1 -1
- package/dist/webpack/plugins.d.mts +36 -2
- package/dist/webpack/plugins.d.mts.map +1 -1
- package/dist/webpack/plugins.mjs +90 -3
- package/dist/webpack/plugins.mjs.map +1 -1
- package/dist/webpack/server.cjs +14 -3
- package/dist/webpack/server.cjs.map +1 -1
- package/dist/webpack/server.d.cts.map +1 -1
- package/dist/webpack/server.d.mts.map +1 -1
- package/dist/webpack/server.mjs +16 -5
- package/dist/webpack/server.mjs.map +1 -1
- package/dist/webpack/utils.cjs +29 -1
- package/dist/webpack/utils.cjs.map +1 -1
- package/dist/webpack/utils.d.cts +9 -1
- package/dist/webpack/utils.d.cts.map +1 -1
- package/dist/webpack/utils.d.mts +9 -1
- package/dist/webpack/utils.d.mts.map +1 -1
- package/dist/webpack/utils.mjs +27 -0
- package/dist/webpack/utils.mjs.map +1 -1
- package/package.json +7 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Ora } from "ora/index.js";
|
|
2
2
|
import type { Compiler, Resolver, WebpackPluginInstance } from "webpack";
|
|
3
|
+
import type { WebpackOptions } from "./config.mjs";
|
|
3
4
|
export type SnapsStatsPluginOptions = {
|
|
4
5
|
/**
|
|
5
6
|
* Whether to log the verbose stats.
|
|
@@ -29,9 +30,9 @@ export declare class SnapsStatsPlugin implements WebpackPluginInstance {
|
|
|
29
30
|
*/
|
|
30
31
|
export type SnapsWatchPluginOptions = {
|
|
31
32
|
/**
|
|
32
|
-
* The
|
|
33
|
+
* The path to the manifest, to determine which files to watch.
|
|
33
34
|
*/
|
|
34
|
-
|
|
35
|
+
manifestPath: string;
|
|
35
36
|
};
|
|
36
37
|
/**
|
|
37
38
|
* A plugin that adds extra files to watch. This is useful for watching files
|
|
@@ -144,5 +145,38 @@ export declare class SnapsBundleWarningsPlugin implements WebpackPluginInstance
|
|
|
144
145
|
*/
|
|
145
146
|
apply(compiler: Compiler): void;
|
|
146
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* The options for the {@link PreinstalledSnapsBundlePlugin}.
|
|
150
|
+
*/
|
|
151
|
+
export type PreinstalledSnapsBundlePluginOptions = {
|
|
152
|
+
/**
|
|
153
|
+
* The path to the manifest file.
|
|
154
|
+
*/
|
|
155
|
+
manifestPath: string;
|
|
156
|
+
/**
|
|
157
|
+
* The name of the output file.
|
|
158
|
+
*/
|
|
159
|
+
outputName: string;
|
|
160
|
+
/**
|
|
161
|
+
* The preinstalled options from the Webpack configuration.
|
|
162
|
+
*/
|
|
163
|
+
preinstalledOptions: WebpackOptions['preinstalledOptions'];
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* A plugin that creates a preinstalled Snap bundle from the compiled bundle.
|
|
167
|
+
* This will read the manifest, and any required files (locales, icon), and
|
|
168
|
+
* create a `preinstalled-snap.json` file that can be used to install the Snap
|
|
169
|
+
* as a preinstalled Snap.
|
|
170
|
+
*/
|
|
171
|
+
export declare class PreinstalledSnapsBundlePlugin implements WebpackPluginInstance {
|
|
172
|
+
#private;
|
|
173
|
+
constructor(options: PreinstalledSnapsBundlePluginOptions, spinner?: Ora);
|
|
174
|
+
/**
|
|
175
|
+
* Apply the plugin to the Webpack compiler.
|
|
176
|
+
*
|
|
177
|
+
* @param compiler - The Webpack compiler.
|
|
178
|
+
*/
|
|
179
|
+
apply(compiler: Compiler): void;
|
|
180
|
+
}
|
|
147
181
|
export {};
|
|
148
182
|
//# sourceMappingURL=plugins.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.d.mts","sourceRoot":"","sources":["../../src/webpack/plugins.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugins.d.mts","sourceRoot":"","sources":["../../src/webpack/plugins.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,GAAG,EAAE,qBAAY;AAE/B,OAAO,KAAK,EACV,QAAQ,EAER,QAAQ,EAER,qBAAqB,EACtB,gBAAgB;AAGjB,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAiB;AAI/C,MAAM,MAAM,uBAAuB,GAAG;IACpC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,qBAAa,gBAAiB,YAAW,qBAAqB;;IAC5D;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;gBAQxC,OAAO,GAAE,uBAER,EACD,OAAO,CAAC,EAAE,GAAG;IAMf;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ;CA6FzB;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,qBAAqB;;IAC5D;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;gBAO9B,OAAO,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,GAAG;IAK3D;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ;CAezB;AAED;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;;;;GAKG;AACH,KAAK,aAAa,GAAG;IACnB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,aAAa;;IACxD;;OAEG;IACH,QAAQ,CAAC,iBAAiB,cAAqB;IAO/C;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,2BAA2B,CAAC;gBAG5C,OAAO,GAAE,2BAER;IAKH;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ;CA4BzB;AAED;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C;;;OAGG;IACH,eAAe,CAAC,EAAE,oBAAoB,GAAG,KAAK,CAAC;IAE/C;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AAEH,qBAAa,yBAA0B,YAAW,qBAAqB;;IACrE;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,gCAAgC,CAAC;gBAGjD,OAAO,GAAE,gCAGR;IAKH;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ;CAsHzB;AAED;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,mBAAmB,EAAE,cAAc,CAAC,qBAAqB,CAAC,CAAC;CAC5D,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,6BAA8B,YAAW,qBAAqB;;gBAK7D,OAAO,EAAE,oCAAoC,EAAE,OAAO,CAAC,EAAE,GAAG;IAKxE;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ;CAmGzB"}
|
package/dist/webpack/plugins.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { loadManifest } from "@metamask/snaps-utils/node";
|
|
1
2
|
import { assert, hasProperty, isObject } from "@metamask/utils";
|
|
2
3
|
import $chalk from "chalk";
|
|
3
4
|
const { bold, dim, red, yellow } = $chalk;
|
|
4
5
|
import { isBuiltin } from "module";
|
|
6
|
+
import { dirname, resolve } from "path";
|
|
5
7
|
import $webpack from "webpack";
|
|
6
|
-
const { WebpackError } = $webpack;
|
|
7
|
-
import { formatText, pluralize } from "./utils.mjs";
|
|
8
|
+
const { Compilation, WebpackError, sources } = $webpack;
|
|
9
|
+
import { formatText, pluralize, readWebpackFile } from "./utils.mjs";
|
|
8
10
|
import { error, getErrorMessage, info, warn } from "../utils/index.mjs";
|
|
9
11
|
/**
|
|
10
12
|
* A plugin that logs the stats after compilation. This is useful for logging
|
|
@@ -113,7 +115,8 @@ export class SnapsWatchPlugin {
|
|
|
113
115
|
info(`Changes detected in ${yellow(file)}, recompiling.`, this.#spinner);
|
|
114
116
|
});
|
|
115
117
|
compiler.hooks.afterEmit.tapPromise(this.constructor.name, async ({ fileDependencies }) => {
|
|
116
|
-
this.options.
|
|
118
|
+
const { files } = await loadManifest(this.options.manifestPath);
|
|
119
|
+
files.forEach(fileDependencies.add.bind(fileDependencies));
|
|
117
120
|
});
|
|
118
121
|
}
|
|
119
122
|
}
|
|
@@ -273,4 +276,88 @@ export class SnapsBundleWarningsPlugin {
|
|
|
273
276
|
});
|
|
274
277
|
}
|
|
275
278
|
}
|
|
279
|
+
/**
|
|
280
|
+
* A plugin that creates a preinstalled Snap bundle from the compiled bundle.
|
|
281
|
+
* This will read the manifest, and any required files (locales, icon), and
|
|
282
|
+
* create a `preinstalled-snap.json` file that can be used to install the Snap
|
|
283
|
+
* as a preinstalled Snap.
|
|
284
|
+
*/
|
|
285
|
+
export class PreinstalledSnapsBundlePlugin {
|
|
286
|
+
#options;
|
|
287
|
+
#spinner;
|
|
288
|
+
constructor(options, spinner) {
|
|
289
|
+
this.#options = options;
|
|
290
|
+
this.#spinner = spinner;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Apply the plugin to the Webpack compiler.
|
|
294
|
+
*
|
|
295
|
+
* @param compiler - The Webpack compiler.
|
|
296
|
+
*/
|
|
297
|
+
apply(compiler) {
|
|
298
|
+
compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {
|
|
299
|
+
compilation.hooks.processAssets.tapPromise({
|
|
300
|
+
name: this.constructor.name,
|
|
301
|
+
// `PROCESS_ASSETS_STAGE_REPORT` is the last stage, so we ensure this
|
|
302
|
+
// plugin runs after all other plugins have finished processing
|
|
303
|
+
// assets.
|
|
304
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_REPORT,
|
|
305
|
+
}, async () => {
|
|
306
|
+
info('Creating preinstalled Snap bundle.', this.#spinner);
|
|
307
|
+
const asset = compilation.getAsset(this.#options.outputName);
|
|
308
|
+
if (!asset) {
|
|
309
|
+
compilation.errors.push(new WebpackError('Bundle asset not found. Make sure to build the project first.'));
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const bundleSource = asset.source.source().toString();
|
|
313
|
+
const preinstalledSnapBundleJson = JSON.stringify(await this.#createPreinstalledBundle(compilation, bundleSource), null, 2);
|
|
314
|
+
compilation.emitAsset('preinstalled-snap.json', new sources.RawSource(preinstalledSnapBundleJson));
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Create a preinstalled bundle object from the given bundle source. This will
|
|
320
|
+
* load the manifest, read any required files (locales, icon), and return the
|
|
321
|
+
* preinstalled bundle object.
|
|
322
|
+
*
|
|
323
|
+
* Custom auxiliary files are not currently supported in preinstalled Snaps.
|
|
324
|
+
*
|
|
325
|
+
* @param compilation - The Webpack compilation.
|
|
326
|
+
* @param bundleSource - The source code of the bundle.
|
|
327
|
+
* @returns The preinstalled bundle object.
|
|
328
|
+
*/
|
|
329
|
+
async #createPreinstalledBundle(compilation, bundleSource) {
|
|
330
|
+
const { mergedManifest } = await loadManifest(this.#options.manifestPath);
|
|
331
|
+
const manifest = mergedManifest;
|
|
332
|
+
const basePath = dirname(this.#options.manifestPath);
|
|
333
|
+
const files = [
|
|
334
|
+
{
|
|
335
|
+
path: manifest.source.location.npm.filePath,
|
|
336
|
+
value: bundleSource,
|
|
337
|
+
},
|
|
338
|
+
];
|
|
339
|
+
if (manifest.source.locales) {
|
|
340
|
+
for (const locale of manifest.source.locales) {
|
|
341
|
+
files.push({
|
|
342
|
+
path: locale,
|
|
343
|
+
value: await readWebpackFile(compilation.inputFileSystem, resolve(basePath, locale)),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (manifest.source.location.npm.iconPath) {
|
|
348
|
+
const { iconPath } = manifest.source.location.npm;
|
|
349
|
+
files.push({
|
|
350
|
+
path: manifest.source.location.npm.iconPath,
|
|
351
|
+
// The icon is expected to be an SVG file, so we read it as UTF-8.
|
|
352
|
+
value: await readWebpackFile(compilation.inputFileSystem, resolve(basePath, iconPath)),
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
snapId: `npm:${manifest.source.location.npm.packageName}`,
|
|
357
|
+
manifest,
|
|
358
|
+
files,
|
|
359
|
+
...this.#options.preinstalledOptions,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
276
363
|
//# sourceMappingURL=plugins.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.mjs","sourceRoot":"","sources":["../../src/webpack/plugins.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, hasProperty, isObject } from '@metamask/utils';\nimport { bold, dim, red, yellow } from 'chalk';\nimport { isBuiltin } from 'module';\nimport type { Ora } from 'ora';\nimport type {\n Compiler,\n ProvidePlugin,\n Resolver,\n StatsError,\n WebpackPluginInstance,\n} from 'webpack';\nimport { WebpackError } from 'webpack';\n\nimport { formatText, pluralize } from './utils';\nimport { error, getErrorMessage, info, warn } from '../utils';\n\nexport type SnapsStatsPluginOptions = {\n /**\n * Whether to log the verbose stats.\n */\n verbose?: boolean;\n};\n\n/**\n * A plugin that logs the stats after compilation. This is useful for logging\n * the number of files compiled, and the time taken to compile them.\n */\nexport class SnapsStatsPlugin implements WebpackPluginInstance {\n /**\n * The options for the plugin.\n */\n readonly options: SnapsStatsPluginOptions;\n\n /**\n * The spinner to use for logging.\n */\n readonly #spinner?: Ora;\n\n constructor(\n options: SnapsStatsPluginOptions = {\n verbose: false,\n },\n spinner?: Ora,\n ) {\n this.options = options;\n this.#spinner = spinner;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n compiler.hooks.afterDone.tap(this.constructor.name, (stats) => {\n if (!stats) {\n return;\n }\n\n const { modules, time, errors, warnings } = stats.toJson();\n\n assert(modules, 'Modules must be defined in stats.');\n assert(time, 'Time must be defined in stats.');\n\n if (errors?.length) {\n const formattedErrors = errors\n .map((statsError) => this.#getStatsErrorMessage(statsError, red))\n .join('\\n\\n');\n\n error(\n `Compiled ${modules.length} ${pluralize(\n modules.length,\n 'file',\n )} in ${time}ms with ${errors.length} ${pluralize(\n errors.length,\n 'error',\n )}.\\n\\n${formattedErrors}\\n`,\n this.#spinner,\n );\n\n this.#spinner?.stop();\n\n process.exitCode = 1;\n return;\n }\n\n if (warnings?.length) {\n const formattedWarnings = warnings\n .map((statsWarning) =>\n this.#getStatsErrorMessage(statsWarning, yellow),\n )\n .join('\\n\\n');\n\n warn(\n `Compiled ${modules.length} ${pluralize(\n modules.length,\n 'file',\n )} in ${time}ms with ${warnings.length} ${pluralize(\n warnings.length,\n 'warning',\n )}.\\n\\n${formattedWarnings}\\n`,\n this.#spinner,\n );\n } else {\n info(\n `Compiled ${modules.length} ${pluralize(\n modules.length,\n 'file',\n )} in ${time}ms.`,\n this.#spinner,\n );\n }\n\n if (compiler.watchMode) {\n // The spinner may be restarted by the watch plugin, outside of the\n // `executeSteps` flow, so we stop it here just in case.\n this.#spinner?.succeed('Done!');\n }\n });\n }\n\n /**\n * Get the error message for the given stats error.\n *\n * @param statsError - The stats error.\n * @param color - The color to use for the error message.\n * @returns The error message.\n */\n #getStatsErrorMessage(\n statsError: StatsError,\n color: typeof red | typeof yellow,\n ) {\n const baseMessage = this.options.verbose\n ? getErrorMessage(statsError)\n : statsError.message;\n\n const [first, ...rest] = baseMessage.split('\\n');\n\n return [\n color(formatText(`• ${first}`, 4, 2)),\n ...rest.map((message) => formatText(color(message), 4)),\n statsError.details && `\\n${formatText(dim(statsError.details), 6)}`,\n ]\n .filter(Boolean)\n .join('\\n');\n }\n}\n\n/**\n * The options for the {@link SnapsWatchPlugin}.\n */\nexport type SnapsWatchPluginOptions = {\n /**\n * The extra files to watch.\n */\n files?: string[];\n};\n\n/**\n * A plugin that adds extra files to watch. This is useful for watching files\n * that are not imported by the entry point, such as the `snap.manifest.json`\n * file.\n */\nexport class SnapsWatchPlugin implements WebpackPluginInstance {\n /**\n * The options for the plugin.\n */\n readonly options: SnapsWatchPluginOptions;\n\n /**\n * The spinner to use for logging.\n */\n readonly #spinner?: Ora;\n\n constructor(options: SnapsWatchPluginOptions, spinner?: Ora) {\n this.options = options;\n this.#spinner = spinner;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n compiler.hooks.invalid.tap(this.constructor.name, (file) => {\n this.#spinner?.start();\n info(`Changes detected in ${yellow(file)}, recompiling.`, this.#spinner);\n });\n\n compiler.hooks.afterEmit.tapPromise(\n this.constructor.name,\n async ({ fileDependencies }) => {\n this.options.files?.forEach(\n fileDependencies.add.bind(fileDependencies),\n );\n },\n );\n }\n}\n\n/**\n * The options for the {@link SnapsBuiltInResolver}.\n */\nexport type SnapsBuiltInResolverOptions = {\n /**\n * The built-in modules to ignore.\n */\n ignore?: string[];\n};\n\n/**\n * A Webpack resolve plugin.\n *\n * Copied from Webpack's own types, because the `ResolvePluginInstance` type is\n * a union, and can't be used as a type for a class.\n */\ntype ResolvePlugin = {\n apply: (resolver: Resolver) => void;\n};\n\n/**\n * A plugin that logs a message when a built-in module is not resolved. The\n * MetaMask Snaps CLI does not support built-in modules by default, and this\n * plugin is used to warn the user when they try to import a built-in module,\n * when no fallback is configured.\n */\nexport class SnapsBuiltInResolver implements ResolvePlugin {\n /**\n * The built-in modules that have been imported, but not resolved.\n */\n readonly unresolvedModules = new Set<string>();\n\n /**\n * The name of the resolver hook to tap into.\n */\n readonly #source = 'described-resolve';\n\n /**\n * The options for the plugin.\n */\n readonly options: SnapsBuiltInResolverOptions;\n\n constructor(\n options: SnapsBuiltInResolverOptions = {\n ignore: [],\n },\n ) {\n this.options = options;\n }\n\n /**\n * Apply the plugin to the Webpack resolver.\n *\n * @param resolver - The Webpack resolver.\n */\n apply(resolver: Resolver) {\n resolver\n .getHook(this.#source)\n .tapAsync(\n this.constructor.name,\n ({ module: isModule, request }, _, callback) => {\n if (!isModule || !request) {\n return callback();\n }\n\n const baseRequest = request.split('/')[0];\n if (\n isBuiltin(baseRequest) &&\n !this.options.ignore?.includes(baseRequest)\n ) {\n const fallback = resolver.options.fallback.find(\n ({ name }) => name === baseRequest,\n );\n\n if (fallback && !fallback.alias) {\n this.unresolvedModules.add(baseRequest);\n }\n }\n\n return callback();\n },\n );\n }\n}\n\n/**\n * The options for the {@link SnapsBundleWarningsPlugin}.\n */\nexport type SnapsBundleWarningsPluginOptions = {\n /**\n * The {@link SnapsBuiltInResolver} instance to use for detecting built-in\n * modules.\n */\n builtInResolver?: SnapsBuiltInResolver | false;\n\n /**\n * Whether to show warnings if built-in modules are used, but not provided by\n * Webpack's `fallback` configuration.\n */\n builtIns?: boolean;\n\n /**\n * Whether to show warnings if the `Buffer` global is used, but not provided\n * by Webpack's `DefinePlugin`.\n */\n buffer?: boolean;\n};\n\n/**\n * A plugin that logs a message when:\n *\n * - A built-in module is not resolved. The MetaMask Snaps CLI does not support\n * built-in modules by default, and this plugin is used to warn the user when\n * they try to import a built-in module, when no fallback is configured.\n * - A snap uses the `Buffer` global. The MetaMask Snaps CLI does not support\n * the `Buffer` global by default, and this plugin is used to warn the user when\n * they try to use the `Buffer` global.\n *\n * We use both a resolver and a plugin, because the resolver is used to detect\n * when a built-in module is imported, and the plugin is used to log a single\n * message when the compilation is complete. We can't do everything in a single\n * plugin, because the resolver doesn't have access to the compilation, and the\n * plugin doesn't have access to the resolver.\n */\n\nexport class SnapsBundleWarningsPlugin implements WebpackPluginInstance {\n /**\n * The options for the plugin.\n */\n readonly options: SnapsBundleWarningsPluginOptions;\n\n constructor(\n options: SnapsBundleWarningsPluginOptions = {\n buffer: true,\n builtIns: true,\n },\n ) {\n this.options = options;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n if (this.options.builtIns) {\n this.#checkBuiltIns(compiler);\n }\n\n if (this.options.buffer) {\n this.#checkBuffer(compiler);\n }\n }\n\n /**\n * Check if a built-in module is used, but not provided by Webpack's\n * `fallback` configuration.\n *\n * @param compiler - The Webpack compiler.\n */\n #checkBuiltIns(compiler: Compiler) {\n compiler.hooks.afterCompile.tap(this.constructor.name, (compilation) => {\n if (!this.options.builtInResolver) {\n return;\n }\n\n const { unresolvedModules } = this.options.builtInResolver;\n if (unresolvedModules.size === 0) {\n return;\n }\n\n const formattedModules = new Array(...unresolvedModules)\n .map((name) => `• ${name}`)\n .join('\\n');\n\n const webpackError = new WebpackError(\n `The snap attempted to use one or more Node.js builtins, but no browser fallback has been provided. The MetaMask Snaps CLI does not support Node.js builtins by default. If you want to use this module, you must set ${bold(\n '`polyfills`',\n )} to ${bold(\n '`true`',\n )} or an object with the builtins to polyfill as the key and ${bold(\n '`true`',\n )} as the value. To disable this warning, set ${bold(\n '`stats.builtIns`',\n )} to ${bold(\n '`false`',\n )} in your snap config file, or add the module to the ${bold(\n '`stats.builtIns.ignore`',\n )} array.`,\n );\n\n webpackError.details = formattedModules;\n compilation.warnings.push(webpackError);\n });\n }\n\n /**\n * Check if the given instance is a `ProvidePlugin`. This is not guaranteed to\n * be accurate, but it's good enough for our purposes. If we were to use\n * `instanceof` instead, it might not work if multiple versions of Webpack are\n * installed.\n *\n * @param instance - The instance to check.\n * @returns Whether the instance is a `ProvidePlugin`, i.e., whether it's an\n * object with the name `ProvidePlugin` and a `definitions` property.\n */\n #isProvidePlugin(instance: unknown): instance is ProvidePlugin {\n return (\n isObject(instance) &&\n instance.constructor.name === 'ProvidePlugin' &&\n hasProperty(instance, 'definitions')\n );\n }\n\n /**\n * Check if the `Buffer` global is used, but not provided by Webpack's\n * `DefinePlugin`.\n *\n * @param compiler - The Webpack compiler.\n */\n #checkBuffer(compiler: Compiler) {\n const plugin = compiler.options.plugins?.find((instance) =>\n this.#isProvidePlugin(instance),\n ) as ProvidePlugin | undefined;\n\n // If the `ProvidePlugin` is configured to provide `Buffer`, then we don't\n // need to warn the user.\n if (plugin) {\n const { definitions } = plugin;\n if (definitions.Buffer) {\n return;\n }\n }\n\n compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {\n compilation.hooks.afterProcessAssets.tap(\n this.constructor.name,\n (assets) => {\n // Check if assets use `Buffer`.\n const bufferAssets = Object.entries(assets)\n .filter(([name]) => name.endsWith('.js'))\n .filter(([, asset]) => asset.source().includes('Buffer'));\n\n if (bufferAssets.length === 0) {\n return;\n }\n\n compilation.warnings.push(\n new WebpackError(\n `The snap attempted to use the Node.js Buffer global, which is not supported in the MetaMask Snaps CLI by default. To use the Buffer global, you must polyfill Buffer by setting ${bold(\n '`buffer`',\n )} to ${bold('`true`')} in the ${bold(\n '`polyfills`',\n )} config object in your snap config. To disable this warning, set ${bold(\n '`stats.buffer`',\n )} to ${bold('`false`')} in your snap config file.`,\n ),\n );\n },\n );\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plugins.mjs","sourceRoot":"","sources":["../../src/webpack/plugins.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapManifest } from '@metamask/snaps-utils';\nimport { loadManifest } from '@metamask/snaps-utils/node';\nimport { assert, hasProperty, isObject } from '@metamask/utils';\nimport { bold, dim, red, yellow } from 'chalk';\nimport { isBuiltin } from 'module';\nimport type { Ora } from 'ora';\nimport { dirname, resolve } from 'path';\nimport type {\n Compiler,\n ProvidePlugin,\n Resolver,\n StatsError,\n WebpackPluginInstance,\n} from 'webpack';\nimport { Compilation, WebpackError, sources } from 'webpack';\n\nimport type { WebpackOptions } from './config';\nimport { formatText, pluralize, readWebpackFile } from './utils';\nimport { error, getErrorMessage, info, warn } from '../utils';\n\nexport type SnapsStatsPluginOptions = {\n /**\n * Whether to log the verbose stats.\n */\n verbose?: boolean;\n};\n\n/**\n * A plugin that logs the stats after compilation. This is useful for logging\n * the number of files compiled, and the time taken to compile them.\n */\nexport class SnapsStatsPlugin implements WebpackPluginInstance {\n /**\n * The options for the plugin.\n */\n readonly options: SnapsStatsPluginOptions;\n\n /**\n * The spinner to use for logging.\n */\n readonly #spinner?: Ora;\n\n constructor(\n options: SnapsStatsPluginOptions = {\n verbose: false,\n },\n spinner?: Ora,\n ) {\n this.options = options;\n this.#spinner = spinner;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n compiler.hooks.afterDone.tap(this.constructor.name, (stats) => {\n if (!stats) {\n return;\n }\n\n const { modules, time, errors, warnings } = stats.toJson();\n\n assert(modules, 'Modules must be defined in stats.');\n assert(time, 'Time must be defined in stats.');\n\n if (errors?.length) {\n const formattedErrors = errors\n .map((statsError) => this.#getStatsErrorMessage(statsError, red))\n .join('\\n\\n');\n\n error(\n `Compiled ${modules.length} ${pluralize(\n modules.length,\n 'file',\n )} in ${time}ms with ${errors.length} ${pluralize(\n errors.length,\n 'error',\n )}.\\n\\n${formattedErrors}\\n`,\n this.#spinner,\n );\n\n this.#spinner?.stop();\n\n process.exitCode = 1;\n return;\n }\n\n if (warnings?.length) {\n const formattedWarnings = warnings\n .map((statsWarning) =>\n this.#getStatsErrorMessage(statsWarning, yellow),\n )\n .join('\\n\\n');\n\n warn(\n `Compiled ${modules.length} ${pluralize(\n modules.length,\n 'file',\n )} in ${time}ms with ${warnings.length} ${pluralize(\n warnings.length,\n 'warning',\n )}.\\n\\n${formattedWarnings}\\n`,\n this.#spinner,\n );\n } else {\n info(\n `Compiled ${modules.length} ${pluralize(\n modules.length,\n 'file',\n )} in ${time}ms.`,\n this.#spinner,\n );\n }\n\n if (compiler.watchMode) {\n // The spinner may be restarted by the watch plugin, outside of the\n // `executeSteps` flow, so we stop it here just in case.\n this.#spinner?.succeed('Done!');\n }\n });\n }\n\n /**\n * Get the error message for the given stats error.\n *\n * @param statsError - The stats error.\n * @param color - The color to use for the error message.\n * @returns The error message.\n */\n #getStatsErrorMessage(\n statsError: StatsError,\n color: typeof red | typeof yellow,\n ) {\n const baseMessage = this.options.verbose\n ? getErrorMessage(statsError)\n : statsError.message;\n\n const [first, ...rest] = baseMessage.split('\\n');\n\n return [\n color(formatText(`• ${first}`, 4, 2)),\n ...rest.map((message) => formatText(color(message), 4)),\n statsError.details && `\\n${formatText(dim(statsError.details), 6)}`,\n ]\n .filter(Boolean)\n .join('\\n');\n }\n}\n\n/**\n * The options for the {@link SnapsWatchPlugin}.\n */\nexport type SnapsWatchPluginOptions = {\n /**\n * The path to the manifest, to determine which files to watch.\n */\n manifestPath: string;\n};\n\n/**\n * A plugin that adds extra files to watch. This is useful for watching files\n * that are not imported by the entry point, such as the `snap.manifest.json`\n * file.\n */\nexport class SnapsWatchPlugin implements WebpackPluginInstance {\n /**\n * The options for the plugin.\n */\n readonly options: SnapsWatchPluginOptions;\n\n /**\n * The spinner to use for logging.\n */\n readonly #spinner?: Ora;\n\n constructor(options: SnapsWatchPluginOptions, spinner?: Ora) {\n this.options = options;\n this.#spinner = spinner;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n compiler.hooks.invalid.tap(this.constructor.name, (file) => {\n this.#spinner?.start();\n info(`Changes detected in ${yellow(file)}, recompiling.`, this.#spinner);\n });\n\n compiler.hooks.afterEmit.tapPromise(\n this.constructor.name,\n async ({ fileDependencies }) => {\n const { files } = await loadManifest(this.options.manifestPath);\n\n files.forEach(fileDependencies.add.bind(fileDependencies));\n },\n );\n }\n}\n\n/**\n * The options for the {@link SnapsBuiltInResolver}.\n */\nexport type SnapsBuiltInResolverOptions = {\n /**\n * The built-in modules to ignore.\n */\n ignore?: string[];\n};\n\n/**\n * A Webpack resolve plugin.\n *\n * Copied from Webpack's own types, because the `ResolvePluginInstance` type is\n * a union, and can't be used as a type for a class.\n */\ntype ResolvePlugin = {\n apply: (resolver: Resolver) => void;\n};\n\n/**\n * A plugin that logs a message when a built-in module is not resolved. The\n * MetaMask Snaps CLI does not support built-in modules by default, and this\n * plugin is used to warn the user when they try to import a built-in module,\n * when no fallback is configured.\n */\nexport class SnapsBuiltInResolver implements ResolvePlugin {\n /**\n * The built-in modules that have been imported, but not resolved.\n */\n readonly unresolvedModules = new Set<string>();\n\n /**\n * The name of the resolver hook to tap into.\n */\n readonly #source = 'described-resolve';\n\n /**\n * The options for the plugin.\n */\n readonly options: SnapsBuiltInResolverOptions;\n\n constructor(\n options: SnapsBuiltInResolverOptions = {\n ignore: [],\n },\n ) {\n this.options = options;\n }\n\n /**\n * Apply the plugin to the Webpack resolver.\n *\n * @param resolver - The Webpack resolver.\n */\n apply(resolver: Resolver) {\n resolver\n .getHook(this.#source)\n .tapAsync(\n this.constructor.name,\n ({ module: isModule, request }, _, callback) => {\n if (!isModule || !request) {\n return callback();\n }\n\n const baseRequest = request.split('/')[0];\n if (\n isBuiltin(baseRequest) &&\n !this.options.ignore?.includes(baseRequest)\n ) {\n const fallback = resolver.options.fallback.find(\n ({ name }) => name === baseRequest,\n );\n\n if (fallback && !fallback.alias) {\n this.unresolvedModules.add(baseRequest);\n }\n }\n\n return callback();\n },\n );\n }\n}\n\n/**\n * The options for the {@link SnapsBundleWarningsPlugin}.\n */\nexport type SnapsBundleWarningsPluginOptions = {\n /**\n * The {@link SnapsBuiltInResolver} instance to use for detecting built-in\n * modules.\n */\n builtInResolver?: SnapsBuiltInResolver | false;\n\n /**\n * Whether to show warnings if built-in modules are used, but not provided by\n * Webpack's `fallback` configuration.\n */\n builtIns?: boolean;\n\n /**\n * Whether to show warnings if the `Buffer` global is used, but not provided\n * by Webpack's `DefinePlugin`.\n */\n buffer?: boolean;\n};\n\n/**\n * A plugin that logs a message when:\n *\n * - A built-in module is not resolved. The MetaMask Snaps CLI does not support\n * built-in modules by default, and this plugin is used to warn the user when\n * they try to import a built-in module, when no fallback is configured.\n * - A snap uses the `Buffer` global. The MetaMask Snaps CLI does not support\n * the `Buffer` global by default, and this plugin is used to warn the user when\n * they try to use the `Buffer` global.\n *\n * We use both a resolver and a plugin, because the resolver is used to detect\n * when a built-in module is imported, and the plugin is used to log a single\n * message when the compilation is complete. We can't do everything in a single\n * plugin, because the resolver doesn't have access to the compilation, and the\n * plugin doesn't have access to the resolver.\n */\n\nexport class SnapsBundleWarningsPlugin implements WebpackPluginInstance {\n /**\n * The options for the plugin.\n */\n readonly options: SnapsBundleWarningsPluginOptions;\n\n constructor(\n options: SnapsBundleWarningsPluginOptions = {\n buffer: true,\n builtIns: true,\n },\n ) {\n this.options = options;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n if (this.options.builtIns) {\n this.#checkBuiltIns(compiler);\n }\n\n if (this.options.buffer) {\n this.#checkBuffer(compiler);\n }\n }\n\n /**\n * Check if a built-in module is used, but not provided by Webpack's\n * `fallback` configuration.\n *\n * @param compiler - The Webpack compiler.\n */\n #checkBuiltIns(compiler: Compiler) {\n compiler.hooks.afterCompile.tap(this.constructor.name, (compilation) => {\n if (!this.options.builtInResolver) {\n return;\n }\n\n const { unresolvedModules } = this.options.builtInResolver;\n if (unresolvedModules.size === 0) {\n return;\n }\n\n const formattedModules = new Array(...unresolvedModules)\n .map((name) => `• ${name}`)\n .join('\\n');\n\n const webpackError = new WebpackError(\n `The snap attempted to use one or more Node.js builtins, but no browser fallback has been provided. The MetaMask Snaps CLI does not support Node.js builtins by default. If you want to use this module, you must set ${bold(\n '`polyfills`',\n )} to ${bold(\n '`true`',\n )} or an object with the builtins to polyfill as the key and ${bold(\n '`true`',\n )} as the value. To disable this warning, set ${bold(\n '`stats.builtIns`',\n )} to ${bold(\n '`false`',\n )} in your snap config file, or add the module to the ${bold(\n '`stats.builtIns.ignore`',\n )} array.`,\n );\n\n webpackError.details = formattedModules;\n compilation.warnings.push(webpackError);\n });\n }\n\n /**\n * Check if the given instance is a `ProvidePlugin`. This is not guaranteed to\n * be accurate, but it's good enough for our purposes. If we were to use\n * `instanceof` instead, it might not work if multiple versions of Webpack are\n * installed.\n *\n * @param instance - The instance to check.\n * @returns Whether the instance is a `ProvidePlugin`, i.e., whether it's an\n * object with the name `ProvidePlugin` and a `definitions` property.\n */\n #isProvidePlugin(instance: unknown): instance is ProvidePlugin {\n return (\n isObject(instance) &&\n instance.constructor.name === 'ProvidePlugin' &&\n hasProperty(instance, 'definitions')\n );\n }\n\n /**\n * Check if the `Buffer` global is used, but not provided by Webpack's\n * `DefinePlugin`.\n *\n * @param compiler - The Webpack compiler.\n */\n #checkBuffer(compiler: Compiler) {\n const plugin = compiler.options.plugins?.find((instance) =>\n this.#isProvidePlugin(instance),\n ) as ProvidePlugin | undefined;\n\n // If the `ProvidePlugin` is configured to provide `Buffer`, then we don't\n // need to warn the user.\n if (plugin) {\n const { definitions } = plugin;\n if (definitions.Buffer) {\n return;\n }\n }\n\n compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {\n compilation.hooks.afterProcessAssets.tap(\n this.constructor.name,\n (assets) => {\n // Check if assets use `Buffer`.\n const bufferAssets = Object.entries(assets)\n .filter(([name]) => name.endsWith('.js'))\n .filter(([, asset]) => asset.source().includes('Buffer'));\n\n if (bufferAssets.length === 0) {\n return;\n }\n\n compilation.warnings.push(\n new WebpackError(\n `The snap attempted to use the Node.js Buffer global, which is not supported in the MetaMask Snaps CLI by default. To use the Buffer global, you must polyfill Buffer by setting ${bold(\n '`buffer`',\n )} to ${bold('`true`')} in the ${bold(\n '`polyfills`',\n )} config object in your snap config. To disable this warning, set ${bold(\n '`stats.buffer`',\n )} to ${bold('`false`')} in your snap config file.`,\n ),\n );\n },\n );\n });\n }\n}\n\n/**\n * The options for the {@link PreinstalledSnapsBundlePlugin}.\n */\nexport type PreinstalledSnapsBundlePluginOptions = {\n /**\n * The path to the manifest file.\n */\n manifestPath: string;\n\n /**\n * The name of the output file.\n */\n outputName: string;\n\n /**\n * The preinstalled options from the Webpack configuration.\n */\n preinstalledOptions: WebpackOptions['preinstalledOptions'];\n};\n\n/**\n * A plugin that creates a preinstalled Snap bundle from the compiled bundle.\n * This will read the manifest, and any required files (locales, icon), and\n * create a `preinstalled-snap.json` file that can be used to install the Snap\n * as a preinstalled Snap.\n */\nexport class PreinstalledSnapsBundlePlugin implements WebpackPluginInstance {\n readonly #options: PreinstalledSnapsBundlePluginOptions;\n\n readonly #spinner?: Ora;\n\n constructor(options: PreinstalledSnapsBundlePluginOptions, spinner?: Ora) {\n this.#options = options;\n this.#spinner = spinner;\n }\n\n /**\n * Apply the plugin to the Webpack compiler.\n *\n * @param compiler - The Webpack compiler.\n */\n apply(compiler: Compiler) {\n compiler.hooks.compilation.tap(this.constructor.name, (compilation) => {\n compilation.hooks.processAssets.tapPromise(\n {\n name: this.constructor.name,\n // `PROCESS_ASSETS_STAGE_REPORT` is the last stage, so we ensure this\n // plugin runs after all other plugins have finished processing\n // assets.\n stage: Compilation.PROCESS_ASSETS_STAGE_REPORT,\n },\n async () => {\n info('Creating preinstalled Snap bundle.', this.#spinner);\n\n const asset = compilation.getAsset(this.#options.outputName);\n if (!asset) {\n compilation.errors.push(\n new WebpackError(\n 'Bundle asset not found. Make sure to build the project first.',\n ),\n );\n\n return;\n }\n\n const bundleSource = asset.source.source().toString();\n const preinstalledSnapBundleJson = JSON.stringify(\n await this.#createPreinstalledBundle(compilation, bundleSource),\n null,\n 2,\n );\n\n compilation.emitAsset(\n 'preinstalled-snap.json',\n new sources.RawSource(preinstalledSnapBundleJson),\n );\n },\n );\n });\n }\n\n /**\n * Create a preinstalled bundle object from the given bundle source. This will\n * load the manifest, read any required files (locales, icon), and return the\n * preinstalled bundle object.\n *\n * Custom auxiliary files are not currently supported in preinstalled Snaps.\n *\n * @param compilation - The Webpack compilation.\n * @param bundleSource - The source code of the bundle.\n * @returns The preinstalled bundle object.\n */\n async #createPreinstalledBundle(\n compilation: Compilation,\n bundleSource: string,\n ) {\n const { mergedManifest } = await loadManifest(this.#options.manifestPath);\n const manifest = mergedManifest as SnapManifest;\n\n const basePath = dirname(this.#options.manifestPath);\n\n const files = [\n {\n path: manifest.source.location.npm.filePath,\n value: bundleSource,\n },\n ];\n\n if (manifest.source.locales) {\n for (const locale of manifest.source.locales) {\n files.push({\n path: locale,\n value: await readWebpackFile(\n compilation.inputFileSystem,\n resolve(basePath, locale),\n ),\n });\n }\n }\n\n if (manifest.source.location.npm.iconPath) {\n const { iconPath } = manifest.source.location.npm;\n files.push({\n path: manifest.source.location.npm.iconPath,\n\n // The icon is expected to be an SVG file, so we read it as UTF-8.\n value: await readWebpackFile(\n compilation.inputFileSystem,\n resolve(basePath, iconPath),\n ),\n });\n }\n\n return {\n snapId: `npm:${manifest.source.location.npm.packageName}`,\n manifest,\n files,\n ...this.#options.preinstalledOptions,\n };\n }\n}\n"]}
|
package/dist/webpack/server.cjs
CHANGED
|
@@ -75,9 +75,9 @@ exports.getAllowedPaths = getAllowedPaths;
|
|
|
75
75
|
* `false` if it is not.
|
|
76
76
|
*/
|
|
77
77
|
async function isAllowedPath(request, config) {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const allowedPaths = getAllowedPaths(config,
|
|
78
|
+
const { mergedManifest } = await (0, node_1.loadManifest)((0, path_1.resolve)(config.server.root, config.manifest.path));
|
|
79
|
+
// TODO: Validate manifest, or at least add some basic checks.
|
|
80
|
+
const allowedPaths = getAllowedPaths(config, mergedManifest);
|
|
81
81
|
const path = request.path.slice(1);
|
|
82
82
|
return allowedPaths.some((allowedPath) => path === allowedPath);
|
|
83
83
|
}
|
|
@@ -113,6 +113,17 @@ function getServer(config, middleware = []) {
|
|
|
113
113
|
// eslint-disable-next-line promise/no-callback-in-promise
|
|
114
114
|
.catch(next);
|
|
115
115
|
});
|
|
116
|
+
// Serve the manifest file at the expected URL.
|
|
117
|
+
app.get('/snap.manifest.json', (_request, response, next) => {
|
|
118
|
+
(0, node_1.loadManifest)((0, path_1.resolve)(config.server.root, config.manifest.path))
|
|
119
|
+
.then(({ mergedManifest }) => {
|
|
120
|
+
response.setHeader('Cache-Control', 'no-cache');
|
|
121
|
+
response.setHeader('Access-Control-Allow-Origin', '*');
|
|
122
|
+
response.json(mergedManifest);
|
|
123
|
+
})
|
|
124
|
+
// eslint-disable-next-line promise/no-callback-in-promise
|
|
125
|
+
.catch(next);
|
|
126
|
+
});
|
|
116
127
|
// Serve the static files.
|
|
117
128
|
app.use((0, express_1.static)(config.server.root, {
|
|
118
129
|
dotfiles: 'deny',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.cjs","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapManifest } from '@metamask/snaps-utils';\nimport { NpmSnapFileNames, readJsonFile } from '@metamask/snaps-utils/node';\nimport type { Express, Request } from 'express';\nimport express, { static as expressStatic } from 'express';\nimport type { Server } from 'http';\nimport type { AddressInfo } from 'net';\nimport { join, relative, resolve as resolvePath, sep, posix } from 'path';\n\nimport type { ProcessedConfig } from '../config';\n\n/**\n * Get the relative path from one path to another.\n *\n * Note: This is a modified version of `path.relative` that uses Posix\n * separators for URL-compatibility.\n *\n * @param from - The path to start from.\n * @param to - The path to end at.\n * @returns The relative path.\n */\nfunction getRelativePath(from: string, to: string) {\n return relative(from, to).split(sep).join(posix.sep);\n}\n\n/**\n * Get the allowed paths for the static server. This includes the output file,\n * the manifest file, and any auxiliary/localization files.\n *\n * @param config - The config object.\n * @param manifest - The Snap manifest object.\n * @returns An array of allowed paths.\n */\nexport function getAllowedPaths(\n config: ProcessedConfig,\n manifest: SnapManifest,\n) {\n const auxiliaryFiles =\n manifest.source.files?.map((file) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, file),\n ),\n ) ?? [];\n\n const localizationFiles =\n manifest.source.locales?.map((localization) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, localization),\n ),\n ) ?? [];\n\n const otherFiles = manifest.source.location.npm.iconPath\n ? [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n manifest.source.location.npm.iconPath,\n ),\n ),\n ]\n : [];\n\n return [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n config.output.path,\n config.output.filename,\n ),\n ),\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, NpmSnapFileNames.Manifest),\n ),\n ...auxiliaryFiles,\n ...localizationFiles,\n ...otherFiles,\n ];\n}\n\n/**\n * Get whether the request path is allowed. This is used to check if the request\n * path is in the list of allowed paths for the static server.\n *\n * @param request - The request object.\n * @param config - The config object.\n * @returns A promise that resolves to `true` if the path is allowed, or\n * `false` if it is not.\n */\nasync function isAllowedPath(request: Request, config: ProcessedConfig) {\n const manifestPath = join(config.server.root, NpmSnapFileNames.Manifest);\n const { result } = await readJsonFile<SnapManifest>(manifestPath);\n const allowedPaths = getAllowedPaths(config, result);\n\n const path = request.path.slice(1);\n return allowedPaths.some((allowedPath) => path === allowedPath);\n}\n\ntype Middleware = (app: Express) => void;\n\n/**\n * Get a static server for development purposes.\n *\n * Note: We're intentionally not using `webpack-dev-server` here because it\n * adds a lot of extra stuff to the output that we don't need, and it's\n * difficult to customize.\n *\n * @param config - The config object.\n * @param middleware - An array of middleware functions to run before serving\n * the static files.\n * @returns An object with a `listen` method that returns a promise that\n * resolves when the server is listening.\n */\nexport function getServer(\n config: ProcessedConfig,\n middleware: Middleware[] = [],\n) {\n const app = express();\n\n // Run \"middleware\" functions before serving the static files.\n middleware.forEach((fn) => fn(app));\n\n // Check for allowed paths in the request URL.\n app.use((request, response, next) => {\n isAllowedPath(request, config)\n .then((allowed) => {\n if (allowed) {\n // eslint-disable-next-line promise/no-callback-in-promise\n next();\n return;\n }\n\n response.status(404);\n response.end();\n })\n // eslint-disable-next-line promise/no-callback-in-promise\n .catch(next);\n });\n\n // Serve the static files.\n app.use(\n expressStatic(config.server.root, {\n dotfiles: 'deny',\n setHeaders: (res) => {\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Access-Control-Allow-Origin', '*');\n },\n }),\n );\n\n /**\n * Start the server on the port specified in the config.\n *\n * @param port - The port to listen on.\n * @returns A promise that resolves when the server is listening. The promise\n * resolves to an object with the port and the server instance. Note that if\n * the `config.server.port` is `0`, the OS will choose a random port for us,\n * so we need to get the port from the server after it starts.\n */\n const listen = async (port = config.server.port) => {\n return new Promise<{\n port: number;\n server: Server;\n close: () => Promise<void>;\n }>((resolve, reject) => {\n // eslint-disable-next-line consistent-return\n const server = app.listen(port, (error) => {\n if (error) {\n return reject(error);\n }\n\n const close = async () => {\n await new Promise<void>((resolveClose, rejectClose) => {\n server.close((closeError) => {\n if (closeError) {\n return rejectClose(closeError);\n }\n\n return resolveClose();\n });\n });\n };\n\n const address = server.address() as AddressInfo;\n resolve({ port: address.port, server, close });\n });\n });\n };\n\n return { listen };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.cjs","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapManifest } from '@metamask/snaps-utils';\nimport { loadManifest, NpmSnapFileNames } from '@metamask/snaps-utils/node';\nimport type { Express, Request } from 'express';\nimport express, { static as expressStatic } from 'express';\nimport type { Server } from 'http';\nimport type { AddressInfo } from 'net';\nimport { relative, resolve as resolvePath, sep, posix } from 'path';\n\nimport type { ProcessedConfig } from '../config';\n\n/**\n * Get the relative path from one path to another.\n *\n * Note: This is a modified version of `path.relative` that uses Posix\n * separators for URL-compatibility.\n *\n * @param from - The path to start from.\n * @param to - The path to end at.\n * @returns The relative path.\n */\nfunction getRelativePath(from: string, to: string) {\n return relative(from, to).split(sep).join(posix.sep);\n}\n\n/**\n * Get the allowed paths for the static server. This includes the output file,\n * the manifest file, and any auxiliary/localization files.\n *\n * @param config - The config object.\n * @param manifest - The Snap manifest object.\n * @returns An array of allowed paths.\n */\nexport function getAllowedPaths(\n config: ProcessedConfig,\n manifest: SnapManifest,\n) {\n const auxiliaryFiles =\n manifest.source.files?.map((file) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, file),\n ),\n ) ?? [];\n\n const localizationFiles =\n manifest.source.locales?.map((localization) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, localization),\n ),\n ) ?? [];\n\n const otherFiles = manifest.source.location.npm.iconPath\n ? [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n manifest.source.location.npm.iconPath,\n ),\n ),\n ]\n : [];\n\n return [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n config.output.path,\n config.output.filename,\n ),\n ),\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, NpmSnapFileNames.Manifest),\n ),\n ...auxiliaryFiles,\n ...localizationFiles,\n ...otherFiles,\n ];\n}\n\n/**\n * Get whether the request path is allowed. This is used to check if the request\n * path is in the list of allowed paths for the static server.\n *\n * @param request - The request object.\n * @param config - The config object.\n * @returns A promise that resolves to `true` if the path is allowed, or\n * `false` if it is not.\n */\nasync function isAllowedPath(request: Request, config: ProcessedConfig) {\n const { mergedManifest } = await loadManifest(\n resolvePath(config.server.root, config.manifest.path),\n );\n\n // TODO: Validate manifest, or at least add some basic checks.\n const allowedPaths = getAllowedPaths(config, mergedManifest as SnapManifest);\n\n const path = request.path.slice(1);\n return allowedPaths.some((allowedPath) => path === allowedPath);\n}\n\ntype Middleware = (app: Express) => void;\n\n/**\n * Get a static server for development purposes.\n *\n * Note: We're intentionally not using `webpack-dev-server` here because it\n * adds a lot of extra stuff to the output that we don't need, and it's\n * difficult to customize.\n *\n * @param config - The config object.\n * @param middleware - An array of middleware functions to run before serving\n * the static files.\n * @returns An object with a `listen` method that returns a promise that\n * resolves when the server is listening.\n */\nexport function getServer(\n config: ProcessedConfig,\n middleware: Middleware[] = [],\n) {\n const app = express();\n\n // Run \"middleware\" functions before serving the static files.\n middleware.forEach((fn) => fn(app));\n\n // Check for allowed paths in the request URL.\n app.use((request, response, next) => {\n isAllowedPath(request, config)\n .then((allowed) => {\n if (allowed) {\n // eslint-disable-next-line promise/no-callback-in-promise\n next();\n return;\n }\n\n response.status(404);\n response.end();\n })\n // eslint-disable-next-line promise/no-callback-in-promise\n .catch(next);\n });\n\n // Serve the manifest file at the expected URL.\n app.get('/snap.manifest.json', (_request, response, next) => {\n loadManifest(resolvePath(config.server.root, config.manifest.path))\n .then(({ mergedManifest }) => {\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.json(mergedManifest);\n })\n // eslint-disable-next-line promise/no-callback-in-promise\n .catch(next);\n });\n\n // Serve the static files.\n app.use(\n expressStatic(config.server.root, {\n dotfiles: 'deny',\n setHeaders: (res) => {\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Access-Control-Allow-Origin', '*');\n },\n }),\n );\n\n /**\n * Start the server on the port specified in the config.\n *\n * @param port - The port to listen on.\n * @returns A promise that resolves when the server is listening. The promise\n * resolves to an object with the port and the server instance. Note that if\n * the `config.server.port` is `0`, the OS will choose a random port for us,\n * so we need to get the port from the server after it starts.\n */\n const listen = async (port = config.server.port) => {\n return new Promise<{\n port: number;\n server: Server;\n close: () => Promise<void>;\n }>((resolve, reject) => {\n // eslint-disable-next-line consistent-return\n const server = app.listen(port, (error) => {\n if (error) {\n return reject(error);\n }\n\n const close = async () => {\n await new Promise<void>((resolveClose, rejectClose) => {\n server.close((closeError) => {\n if (closeError) {\n return rejectClose(closeError);\n }\n\n return resolveClose();\n });\n });\n };\n\n const address = server.address() as AddressInfo;\n resolve({ port: address.port, server, close });\n });\n });\n };\n\n return { listen };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.cts","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAW,yBAAgB;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa;AAInC,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAkB;AAgBjD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,YAAY,YA+CvB;
|
|
1
|
+
{"version":3,"file":"server.d.cts","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAW,yBAAgB;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa;AAInC,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAkB;AAgBjD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,YAAY,YA+CvB;AAuBD,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,eAAe,EACvB,UAAU,GAAE,UAAU,EAAO;;cA0DnB,MAAM;gBACJ,MAAM;eACP,MAAM,QAAQ,IAAI,CAAC;;EA2B/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.mts","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAW,yBAAgB;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa;AAInC,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAkB;AAgBjD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,YAAY,YA+CvB;
|
|
1
|
+
{"version":3,"file":"server.d.mts","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,8BAA8B;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAW,yBAAgB;AAEhD,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa;AAInC,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAkB;AAgBjD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,YAAY,YA+CvB;AAuBD,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,eAAe,EACvB,UAAU,GAAE,UAAU,EAAO;;cA0DnB,MAAM;gBACJ,MAAM;eACP,MAAM,QAAQ,IAAI,CAAC;;EA2B/B"}
|
package/dist/webpack/server.mjs
CHANGED
|
@@ -4,10 +4,10 @@ function $importDefault(module) {
|
|
|
4
4
|
}
|
|
5
5
|
return module;
|
|
6
6
|
}
|
|
7
|
-
import {
|
|
7
|
+
import { loadManifest, NpmSnapFileNames } from "@metamask/snaps-utils/node";
|
|
8
8
|
import $express, { static as expressStatic } from "express/index.js";
|
|
9
9
|
const express = $importDefault($express);
|
|
10
|
-
import {
|
|
10
|
+
import { relative, resolve as resolvePath, sep, posix } from "path";
|
|
11
11
|
/**
|
|
12
12
|
* Get the relative path from one path to another.
|
|
13
13
|
*
|
|
@@ -55,9 +55,9 @@ export function getAllowedPaths(config, manifest) {
|
|
|
55
55
|
* `false` if it is not.
|
|
56
56
|
*/
|
|
57
57
|
async function isAllowedPath(request, config) {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const allowedPaths = getAllowedPaths(config,
|
|
58
|
+
const { mergedManifest } = await loadManifest(resolvePath(config.server.root, config.manifest.path));
|
|
59
|
+
// TODO: Validate manifest, or at least add some basic checks.
|
|
60
|
+
const allowedPaths = getAllowedPaths(config, mergedManifest);
|
|
61
61
|
const path = request.path.slice(1);
|
|
62
62
|
return allowedPaths.some((allowedPath) => path === allowedPath);
|
|
63
63
|
}
|
|
@@ -93,6 +93,17 @@ export function getServer(config, middleware = []) {
|
|
|
93
93
|
// eslint-disable-next-line promise/no-callback-in-promise
|
|
94
94
|
.catch(next);
|
|
95
95
|
});
|
|
96
|
+
// Serve the manifest file at the expected URL.
|
|
97
|
+
app.get('/snap.manifest.json', (_request, response, next) => {
|
|
98
|
+
loadManifest(resolvePath(config.server.root, config.manifest.path))
|
|
99
|
+
.then(({ mergedManifest }) => {
|
|
100
|
+
response.setHeader('Cache-Control', 'no-cache');
|
|
101
|
+
response.setHeader('Access-Control-Allow-Origin', '*');
|
|
102
|
+
response.json(mergedManifest);
|
|
103
|
+
})
|
|
104
|
+
// eslint-disable-next-line promise/no-callback-in-promise
|
|
105
|
+
.catch(next);
|
|
106
|
+
});
|
|
96
107
|
// Serve the static files.
|
|
97
108
|
app.use(expressStatic(config.server.root, {
|
|
98
109
|
dotfiles: 'deny',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.mjs","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapManifest } from '@metamask/snaps-utils';\nimport { NpmSnapFileNames, readJsonFile } from '@metamask/snaps-utils/node';\nimport type { Express, Request } from 'express';\nimport express, { static as expressStatic } from 'express';\nimport type { Server } from 'http';\nimport type { AddressInfo } from 'net';\nimport { join, relative, resolve as resolvePath, sep, posix } from 'path';\n\nimport type { ProcessedConfig } from '../config';\n\n/**\n * Get the relative path from one path to another.\n *\n * Note: This is a modified version of `path.relative` that uses Posix\n * separators for URL-compatibility.\n *\n * @param from - The path to start from.\n * @param to - The path to end at.\n * @returns The relative path.\n */\nfunction getRelativePath(from: string, to: string) {\n return relative(from, to).split(sep).join(posix.sep);\n}\n\n/**\n * Get the allowed paths for the static server. This includes the output file,\n * the manifest file, and any auxiliary/localization files.\n *\n * @param config - The config object.\n * @param manifest - The Snap manifest object.\n * @returns An array of allowed paths.\n */\nexport function getAllowedPaths(\n config: ProcessedConfig,\n manifest: SnapManifest,\n) {\n const auxiliaryFiles =\n manifest.source.files?.map((file) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, file),\n ),\n ) ?? [];\n\n const localizationFiles =\n manifest.source.locales?.map((localization) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, localization),\n ),\n ) ?? [];\n\n const otherFiles = manifest.source.location.npm.iconPath\n ? [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n manifest.source.location.npm.iconPath,\n ),\n ),\n ]\n : [];\n\n return [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n config.output.path,\n config.output.filename,\n ),\n ),\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, NpmSnapFileNames.Manifest),\n ),\n ...auxiliaryFiles,\n ...localizationFiles,\n ...otherFiles,\n ];\n}\n\n/**\n * Get whether the request path is allowed. This is used to check if the request\n * path is in the list of allowed paths for the static server.\n *\n * @param request - The request object.\n * @param config - The config object.\n * @returns A promise that resolves to `true` if the path is allowed, or\n * `false` if it is not.\n */\nasync function isAllowedPath(request: Request, config: ProcessedConfig) {\n const manifestPath = join(config.server.root, NpmSnapFileNames.Manifest);\n const { result } = await readJsonFile<SnapManifest>(manifestPath);\n const allowedPaths = getAllowedPaths(config, result);\n\n const path = request.path.slice(1);\n return allowedPaths.some((allowedPath) => path === allowedPath);\n}\n\ntype Middleware = (app: Express) => void;\n\n/**\n * Get a static server for development purposes.\n *\n * Note: We're intentionally not using `webpack-dev-server` here because it\n * adds a lot of extra stuff to the output that we don't need, and it's\n * difficult to customize.\n *\n * @param config - The config object.\n * @param middleware - An array of middleware functions to run before serving\n * the static files.\n * @returns An object with a `listen` method that returns a promise that\n * resolves when the server is listening.\n */\nexport function getServer(\n config: ProcessedConfig,\n middleware: Middleware[] = [],\n) {\n const app = express();\n\n // Run \"middleware\" functions before serving the static files.\n middleware.forEach((fn) => fn(app));\n\n // Check for allowed paths in the request URL.\n app.use((request, response, next) => {\n isAllowedPath(request, config)\n .then((allowed) => {\n if (allowed) {\n // eslint-disable-next-line promise/no-callback-in-promise\n next();\n return;\n }\n\n response.status(404);\n response.end();\n })\n // eslint-disable-next-line promise/no-callback-in-promise\n .catch(next);\n });\n\n // Serve the static files.\n app.use(\n expressStatic(config.server.root, {\n dotfiles: 'deny',\n setHeaders: (res) => {\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Access-Control-Allow-Origin', '*');\n },\n }),\n );\n\n /**\n * Start the server on the port specified in the config.\n *\n * @param port - The port to listen on.\n * @returns A promise that resolves when the server is listening. The promise\n * resolves to an object with the port and the server instance. Note that if\n * the `config.server.port` is `0`, the OS will choose a random port for us,\n * so we need to get the port from the server after it starts.\n */\n const listen = async (port = config.server.port) => {\n return new Promise<{\n port: number;\n server: Server;\n close: () => Promise<void>;\n }>((resolve, reject) => {\n // eslint-disable-next-line consistent-return\n const server = app.listen(port, (error) => {\n if (error) {\n return reject(error);\n }\n\n const close = async () => {\n await new Promise<void>((resolveClose, rejectClose) => {\n server.close((closeError) => {\n if (closeError) {\n return rejectClose(closeError);\n }\n\n return resolveClose();\n });\n });\n };\n\n const address = server.address() as AddressInfo;\n resolve({ port: address.port, server, close });\n });\n });\n };\n\n return { listen };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.mjs","sourceRoot":"","sources":["../../src/webpack/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SnapManifest } from '@metamask/snaps-utils';\nimport { loadManifest, NpmSnapFileNames } from '@metamask/snaps-utils/node';\nimport type { Express, Request } from 'express';\nimport express, { static as expressStatic } from 'express';\nimport type { Server } from 'http';\nimport type { AddressInfo } from 'net';\nimport { relative, resolve as resolvePath, sep, posix } from 'path';\n\nimport type { ProcessedConfig } from '../config';\n\n/**\n * Get the relative path from one path to another.\n *\n * Note: This is a modified version of `path.relative` that uses Posix\n * separators for URL-compatibility.\n *\n * @param from - The path to start from.\n * @param to - The path to end at.\n * @returns The relative path.\n */\nfunction getRelativePath(from: string, to: string) {\n return relative(from, to).split(sep).join(posix.sep);\n}\n\n/**\n * Get the allowed paths for the static server. This includes the output file,\n * the manifest file, and any auxiliary/localization files.\n *\n * @param config - The config object.\n * @param manifest - The Snap manifest object.\n * @returns An array of allowed paths.\n */\nexport function getAllowedPaths(\n config: ProcessedConfig,\n manifest: SnapManifest,\n) {\n const auxiliaryFiles =\n manifest.source.files?.map((file) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, file),\n ),\n ) ?? [];\n\n const localizationFiles =\n manifest.source.locales?.map((localization) =>\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, localization),\n ),\n ) ?? [];\n\n const otherFiles = manifest.source.location.npm.iconPath\n ? [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n manifest.source.location.npm.iconPath,\n ),\n ),\n ]\n : [];\n\n return [\n getRelativePath(\n config.server.root,\n resolvePath(\n config.server.root,\n config.output.path,\n config.output.filename,\n ),\n ),\n getRelativePath(\n config.server.root,\n resolvePath(config.server.root, NpmSnapFileNames.Manifest),\n ),\n ...auxiliaryFiles,\n ...localizationFiles,\n ...otherFiles,\n ];\n}\n\n/**\n * Get whether the request path is allowed. This is used to check if the request\n * path is in the list of allowed paths for the static server.\n *\n * @param request - The request object.\n * @param config - The config object.\n * @returns A promise that resolves to `true` if the path is allowed, or\n * `false` if it is not.\n */\nasync function isAllowedPath(request: Request, config: ProcessedConfig) {\n const { mergedManifest } = await loadManifest(\n resolvePath(config.server.root, config.manifest.path),\n );\n\n // TODO: Validate manifest, or at least add some basic checks.\n const allowedPaths = getAllowedPaths(config, mergedManifest as SnapManifest);\n\n const path = request.path.slice(1);\n return allowedPaths.some((allowedPath) => path === allowedPath);\n}\n\ntype Middleware = (app: Express) => void;\n\n/**\n * Get a static server for development purposes.\n *\n * Note: We're intentionally not using `webpack-dev-server` here because it\n * adds a lot of extra stuff to the output that we don't need, and it's\n * difficult to customize.\n *\n * @param config - The config object.\n * @param middleware - An array of middleware functions to run before serving\n * the static files.\n * @returns An object with a `listen` method that returns a promise that\n * resolves when the server is listening.\n */\nexport function getServer(\n config: ProcessedConfig,\n middleware: Middleware[] = [],\n) {\n const app = express();\n\n // Run \"middleware\" functions before serving the static files.\n middleware.forEach((fn) => fn(app));\n\n // Check for allowed paths in the request URL.\n app.use((request, response, next) => {\n isAllowedPath(request, config)\n .then((allowed) => {\n if (allowed) {\n // eslint-disable-next-line promise/no-callback-in-promise\n next();\n return;\n }\n\n response.status(404);\n response.end();\n })\n // eslint-disable-next-line promise/no-callback-in-promise\n .catch(next);\n });\n\n // Serve the manifest file at the expected URL.\n app.get('/snap.manifest.json', (_request, response, next) => {\n loadManifest(resolvePath(config.server.root, config.manifest.path))\n .then(({ mergedManifest }) => {\n response.setHeader('Cache-Control', 'no-cache');\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.json(mergedManifest);\n })\n // eslint-disable-next-line promise/no-callback-in-promise\n .catch(next);\n });\n\n // Serve the static files.\n app.use(\n expressStatic(config.server.root, {\n dotfiles: 'deny',\n setHeaders: (res) => {\n res.setHeader('Cache-Control', 'no-cache');\n res.setHeader('Access-Control-Allow-Origin', '*');\n },\n }),\n );\n\n /**\n * Start the server on the port specified in the config.\n *\n * @param port - The port to listen on.\n * @returns A promise that resolves when the server is listening. The promise\n * resolves to an object with the port and the server instance. Note that if\n * the `config.server.port` is `0`, the OS will choose a random port for us,\n * so we need to get the port from the server after it starts.\n */\n const listen = async (port = config.server.port) => {\n return new Promise<{\n port: number;\n server: Server;\n close: () => Promise<void>;\n }>((resolve, reject) => {\n // eslint-disable-next-line consistent-return\n const server = app.listen(port, (error) => {\n if (error) {\n return reject(error);\n }\n\n const close = async () => {\n await new Promise<void>((resolveClose, rejectClose) => {\n server.close((closeError) => {\n if (closeError) {\n return rejectClose(closeError);\n }\n\n return resolveClose();\n });\n });\n };\n\n const address = server.address() as AddressInfo;\n resolve({ port: address.port, server, close });\n });\n });\n };\n\n return { listen };\n}\n"]}
|
package/dist/webpack/utils.cjs
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getImageSVG = exports.formatText = exports.getEnvironmentVariables = exports.getFallbacks = exports.pluralize = exports.getBrowserslistTargets = exports.getProgressHandler = exports.getDevTool = exports.getDefaultLoader = exports.WEBPACK_FALLBACKS = exports.BROWSERSLIST_FILE = void 0;
|
|
6
|
+
exports.readWebpackFile = exports.getImageSVG = exports.formatText = exports.getEnvironmentVariables = exports.getFallbacks = exports.pluralize = exports.getBrowserslistTargets = exports.getProgressHandler = exports.getDevTool = exports.getDefaultLoader = exports.WEBPACK_FALLBACKS = exports.BROWSERSLIST_FILE = void 0;
|
|
7
7
|
const utils_1 = require("@metamask/utils");
|
|
8
8
|
const chalk_1 = require("chalk");
|
|
9
9
|
const fs_1 = require("fs");
|
|
@@ -340,4 +340,32 @@ function getImageSVG(mimeType, bytes) {
|
|
|
340
340
|
return `<svg xmlns="http://www.w3.org/2000/svg"><image href="${dataUrl}" /></svg>`;
|
|
341
341
|
}
|
|
342
342
|
exports.getImageSVG = getImageSVG;
|
|
343
|
+
/**
|
|
344
|
+
* Read a file from a Webpack input or output file system.
|
|
345
|
+
*
|
|
346
|
+
* @param fileSystem - The Webpack file system.
|
|
347
|
+
* @param path - The path to the file.
|
|
348
|
+
* @returns The file contents.
|
|
349
|
+
*/
|
|
350
|
+
async function readWebpackFile(fileSystem, path) {
|
|
351
|
+
// This function doesn't use `promisify`, since it doesn't seem to infer the
|
|
352
|
+
// correct type when providing an encoding. We also can't use `readFileSync`,
|
|
353
|
+
// because it isn't guaranteed to be available on all file systems.
|
|
354
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
355
|
+
fileSystem.readFile(path, 'utf-8', (error, data) => {
|
|
356
|
+
if (error) {
|
|
357
|
+
rejectPromise(error);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
// Webpack's file system can return `undefined` according to its types,
|
|
361
|
+
// in which case we assume the file was not found.
|
|
362
|
+
if (data === undefined) {
|
|
363
|
+
rejectPromise(new Error(`File not found: "${path}".`));
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
resolvePromise(data);
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
exports.readWebpackFile = readWebpackFile;
|
|
343
371
|
//# sourceMappingURL=utils.cjs.map
|