@metamask/snaps-utils 3.0.0 → 3.1.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/dist/cjs/auxiliary-files.js +40 -0
  3. package/dist/cjs/auxiliary-files.js.map +1 -0
  4. package/dist/cjs/errors.js +353 -3
  5. package/dist/cjs/errors.js.map +1 -1
  6. package/dist/cjs/index.browser.js +1 -0
  7. package/dist/cjs/index.browser.js.map +1 -1
  8. package/dist/cjs/index.executionenv.js +1 -0
  9. package/dist/cjs/index.executionenv.js.map +1 -1
  10. package/dist/cjs/index.js +1 -0
  11. package/dist/cjs/index.js.map +1 -1
  12. package/dist/cjs/manifest/manifest.js +25 -5
  13. package/dist/cjs/manifest/manifest.js.map +1 -1
  14. package/dist/cjs/manifest/validation.js +6 -1
  15. package/dist/cjs/manifest/validation.js.map +1 -1
  16. package/dist/cjs/npm.js +5 -3
  17. package/dist/cjs/npm.js.map +1 -1
  18. package/dist/cjs/snaps.js +3 -2
  19. package/dist/cjs/snaps.js.map +1 -1
  20. package/dist/cjs/types.js.map +1 -1
  21. package/dist/cjs/validation.js.map +1 -1
  22. package/dist/cjs/virtual-file/VirtualFile.js +6 -0
  23. package/dist/cjs/virtual-file/VirtualFile.js.map +1 -1
  24. package/dist/esm/auxiliary-files.js +28 -0
  25. package/dist/esm/auxiliary-files.js.map +1 -0
  26. package/dist/esm/errors.js +350 -1
  27. package/dist/esm/errors.js.map +1 -1
  28. package/dist/esm/index.browser.js +1 -0
  29. package/dist/esm/index.browser.js.map +1 -1
  30. package/dist/esm/index.executionenv.js +1 -0
  31. package/dist/esm/index.executionenv.js.map +1 -1
  32. package/dist/esm/index.js +1 -0
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/manifest/manifest.js +30 -5
  35. package/dist/esm/manifest/manifest.js.map +1 -1
  36. package/dist/esm/manifest/validation.js +3 -1
  37. package/dist/esm/manifest/validation.js.map +1 -1
  38. package/dist/esm/npm.js +5 -3
  39. package/dist/esm/npm.js.map +1 -1
  40. package/dist/esm/snaps.js +3 -2
  41. package/dist/esm/snaps.js.map +1 -1
  42. package/dist/esm/types.js.map +1 -1
  43. package/dist/esm/validation.js.map +1 -1
  44. package/dist/esm/virtual-file/VirtualFile.js +7 -1
  45. package/dist/esm/virtual-file/VirtualFile.js.map +1 -1
  46. package/dist/types/auxiliary-files.d.ts +13 -0
  47. package/dist/types/errors.d.ts +182 -0
  48. package/dist/types/index.browser.d.ts +1 -0
  49. package/dist/types/index.d.ts +1 -0
  50. package/dist/types/index.executionenv.d.ts +1 -0
  51. package/dist/types/manifest/manifest.d.ts +11 -1
  52. package/dist/types/manifest/validation.d.ts +4 -0
  53. package/dist/types/snaps.d.ts +13 -6
  54. package/dist/types/types.d.ts +6 -0
  55. package/dist/types/validation.d.ts +2 -2
  56. package/package.json +17 -18
@@ -1,4 +1,45 @@
1
- import { hasProperty, isObject } from '@metamask/utils';
1
+ function _check_private_redeclaration(obj, privateCollection) {
2
+ if (privateCollection.has(obj)) {
3
+ throw new TypeError("Cannot initialize the same private elements twice on an object");
4
+ }
5
+ }
6
+ function _class_apply_descriptor_get(receiver, descriptor) {
7
+ if (descriptor.get) {
8
+ return descriptor.get.call(receiver);
9
+ }
10
+ return descriptor.value;
11
+ }
12
+ function _class_apply_descriptor_set(receiver, descriptor, value) {
13
+ if (descriptor.set) {
14
+ descriptor.set.call(receiver, value);
15
+ } else {
16
+ if (!descriptor.writable) {
17
+ throw new TypeError("attempted to set read only private field");
18
+ }
19
+ descriptor.value = value;
20
+ }
21
+ }
22
+ function _class_extract_field_descriptor(receiver, privateMap, action) {
23
+ if (!privateMap.has(receiver)) {
24
+ throw new TypeError("attempted to " + action + " private field on non-instance");
25
+ }
26
+ return privateMap.get(receiver);
27
+ }
28
+ function _class_private_field_get(receiver, privateMap) {
29
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
30
+ return _class_apply_descriptor_get(receiver, descriptor);
31
+ }
32
+ function _class_private_field_init(obj, privateMap, value) {
33
+ _check_private_redeclaration(obj, privateMap);
34
+ privateMap.set(obj, value);
35
+ }
36
+ function _class_private_field_set(receiver, privateMap, value) {
37
+ var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
38
+ _class_apply_descriptor_set(receiver, descriptor, value);
39
+ return value;
40
+ }
41
+ import { errorCodes, JsonRpcError as RpcError, serializeCause } from '@metamask/rpc-errors';
42
+ import { hasProperty, isJsonRpcError, isObject, isValidJson } from '@metamask/utils';
2
43
  /**
3
44
  * Get the error message from an unknown error type.
4
45
  *
@@ -13,5 +54,313 @@ import { hasProperty, isObject } from '@metamask/utils';
13
54
  }
14
55
  return String(error);
15
56
  }
57
+ /**
58
+ * Get the error stack from an unknown error type.
59
+ *
60
+ * @param error - The error to get the stack from.
61
+ * @returns The error stack, or undefined if the error does not have a valid
62
+ * stack.
63
+ */ export function getErrorStack(error) {
64
+ if (isObject(error) && hasProperty(error, 'stack') && typeof error.stack === 'string') {
65
+ return error.stack;
66
+ }
67
+ return undefined;
68
+ }
69
+ /**
70
+ * Get the error code from an unknown error type.
71
+ *
72
+ * @param error - The error to get the code from.
73
+ * @returns The error code, or `-32603` if the error does not have a valid code.
74
+ */ export function getErrorCode(error) {
75
+ if (isObject(error) && hasProperty(error, 'code') && typeof error.code === 'number' && Number.isInteger(error.code)) {
76
+ return error.code;
77
+ }
78
+ return errorCodes.rpc.internal;
79
+ }
80
+ /**
81
+ * Get the error data from an unknown error type.
82
+ *
83
+ * @param error - The error to get the data from.
84
+ * @returns The error data, or an empty object if the error does not have valid
85
+ * data.
86
+ */ export function getErrorData(error) {
87
+ if (isObject(error) && hasProperty(error, 'data') && typeof error.data === 'object' && error.data !== null && isValidJson(error.data) && !Array.isArray(error.data)) {
88
+ return error.data;
89
+ }
90
+ return {};
91
+ }
92
+ export const SNAP_ERROR_WRAPPER_CODE = -31001;
93
+ export const SNAP_ERROR_WRAPPER_MESSAGE = 'Wrapped Snap Error';
94
+ export const SNAP_ERROR_CODE = -31002;
95
+ export const SNAP_ERROR_MESSAGE = 'Snap Error';
96
+ var _error = /*#__PURE__*/ new WeakMap(), _message = /*#__PURE__*/ new WeakMap(), _stack = /*#__PURE__*/ new WeakMap();
97
+ export class WrappedSnapError extends Error {
98
+ /**
99
+ * The error name.
100
+ *
101
+ * @returns The error name.
102
+ */ get name() {
103
+ return 'WrappedSnapError';
104
+ }
105
+ /**
106
+ * The error message.
107
+ *
108
+ * @returns The error message.
109
+ */ get message() {
110
+ return _class_private_field_get(this, _message);
111
+ }
112
+ /**
113
+ * The error stack.
114
+ *
115
+ * @returns The error stack.
116
+ */ get stack() {
117
+ return _class_private_field_get(this, _stack);
118
+ }
119
+ /**
120
+ * Convert the error to a JSON object.
121
+ *
122
+ * @returns The JSON object.
123
+ */ toJSON() {
124
+ const cause = isSnapError(_class_private_field_get(this, _error)) ? _class_private_field_get(this, _error).serialize() : serializeCause(_class_private_field_get(this, _error));
125
+ return {
126
+ code: SNAP_ERROR_WRAPPER_CODE,
127
+ message: SNAP_ERROR_WRAPPER_MESSAGE,
128
+ data: {
129
+ cause
130
+ }
131
+ };
132
+ }
133
+ /**
134
+ * Serialize the error to a JSON object. This is called by
135
+ * `@metamask/rpc-errors` when serializing the error.
136
+ *
137
+ * @returns The JSON object.
138
+ */ serialize() {
139
+ return this.toJSON();
140
+ }
141
+ /**
142
+ * Create a new `WrappedSnapError`.
143
+ *
144
+ * @param error - The error to create the `WrappedSnapError` from.
145
+ */ constructor(error){
146
+ const message = getErrorMessage(error);
147
+ super(message);
148
+ _class_private_field_init(this, _error, {
149
+ writable: true,
150
+ value: void 0
151
+ });
152
+ _class_private_field_init(this, _message, {
153
+ writable: true,
154
+ value: void 0
155
+ });
156
+ _class_private_field_init(this, _stack, {
157
+ writable: true,
158
+ value: void 0
159
+ });
160
+ _class_private_field_set(this, _error, error);
161
+ _class_private_field_set(this, _message, message);
162
+ _class_private_field_set(this, _stack, getErrorStack(error));
163
+ }
164
+ }
165
+ var _code = /*#__PURE__*/ new WeakMap(), _message1 = /*#__PURE__*/ new WeakMap(), _data = /*#__PURE__*/ new WeakMap(), _stack1 = /*#__PURE__*/ new WeakMap();
166
+ /**
167
+ * A generic error which can be thrown by a Snap, without it causing the Snap to
168
+ * crash.
169
+ */ export class SnapError extends Error {
170
+ /**
171
+ * The error name.
172
+ *
173
+ * @returns The error name.
174
+ */ get name() {
175
+ return 'SnapError';
176
+ }
177
+ /**
178
+ * The error code.
179
+ *
180
+ * @returns The error code.
181
+ */ get code() {
182
+ return _class_private_field_get(this, _code);
183
+ }
184
+ /**
185
+ * The error message.
186
+ *
187
+ * @returns The error message.
188
+ */ get message() {
189
+ return _class_private_field_get(this, _message1);
190
+ }
191
+ /**
192
+ * Additional data for the error.
193
+ *
194
+ * @returns Additional data for the error.
195
+ */ get data() {
196
+ return _class_private_field_get(this, _data);
197
+ }
198
+ /**
199
+ * The error stack.
200
+ *
201
+ * @returns The error stack.
202
+ */ get stack() {
203
+ return _class_private_field_get(this, _stack1);
204
+ }
205
+ /**
206
+ * Convert the error to a JSON object.
207
+ *
208
+ * @returns The JSON object.
209
+ */ toJSON() {
210
+ return {
211
+ code: SNAP_ERROR_CODE,
212
+ message: SNAP_ERROR_MESSAGE,
213
+ data: {
214
+ cause: {
215
+ code: this.code,
216
+ message: this.message,
217
+ stack: this.stack,
218
+ data: this.data
219
+ }
220
+ }
221
+ };
222
+ }
223
+ /**
224
+ * Serialize the error to a JSON object. This is called by
225
+ * `@metamask/rpc-errors` when serializing the error.
226
+ *
227
+ * @returns The JSON object.
228
+ */ serialize() {
229
+ return this.toJSON();
230
+ }
231
+ /**
232
+ * Create a new `SnapError`.
233
+ *
234
+ * @param error - The error to create the `SnapError` from. If this is a
235
+ * `string`, it will be used as the error message. If this is an `Error`, its
236
+ * `message` property will be used as the error message. If this is a
237
+ * `JsonRpcError`, its `message` property will be used as the error message
238
+ * and its `code` property will be used as the error code. Otherwise, the
239
+ * error will be converted to a string and used as the error message.
240
+ * @param data - Additional data to include in the error. This will be merged
241
+ * with the error data, if any.
242
+ */ constructor(error, data = {}){
243
+ const message = getErrorMessage(error);
244
+ super(message);
245
+ _class_private_field_init(this, _code, {
246
+ writable: true,
247
+ value: void 0
248
+ });
249
+ _class_private_field_init(this, _message1, {
250
+ writable: true,
251
+ value: void 0
252
+ });
253
+ _class_private_field_init(this, _data, {
254
+ writable: true,
255
+ value: void 0
256
+ });
257
+ _class_private_field_init(this, _stack1, {
258
+ writable: true,
259
+ value: void 0
260
+ });
261
+ _class_private_field_set(this, _message1, message);
262
+ _class_private_field_set(this, _code, getErrorCode(error));
263
+ _class_private_field_set(this, _data, {
264
+ ...getErrorData(error),
265
+ ...data
266
+ });
267
+ _class_private_field_set(this, _stack1, super.stack);
268
+ }
269
+ }
270
+ /**
271
+ * Check if an object is a `SnapError`.
272
+ *
273
+ * @param error - The object to check.
274
+ * @returns Whether the object is a `SnapError`.
275
+ */ export function isSnapError(error) {
276
+ if (isObject(error) && 'serialize' in error && typeof error.serialize === 'function') {
277
+ const serialized = error.serialize();
278
+ return isJsonRpcError(serialized) && isSerializedSnapError(serialized);
279
+ }
280
+ return false;
281
+ }
282
+ /**
283
+ * Check if a JSON-RPC error is a `SnapError`.
284
+ *
285
+ * @param error - The object to check.
286
+ * @returns Whether the object is a `SnapError`.
287
+ */ export function isSerializedSnapError(error) {
288
+ return error.code === SNAP_ERROR_CODE && error.message === SNAP_ERROR_MESSAGE;
289
+ }
290
+ /**
291
+ * Check if a JSON-RPC error is a `WrappedSnapError`.
292
+ *
293
+ * @param error - The object to check.
294
+ * @returns Whether the object is a `WrappedSnapError`.
295
+ */ export function isWrappedSnapError(error) {
296
+ return isJsonRpcError(error) && error.code === SNAP_ERROR_WRAPPER_CODE && error.message === SNAP_ERROR_WRAPPER_MESSAGE;
297
+ }
298
+ /**
299
+ * Get a JSON-RPC error with the given code, message, stack, and data.
300
+ *
301
+ * @param code - The error code.
302
+ * @param message - The error message.
303
+ * @param stack - The error stack.
304
+ * @param data - Additional data for the error.
305
+ * @returns The JSON-RPC error.
306
+ */ function getJsonRpcError(code, message, stack, data) {
307
+ const error = new RpcError(code, message, data);
308
+ error.stack = stack;
309
+ return error;
310
+ }
311
+ /**
312
+ * Attempt to unwrap an unknown error to a `JsonRpcError`. This function will
313
+ * try to get the error code, message, and data from the error, and return a
314
+ * `JsonRpcError` with those properties.
315
+ *
316
+ * @param error - The error to unwrap.
317
+ * @returns A tuple containing the unwrapped error and a boolean indicating
318
+ * whether the error was handled.
319
+ */ export function unwrapError(error) {
320
+ // This logic is a bit complicated, but it's necessary to handle all the
321
+ // different types of errors that can be thrown by a Snap.
322
+ // If the error is a wrapped Snap error, unwrap it.
323
+ if (isWrappedSnapError(error)) {
324
+ // The wrapped error can be a JSON-RPC error, or an unknown error. If it's
325
+ // a JSON-RPC error, we can unwrap it further.
326
+ if (isJsonRpcError(error.data.cause)) {
327
+ // If the JSON-RPC error is a wrapped Snap error, unwrap it further.
328
+ if (isSerializedSnapError(error.data.cause)) {
329
+ const { code, message, stack, data } = error.data.cause.data.cause;
330
+ return [
331
+ getJsonRpcError(code, message, stack, data),
332
+ true
333
+ ];
334
+ }
335
+ // Otherwise, we use the original JSON-RPC error.
336
+ const { code, message, stack, data } = error.data.cause;
337
+ return [
338
+ getJsonRpcError(code, message, stack, data),
339
+ false
340
+ ];
341
+ }
342
+ // Otherwise, we throw an internal error with the wrapped error as the
343
+ // message.
344
+ return [
345
+ getJsonRpcError(errorCodes.rpc.internal, getErrorMessage(error.data.cause), getErrorStack(error.data.cause)),
346
+ false
347
+ ];
348
+ }
349
+ // The error can be a non-wrapped JSON-RPC error, in which case we can just
350
+ // re-throw it with the same code, message, and data.
351
+ if (isJsonRpcError(error)) {
352
+ const { code, message, stack, data } = error;
353
+ return [
354
+ getJsonRpcError(code, message, stack, data),
355
+ false
356
+ ];
357
+ }
358
+ // If the error is not a wrapped error, we don't know how to handle it, so we
359
+ // throw an internal error with the error as the message.
360
+ return [
361
+ getJsonRpcError(errorCodes.rpc.internal, getErrorMessage(error), getErrorStack(error)),
362
+ false
363
+ ];
364
+ }
16
365
 
17
366
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors.ts"],"sourcesContent":["import { hasProperty, isObject } from '@metamask/utils';\n\n/**\n * Get the error message from an unknown error type.\n *\n * - If the error is an object with a `message` property, return the message.\n * - Otherwise, return the error converted to a string.\n *\n * @param error - The error to get the message from.\n * @returns The error message.\n */\nexport function getErrorMessage(error: unknown) {\n if (\n isObject(error) &&\n hasProperty(error, 'message') &&\n typeof error.message === 'string'\n ) {\n return error.message;\n }\n\n return String(error);\n}\n"],"names":["hasProperty","isObject","getErrorMessage","error","message","String"],"mappings":"AAAA,SAASA,WAAW,EAAEC,QAAQ,QAAQ,kBAAkB;AAExD;;;;;;;;CAQC,GACD,OAAO,SAASC,gBAAgBC,KAAc;IAC5C,IACEF,SAASE,UACTH,YAAYG,OAAO,cACnB,OAAOA,MAAMC,OAAO,KAAK,UACzB;QACA,OAAOD,MAAMC,OAAO;IACtB;IAEA,OAAOC,OAAOF;AAChB"}
1
+ {"version":3,"sources":["../../src/errors.ts"],"sourcesContent":["import {\n errorCodes,\n JsonRpcError as RpcError,\n serializeCause,\n} from '@metamask/rpc-errors';\nimport type { DataWithOptionalCause } from '@metamask/rpc-errors';\nimport type { Json, JsonRpcError } from '@metamask/utils';\nimport {\n hasProperty,\n isJsonRpcError,\n isObject,\n isValidJson,\n} from '@metamask/utils';\n\n/**\n * Get the error message from an unknown error type.\n *\n * - If the error is an object with a `message` property, return the message.\n * - Otherwise, return the error converted to a string.\n *\n * @param error - The error to get the message from.\n * @returns The error message.\n */\nexport function getErrorMessage(error: unknown) {\n if (\n isObject(error) &&\n hasProperty(error, 'message') &&\n typeof error.message === 'string'\n ) {\n return error.message;\n }\n\n return String(error);\n}\n\n/**\n * Get the error stack from an unknown error type.\n *\n * @param error - The error to get the stack from.\n * @returns The error stack, or undefined if the error does not have a valid\n * stack.\n */\nexport function getErrorStack(error: unknown) {\n if (\n isObject(error) &&\n hasProperty(error, 'stack') &&\n typeof error.stack === 'string'\n ) {\n return error.stack;\n }\n\n return undefined;\n}\n\n/**\n * Get the error code from an unknown error type.\n *\n * @param error - The error to get the code from.\n * @returns The error code, or `-32603` if the error does not have a valid code.\n */\nexport function getErrorCode(error: unknown) {\n if (\n isObject(error) &&\n hasProperty(error, 'code') &&\n typeof error.code === 'number' &&\n Number.isInteger(error.code)\n ) {\n return error.code;\n }\n\n return errorCodes.rpc.internal;\n}\n\n/**\n * Get the error data from an unknown error type.\n *\n * @param error - The error to get the data from.\n * @returns The error data, or an empty object if the error does not have valid\n * data.\n */\nexport function getErrorData(error: unknown) {\n if (\n isObject(error) &&\n hasProperty(error, 'data') &&\n typeof error.data === 'object' &&\n error.data !== null &&\n isValidJson(error.data) &&\n !Array.isArray(error.data)\n ) {\n return error.data;\n }\n\n return {};\n}\n\nexport const SNAP_ERROR_WRAPPER_CODE = -31001;\nexport const SNAP_ERROR_WRAPPER_MESSAGE = 'Wrapped Snap Error';\n\nexport const SNAP_ERROR_CODE = -31002;\nexport const SNAP_ERROR_MESSAGE = 'Snap Error';\n\nexport type SerializedSnapErrorWrapper = {\n code: typeof SNAP_ERROR_WRAPPER_CODE;\n message: typeof SNAP_ERROR_WRAPPER_MESSAGE;\n data: {\n cause: Json;\n };\n};\n\nexport type SerializedSnapError = {\n code: typeof SNAP_ERROR_CODE;\n message: typeof SNAP_ERROR_MESSAGE;\n data: {\n cause: JsonRpcError & {\n data: Record<string, Json>;\n };\n };\n};\n\nexport class WrappedSnapError extends Error {\n readonly #error: unknown;\n\n readonly #message: string;\n\n readonly #stack?: string;\n\n /**\n * Create a new `WrappedSnapError`.\n *\n * @param error - The error to create the `WrappedSnapError` from.\n */\n constructor(error: unknown) {\n const message = getErrorMessage(error);\n super(message);\n\n this.#error = error;\n this.#message = message;\n this.#stack = getErrorStack(error);\n }\n\n /**\n * The error name.\n *\n * @returns The error name.\n */\n get name() {\n return 'WrappedSnapError';\n }\n\n /**\n * The error message.\n *\n * @returns The error message.\n */\n get message() {\n return this.#message;\n }\n\n /**\n * The error stack.\n *\n * @returns The error stack.\n */\n get stack() {\n return this.#stack;\n }\n\n /**\n * Convert the error to a JSON object.\n *\n * @returns The JSON object.\n */\n toJSON(): SerializedSnapErrorWrapper {\n const cause = isSnapError(this.#error)\n ? this.#error.serialize()\n : serializeCause(this.#error);\n\n return {\n code: SNAP_ERROR_WRAPPER_CODE,\n message: SNAP_ERROR_WRAPPER_MESSAGE,\n data: {\n cause,\n },\n };\n }\n\n /**\n * Serialize the error to a JSON object. This is called by\n * `@metamask/rpc-errors` when serializing the error.\n *\n * @returns The JSON object.\n */\n serialize() {\n return this.toJSON();\n }\n}\n\n/**\n * A generic error which can be thrown by a Snap, without it causing the Snap to\n * crash.\n */\nexport class SnapError extends Error {\n readonly #code: number;\n\n readonly #message: string;\n\n readonly #data: Record<string, Json>;\n\n readonly #stack?: string;\n\n /**\n * Create a new `SnapError`.\n *\n * @param error - The error to create the `SnapError` from. If this is a\n * `string`, it will be used as the error message. If this is an `Error`, its\n * `message` property will be used as the error message. If this is a\n * `JsonRpcError`, its `message` property will be used as the error message\n * and its `code` property will be used as the error code. Otherwise, the\n * error will be converted to a string and used as the error message.\n * @param data - Additional data to include in the error. This will be merged\n * with the error data, if any.\n */\n constructor(\n error: string | Error | JsonRpcError,\n data: Record<string, Json> = {},\n ) {\n const message = getErrorMessage(error);\n super(message);\n\n this.#message = message;\n this.#code = getErrorCode(error);\n this.#data = { ...getErrorData(error), ...data };\n this.#stack = super.stack;\n }\n\n /**\n * The error name.\n *\n * @returns The error name.\n */\n get name() {\n return 'SnapError';\n }\n\n /**\n * The error code.\n *\n * @returns The error code.\n */\n get code() {\n return this.#code;\n }\n\n /**\n * The error message.\n *\n * @returns The error message.\n */\n get message() {\n return this.#message;\n }\n\n /**\n * Additional data for the error.\n *\n * @returns Additional data for the error.\n */\n get data() {\n return this.#data;\n }\n\n /**\n * The error stack.\n *\n * @returns The error stack.\n */\n get stack() {\n return this.#stack;\n }\n\n /**\n * Convert the error to a JSON object.\n *\n * @returns The JSON object.\n */\n toJSON(): SerializedSnapError {\n return {\n code: SNAP_ERROR_CODE,\n message: SNAP_ERROR_MESSAGE,\n data: {\n cause: {\n code: this.code,\n message: this.message,\n stack: this.stack,\n data: this.data,\n },\n },\n };\n }\n\n /**\n * Serialize the error to a JSON object. This is called by\n * `@metamask/rpc-errors` when serializing the error.\n *\n * @returns The JSON object.\n */\n serialize() {\n return this.toJSON();\n }\n}\n\n/**\n * Check if an object is a `SnapError`.\n *\n * @param error - The object to check.\n * @returns Whether the object is a `SnapError`.\n */\nexport function isSnapError(error: unknown): error is SnapError {\n if (\n isObject(error) &&\n 'serialize' in error &&\n typeof error.serialize === 'function'\n ) {\n const serialized = error.serialize();\n return isJsonRpcError(serialized) && isSerializedSnapError(serialized);\n }\n\n return false;\n}\n\n/**\n * Check if a JSON-RPC error is a `SnapError`.\n *\n * @param error - The object to check.\n * @returns Whether the object is a `SnapError`.\n */\nexport function isSerializedSnapError(\n error: JsonRpcError,\n): error is SerializedSnapError {\n return error.code === SNAP_ERROR_CODE && error.message === SNAP_ERROR_MESSAGE;\n}\n\n/**\n * Check if a JSON-RPC error is a `WrappedSnapError`.\n *\n * @param error - The object to check.\n * @returns Whether the object is a `WrappedSnapError`.\n */\nexport function isWrappedSnapError(\n error: unknown,\n): error is SerializedSnapErrorWrapper {\n return (\n isJsonRpcError(error) &&\n error.code === SNAP_ERROR_WRAPPER_CODE &&\n error.message === SNAP_ERROR_WRAPPER_MESSAGE\n );\n}\n\n/**\n * Get a JSON-RPC error with the given code, message, stack, and data.\n *\n * @param code - The error code.\n * @param message - The error message.\n * @param stack - The error stack.\n * @param data - Additional data for the error.\n * @returns The JSON-RPC error.\n */\nfunction getJsonRpcError(\n code: number,\n message: string,\n stack?: string,\n data?: Json,\n) {\n const error = new RpcError(code, message, data);\n error.stack = stack;\n\n return error;\n}\n\n/**\n * Attempt to unwrap an unknown error to a `JsonRpcError`. This function will\n * try to get the error code, message, and data from the error, and return a\n * `JsonRpcError` with those properties.\n *\n * @param error - The error to unwrap.\n * @returns A tuple containing the unwrapped error and a boolean indicating\n * whether the error was handled.\n */\nexport function unwrapError(\n error: unknown,\n): [error: RpcError<DataWithOptionalCause>, isHandled: boolean] {\n // This logic is a bit complicated, but it's necessary to handle all the\n // different types of errors that can be thrown by a Snap.\n\n // If the error is a wrapped Snap error, unwrap it.\n if (isWrappedSnapError(error)) {\n // The wrapped error can be a JSON-RPC error, or an unknown error. If it's\n // a JSON-RPC error, we can unwrap it further.\n if (isJsonRpcError(error.data.cause)) {\n // If the JSON-RPC error is a wrapped Snap error, unwrap it further.\n if (isSerializedSnapError(error.data.cause)) {\n const { code, message, stack, data } = error.data.cause.data.cause;\n return [getJsonRpcError(code, message, stack, data), true];\n }\n\n // Otherwise, we use the original JSON-RPC error.\n const { code, message, stack, data } = error.data.cause;\n return [getJsonRpcError(code, message, stack, data), false];\n }\n\n // Otherwise, we throw an internal error with the wrapped error as the\n // message.\n return [\n getJsonRpcError(\n errorCodes.rpc.internal,\n getErrorMessage(error.data.cause),\n getErrorStack(error.data.cause),\n ),\n false,\n ];\n }\n\n // The error can be a non-wrapped JSON-RPC error, in which case we can just\n // re-throw it with the same code, message, and data.\n if (isJsonRpcError(error)) {\n const { code, message, stack, data } = error;\n return [getJsonRpcError(code, message, stack, data), false];\n }\n\n // If the error is not a wrapped error, we don't know how to handle it, so we\n // throw an internal error with the error as the message.\n return [\n getJsonRpcError(\n errorCodes.rpc.internal,\n getErrorMessage(error),\n getErrorStack(error),\n ),\n false,\n ];\n}\n"],"names":["errorCodes","JsonRpcError","RpcError","serializeCause","hasProperty","isJsonRpcError","isObject","isValidJson","getErrorMessage","error","message","String","getErrorStack","stack","undefined","getErrorCode","code","Number","isInteger","rpc","internal","getErrorData","data","Array","isArray","SNAP_ERROR_WRAPPER_CODE","SNAP_ERROR_WRAPPER_MESSAGE","SNAP_ERROR_CODE","SNAP_ERROR_MESSAGE","WrappedSnapError","Error","name","toJSON","cause","isSnapError","serialize","constructor","SnapError","serialized","isSerializedSnapError","isWrappedSnapError","getJsonRpcError","unwrapError"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  export * from './array';
2
+ export * from './auxiliary-files';
2
3
  export * from './caveats';
3
4
  export * from './checksum';
4
5
  export * from './cronjob';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.browser.ts"],"sourcesContent":["export * from './array';\nexport * from './caveats';\nexport * from './checksum';\nexport * from './cronjob';\nexport * from './deep-clone';\nexport * from './default-endowments';\nexport * from './entropy';\nexport * from './enum';\nexport * from './errors';\nexport * from './handlers';\nexport * from './iframe';\nexport * from './json';\nexport * from './json-rpc';\nexport * from './logging';\nexport * from './manifest/index.browser';\nexport * from './namespace';\nexport * from './path';\nexport * from './snaps';\nexport * from './strings';\nexport * from './structs';\nexport * from './types';\nexport * from './validation';\nexport * from './versions';\nexport * from './virtual-file/index.browser';\n"],"names":[],"mappings":"AAAA,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,eAAe;AAC7B,cAAc,uBAAuB;AACrC,cAAc,YAAY;AAC1B,cAAc,SAAS;AACvB,cAAc,WAAW;AACzB,cAAc,aAAa;AAC3B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,2BAA2B;AACzC,cAAc,cAAc;AAC5B,cAAc,SAAS;AACvB,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,UAAU;AACxB,cAAc,eAAe;AAC7B,cAAc,aAAa;AAC3B,cAAc,+BAA+B"}
1
+ {"version":3,"sources":["../../src/index.browser.ts"],"sourcesContent":["export * from './array';\nexport * from './auxiliary-files';\nexport * from './caveats';\nexport * from './checksum';\nexport * from './cronjob';\nexport * from './deep-clone';\nexport * from './default-endowments';\nexport * from './entropy';\nexport * from './enum';\nexport * from './errors';\nexport * from './handlers';\nexport * from './iframe';\nexport * from './json';\nexport * from './json-rpc';\nexport * from './logging';\nexport * from './manifest/index.browser';\nexport * from './namespace';\nexport * from './path';\nexport * from './snaps';\nexport * from './strings';\nexport * from './structs';\nexport * from './types';\nexport * from './validation';\nexport * from './versions';\nexport * from './virtual-file/index.browser';\n"],"names":[],"mappings":"AAAA,cAAc,UAAU;AACxB,cAAc,oBAAoB;AAClC,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,eAAe;AAC7B,cAAc,uBAAuB;AACrC,cAAc,YAAY;AAC1B,cAAc,SAAS;AACvB,cAAc,WAAW;AACzB,cAAc,aAAa;AAC3B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,2BAA2B;AACzC,cAAc,cAAc;AAC5B,cAAc,SAAS;AACvB,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,UAAU;AACxB,cAAc,eAAe;AAC7B,cAAc,aAAa;AAC3B,cAAc,+BAA+B"}
@@ -1,4 +1,5 @@
1
1
  // Special entrypoint for execution environments for bundle sizing reasons
2
+ export * from './errors';
2
3
  export * from './handlers';
3
4
  export * from './logging';
4
5
  export * from './namespace';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.executionenv.ts"],"sourcesContent":["// Special entrypoint for execution environments for bundle sizing reasons\nexport * from './handlers';\nexport * from './logging';\nexport * from './namespace';\nexport * from './types';\n"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,cAAc;AAC5B,cAAc,UAAU"}
1
+ {"version":3,"sources":["../../src/index.executionenv.ts"],"sourcesContent":["// Special entrypoint for execution environments for bundle sizing reasons\nexport * from './errors';\nexport * from './handlers';\nexport * from './logging';\nexport * from './namespace';\nexport * from './types';\n"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,cAAc,WAAW;AACzB,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,cAAc;AAC5B,cAAc,UAAU"}
package/dist/esm/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './array';
2
+ export * from './auxiliary-files';
2
3
  export * from './caveats';
3
4
  export * from './cronjob';
4
5
  export * from './checksum';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './array';\nexport * from './caveats';\nexport * from './cronjob';\nexport * from './checksum';\nexport * from './deep-clone';\nexport * from './default-endowments';\nexport * from './entropy';\nexport * from './enum';\nexport * from './eval';\nexport * from './errors';\nexport * from './fs';\nexport * from './handlers';\nexport * from './iframe';\nexport * from './json';\nexport * from './json-rpc';\nexport * from './logging';\nexport * from './manifest';\nexport * from './mock';\nexport * from './namespace';\nexport * from './npm';\nexport * from './path';\nexport * from './post-process';\nexport * from './snaps';\nexport * from './strings';\nexport * from './structs';\nexport * from './types';\nexport * from './validation';\nexport * from './versions';\nexport * from './virtual-file';\n"],"names":[],"mappings":"AAAA,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,cAAc,uBAAuB;AACrC,cAAc,YAAY;AAC1B,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,WAAW;AACzB,cAAc,OAAO;AACrB,cAAc,aAAa;AAC3B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,SAAS;AACvB,cAAc,cAAc;AAC5B,cAAc,QAAQ;AACtB,cAAc,SAAS;AACvB,cAAc,iBAAiB;AAC/B,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,UAAU;AACxB,cAAc,eAAe;AAC7B,cAAc,aAAa;AAC3B,cAAc,iBAAiB"}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export * from './array';\nexport * from './auxiliary-files';\nexport * from './caveats';\nexport * from './cronjob';\nexport * from './checksum';\nexport * from './deep-clone';\nexport * from './default-endowments';\nexport * from './entropy';\nexport * from './enum';\nexport * from './eval';\nexport * from './errors';\nexport * from './fs';\nexport * from './handlers';\nexport * from './iframe';\nexport * from './json';\nexport * from './json-rpc';\nexport * from './logging';\nexport * from './manifest';\nexport * from './mock';\nexport * from './namespace';\nexport * from './npm';\nexport * from './path';\nexport * from './post-process';\nexport * from './snaps';\nexport * from './strings';\nexport * from './structs';\nexport * from './types';\nexport * from './validation';\nexport * from './versions';\nexport * from './virtual-file';\n"],"names":[],"mappings":"AAAA,cAAc,UAAU;AACxB,cAAc,oBAAoB;AAClC,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,eAAe;AAC7B,cAAc,uBAAuB;AACrC,cAAc,YAAY;AAC1B,cAAc,SAAS;AACvB,cAAc,SAAS;AACvB,cAAc,WAAW;AACzB,cAAc,OAAO;AACrB,cAAc,aAAa;AAC3B,cAAc,WAAW;AACzB,cAAc,SAAS;AACvB,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,aAAa;AAC3B,cAAc,SAAS;AACvB,cAAc,cAAc;AAC5B,cAAc,QAAQ;AACtB,cAAc,SAAS;AACvB,cAAc,iBAAiB;AAC/B,cAAc,UAAU;AACxB,cAAc,YAAY;AAC1B,cAAc,YAAY;AAC1B,cAAc,UAAU;AACxB,cAAc,eAAe;AAC7B,cAAc,aAAa;AAC3B,cAAc,iBAAiB"}
@@ -3,6 +3,7 @@ import deepEqual from 'fast-deep-equal';
3
3
  import { promises as fs } from 'fs';
4
4
  import pathUtils from 'path';
5
5
  import { deepClone } from '../deep-clone';
6
+ import { getErrorMessage } from '../errors';
6
7
  import { readJsonFile } from '../fs';
7
8
  import { validateNpmSnap } from '../npm';
8
9
  import { getSnapChecksum, ProgrammaticallyFixableSnapError, validateSnapShasum } from '../snaps';
@@ -41,7 +42,8 @@ const MANIFEST_SORT_ORDER = {
41
42
  manifest: manifestFile,
42
43
  packageJson: packageFile,
43
44
  sourceCode: await getSnapSourceCode(basePath, unvalidatedManifest, sourceCode),
44
- svgIcon: await getSnapIcon(basePath, unvalidatedManifest)
45
+ svgIcon: await getSnapIcon(basePath, unvalidatedManifest),
46
+ auxiliaryFiles: await getSnapAuxiliaryFiles(basePath, unvalidatedManifest) ?? []
45
47
  };
46
48
  let manifest;
47
49
  try {
@@ -173,7 +175,7 @@ const MANIFEST_SORT_ORDER = {
173
175
  const virtualFile = await readVirtualFile(pathUtils.join(basePath, sourceFilePath), 'utf8');
174
176
  return virtualFile;
175
177
  } catch (error) {
176
- throw new Error(`Failed to read snap bundle file: ${error.message}`);
178
+ throw new Error(`Failed to read snap bundle file: ${getErrorMessage(error)}`);
177
179
  }
178
180
  }
179
181
  /**
@@ -195,7 +197,28 @@ const MANIFEST_SORT_ORDER = {
195
197
  const virtualFile = await readVirtualFile(pathUtils.join(basePath, iconPath), 'utf8');
196
198
  return virtualFile;
197
199
  } catch (error) {
198
- throw new Error(`Failed to read snap icon file: ${error.message}`);
200
+ throw new Error(`Failed to read snap icon file: ${getErrorMessage(error)}`);
201
+ }
202
+ }
203
+ /**
204
+ * Given an unvalidated Snap manifest, attempts to extract the auxiliary files
205
+ * and read them.
206
+ *
207
+ * @param basePath - The path to the folder with the manifest files.
208
+ * @param manifest - The unvalidated Snap manifest file contents.
209
+ * @returns A list of auxiliary files and their contents, if any.
210
+ */ export async function getSnapAuxiliaryFiles(basePath, manifest) {
211
+ if (!isPlainObject(manifest)) {
212
+ return undefined;
213
+ }
214
+ const filePaths = manifest.source?.files;
215
+ if (!filePaths) {
216
+ return undefined;
217
+ }
218
+ try {
219
+ return await Promise.all(filePaths.map(async (filePath)=>readVirtualFile(pathUtils.join(basePath, filePath), 'utf8')));
220
+ } catch (error) {
221
+ throw new Error(`Failed to read snap files: ${getErrorMessage(error)}`);
199
222
  }
200
223
  }
201
224
  /**
@@ -225,7 +248,8 @@ const MANIFEST_SORT_ORDER = {
225
248
  * @param snapFiles.packageJson - The npm Snap's `package.json`.
226
249
  * @param snapFiles.sourceCode - The Snap's source code.
227
250
  * @param snapFiles.svgIcon - The Snap's optional icon.
228
- */ export function validateNpmSnapManifest({ manifest, packageJson, sourceCode, svgIcon }) {
251
+ * @param snapFiles.auxiliaryFiles - Any auxiliary files required by the snap at runtime.
252
+ */ export function validateNpmSnapManifest({ manifest, packageJson, sourceCode, svgIcon, auxiliaryFiles }) {
229
253
  const packageJsonName = packageJson.result.name;
230
254
  const packageJsonVersion = packageJson.result.version;
231
255
  const packageJsonRepository = packageJson.result.repository;
@@ -246,7 +270,8 @@ const MANIFEST_SORT_ORDER = {
246
270
  validateSnapShasum({
247
271
  manifest,
248
272
  sourceCode,
249
- svgIcon
273
+ svgIcon,
274
+ auxiliaryFiles
250
275
  }, `"${NpmSnapFileNames.Manifest}" "shasum" field does not match computed shasum.`);
251
276
  }
252
277
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/manifest/manifest.ts"],"sourcesContent":["import type { Json } from '@metamask/utils';\nimport { assertExhaustive, assert, isPlainObject } from '@metamask/utils';\nimport deepEqual from 'fast-deep-equal';\nimport { promises as fs } from 'fs';\nimport pathUtils from 'path';\n\nimport { deepClone } from '../deep-clone';\nimport { readJsonFile } from '../fs';\nimport { validateNpmSnap } from '../npm';\nimport {\n getSnapChecksum,\n ProgrammaticallyFixableSnapError,\n validateSnapShasum,\n} from '../snaps';\nimport type { SnapFiles, UnvalidatedSnapFiles } from '../types';\nimport { NpmSnapFileNames, SnapValidationFailureReason } from '../types';\nimport { readVirtualFile, VirtualFile } from '../virtual-file';\nimport type { SnapManifest } from './validation';\n\nconst MANIFEST_SORT_ORDER: Record<keyof SnapManifest, number> = {\n $schema: 1,\n version: 2,\n description: 3,\n proposedName: 4,\n repository: 5,\n source: 6,\n initialPermissions: 7,\n manifestVersion: 8,\n};\n\n/**\n * The result from the `checkManifest` function.\n *\n * @property manifest - The fixed manifest object.\n * @property updated - Whether the manifest was updated.\n * @property warnings - An array of warnings that were encountered during\n * processing of the manifest files. These warnings are not logged to the\n * console automatically, so depending on the environment the function is called\n * in, a different method for logging can be used.\n * @property errors - An array of errors that were encountered during\n * processing of the manifest files. These errors are not logged to the\n * console automatically, so depending on the environment the function is called\n * in, a different method for logging can be used.\n */\nexport type CheckManifestResult = {\n manifest: SnapManifest;\n updated?: boolean;\n warnings: string[];\n errors: string[];\n};\n\nexport type WriteFileFunction = (path: string, data: string) => Promise<void>;\n\n/**\n * Validates a snap.manifest.json file. Attempts to fix the manifest and write\n * the fixed version to disk if `writeManifest` is true. Throws if validation\n * fails.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param writeManifest - Whether to write the fixed manifest to disk.\n * @param sourceCode - The source code of the Snap.\n * @param writeFileFn - The function to use to write the manifest to disk.\n * @returns Whether the manifest was updated, and an array of warnings that\n * were encountered during processing of the manifest files.\n */\nexport async function checkManifest(\n basePath: string,\n writeManifest = true,\n sourceCode?: string,\n writeFileFn: WriteFileFunction = fs.writeFile,\n): Promise<CheckManifestResult> {\n const warnings: string[] = [];\n const errors: string[] = [];\n\n let updated = false;\n\n const manifestPath = pathUtils.join(basePath, NpmSnapFileNames.Manifest);\n const manifestFile = await readJsonFile(manifestPath);\n const unvalidatedManifest = manifestFile.result;\n\n const packageFile = await readJsonFile(\n pathUtils.join(basePath, NpmSnapFileNames.PackageJson),\n );\n\n const snapFiles: UnvalidatedSnapFiles = {\n manifest: manifestFile,\n packageJson: packageFile,\n sourceCode: await getSnapSourceCode(\n basePath,\n unvalidatedManifest,\n sourceCode,\n ),\n svgIcon: await getSnapIcon(basePath, unvalidatedManifest),\n };\n\n let manifest: VirtualFile<SnapManifest> | undefined;\n try {\n ({ manifest } = validateNpmSnap(snapFiles));\n } catch (error) {\n if (error instanceof ProgrammaticallyFixableSnapError) {\n errors.push(error.message);\n\n // If we get here, the files at least have the correct shape.\n const partiallyValidatedFiles = snapFiles as SnapFiles;\n\n let isInvalid = true;\n let currentError = error;\n const maxAttempts = Object.keys(SnapValidationFailureReason).length;\n\n // Attempt to fix all fixable validation failure reasons. All such reasons\n // are enumerated by the `SnapValidationFailureReason` enum, so we only\n // attempt to fix the manifest the same amount of times as there are\n // reasons in the enum.\n for (let attempts = 1; isInvalid && attempts <= maxAttempts; attempts++) {\n manifest = fixManifest(\n manifest\n ? { ...partiallyValidatedFiles, manifest }\n : partiallyValidatedFiles,\n currentError,\n );\n\n try {\n validateNpmSnapManifest({ ...partiallyValidatedFiles, manifest });\n\n isInvalid = false;\n } catch (nextValidationError) {\n currentError = nextValidationError;\n /* istanbul ignore next: this should be impossible */\n if (\n !(\n nextValidationError instanceof ProgrammaticallyFixableSnapError\n ) ||\n (attempts === maxAttempts && !isInvalid)\n ) {\n throw new Error(\n `Internal error: Failed to fix manifest. This is a bug, please report it. Reason:\\n${error.message}`,\n );\n }\n\n errors.push(currentError.message);\n }\n }\n\n updated = true;\n } else {\n throw error;\n }\n }\n\n // TypeScript assumes `manifest` can still be undefined, that is not the case.\n // But we assert to keep TypeScript happy.\n assert(manifest);\n\n const validatedManifest = manifest.result;\n\n // Check presence of recommended keys\n const recommendedFields = ['repository'] as const;\n\n const missingRecommendedFields = recommendedFields.filter(\n (key) => !validatedManifest[key],\n );\n\n if (missingRecommendedFields.length > 0) {\n warnings.push(\n `Missing recommended package.json properties:\\n${missingRecommendedFields.reduce(\n (allMissing, currentField) => {\n return `${allMissing}\\t${currentField}\\n`;\n },\n '',\n )}`,\n );\n }\n\n if (writeManifest) {\n try {\n const newManifest = `${JSON.stringify(\n getWritableManifest(validatedManifest),\n null,\n 2,\n )}\\n`;\n\n if (updated || newManifest !== manifestFile.value) {\n await writeFileFn(\n pathUtils.join(basePath, NpmSnapFileNames.Manifest),\n newManifest,\n );\n }\n } catch (error) {\n // Note: This error isn't pushed to the errors array, because it's not an\n // error in the manifest itself.\n throw new Error(`Failed to update snap.manifest.json: ${error.message}`);\n }\n }\n\n return { manifest: validatedManifest, updated, warnings, errors };\n}\n\n/**\n * Given the relevant Snap files (manifest, `package.json`, and bundle) and a\n * Snap manifest validation error, fixes the fault in the manifest that caused\n * the error.\n *\n * @param snapFiles - The contents of all Snap files.\n * @param error - The {@link ProgrammaticallyFixableSnapError} that was thrown.\n * @returns A copy of the manifest file where the cause of the error is fixed.\n */\nexport function fixManifest(\n snapFiles: SnapFiles,\n error: ProgrammaticallyFixableSnapError,\n): VirtualFile<SnapManifest> {\n const { manifest, packageJson } = snapFiles;\n const clonedFile = manifest.clone();\n const manifestCopy = clonedFile.result;\n\n switch (error.reason) {\n case SnapValidationFailureReason.NameMismatch:\n manifestCopy.source.location.npm.packageName = packageJson.result.name;\n break;\n\n case SnapValidationFailureReason.VersionMismatch:\n manifestCopy.version = packageJson.result.version;\n break;\n\n case SnapValidationFailureReason.RepositoryMismatch:\n manifestCopy.repository = packageJson.result.repository\n ? deepClone(packageJson.result.repository)\n : undefined;\n break;\n\n case SnapValidationFailureReason.ShasumMismatch:\n manifestCopy.source.shasum = getSnapChecksum(snapFiles);\n break;\n\n /* istanbul ignore next */\n default:\n assertExhaustive(error.reason);\n }\n\n clonedFile.result = manifestCopy;\n clonedFile.value = JSON.stringify(manifestCopy);\n return clonedFile;\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * bundle source file location and read the file.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @param sourceCode - Override source code for plugins.\n * @returns The contents of the bundle file, if any.\n */\nexport async function getSnapSourceCode(\n basePath: string,\n manifest: Json,\n sourceCode?: string,\n): Promise<VirtualFile | undefined> {\n if (!isPlainObject(manifest)) {\n return undefined;\n }\n\n const sourceFilePath = (manifest as Partial<SnapManifest>).source?.location\n ?.npm?.filePath;\n\n if (!sourceFilePath) {\n return undefined;\n }\n\n if (sourceCode) {\n return new VirtualFile({\n path: pathUtils.join(basePath, sourceFilePath),\n value: sourceCode,\n });\n }\n\n try {\n const virtualFile = await readVirtualFile(\n pathUtils.join(basePath, sourceFilePath),\n 'utf8',\n );\n return virtualFile;\n } catch (error) {\n throw new Error(`Failed to read snap bundle file: ${error.message}`);\n }\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * icon and read the file.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @returns The contents of the icon, if any.\n */\nexport async function getSnapIcon(\n basePath: string,\n manifest: Json,\n): Promise<VirtualFile | undefined> {\n if (!isPlainObject(manifest)) {\n return undefined;\n }\n\n const iconPath = (manifest as Partial<SnapManifest>).source?.location?.npm\n ?.iconPath;\n\n if (!iconPath) {\n return undefined;\n }\n\n try {\n const virtualFile = await readVirtualFile(\n pathUtils.join(basePath, iconPath),\n 'utf8',\n );\n return virtualFile;\n } catch (error) {\n throw new Error(`Failed to read snap icon file: ${error.message}`);\n }\n}\n\n/**\n * Sorts the given manifest in our preferred sort order and removes the\n * `repository` field if it is falsy (it may be `null`).\n *\n * @param manifest - The manifest to sort and modify.\n * @returns The disk-ready manifest.\n */\nexport function getWritableManifest(manifest: SnapManifest): SnapManifest {\n const { repository, ...remaining } = manifest;\n\n const keys = Object.keys(\n repository ? { ...remaining, repository } : remaining,\n ) as (keyof SnapManifest)[];\n\n const writableManifest = keys\n .sort((a, b) => MANIFEST_SORT_ORDER[a] - MANIFEST_SORT_ORDER[b])\n .reduce<Partial<SnapManifest>>(\n (result, key) => ({\n ...result,\n [key]: manifest[key],\n }),\n {},\n );\n\n return writableManifest as SnapManifest;\n}\n\n/**\n * Validates the fields of an npm Snap manifest that has already passed JSON\n * Schema validation.\n *\n * @param snapFiles - The relevant snap files to validate.\n * @param snapFiles.manifest - The npm Snap manifest to validate.\n * @param snapFiles.packageJson - The npm Snap's `package.json`.\n * @param snapFiles.sourceCode - The Snap's source code.\n * @param snapFiles.svgIcon - The Snap's optional icon.\n */\nexport function validateNpmSnapManifest({\n manifest,\n packageJson,\n sourceCode,\n svgIcon,\n}: SnapFiles) {\n const packageJsonName = packageJson.result.name;\n const packageJsonVersion = packageJson.result.version;\n const packageJsonRepository = packageJson.result.repository;\n\n const manifestPackageName = manifest.result.source.location.npm.packageName;\n const manifestPackageVersion = manifest.result.version;\n const manifestRepository = manifest.result.repository;\n\n if (packageJsonName !== manifestPackageName) {\n throw new ProgrammaticallyFixableSnapError(\n `\"${NpmSnapFileNames.Manifest}\" npm package name (\"${manifestPackageName}\") does not match the \"${NpmSnapFileNames.PackageJson}\" \"name\" field (\"${packageJsonName}\").`,\n SnapValidationFailureReason.NameMismatch,\n );\n }\n\n if (packageJsonVersion !== manifestPackageVersion) {\n throw new ProgrammaticallyFixableSnapError(\n `\"${NpmSnapFileNames.Manifest}\" npm package version (\"${manifestPackageVersion}\") does not match the \"${NpmSnapFileNames.PackageJson}\" \"version\" field (\"${packageJsonVersion}\").`,\n SnapValidationFailureReason.VersionMismatch,\n );\n }\n\n if (\n // The repository may be `undefined` in package.json but can only be defined\n // or `null` in the Snap manifest due to TS@<4.4 issues.\n (packageJsonRepository || manifestRepository) &&\n !deepEqual(packageJsonRepository, manifestRepository)\n ) {\n throw new ProgrammaticallyFixableSnapError(\n `\"${NpmSnapFileNames.Manifest}\" \"repository\" field does not match the \"${NpmSnapFileNames.PackageJson}\" \"repository\" field.`,\n SnapValidationFailureReason.RepositoryMismatch,\n );\n }\n\n validateSnapShasum(\n { manifest, sourceCode, svgIcon },\n `\"${NpmSnapFileNames.Manifest}\" \"shasum\" field does not match computed shasum.`,\n );\n}\n"],"names":["assertExhaustive","assert","isPlainObject","deepEqual","promises","fs","pathUtils","deepClone","readJsonFile","validateNpmSnap","getSnapChecksum","ProgrammaticallyFixableSnapError","validateSnapShasum","NpmSnapFileNames","SnapValidationFailureReason","readVirtualFile","VirtualFile","MANIFEST_SORT_ORDER","$schema","version","description","proposedName","repository","source","initialPermissions","manifestVersion","checkManifest","basePath","writeManifest","sourceCode","writeFileFn","writeFile","warnings","errors","updated","manifestPath","join","Manifest","manifestFile","unvalidatedManifest","result","packageFile","PackageJson","snapFiles","manifest","packageJson","getSnapSourceCode","svgIcon","getSnapIcon","error","push","message","partiallyValidatedFiles","isInvalid","currentError","maxAttempts","Object","keys","length","attempts","fixManifest","validateNpmSnapManifest","nextValidationError","Error","validatedManifest","recommendedFields","missingRecommendedFields","filter","key","reduce","allMissing","currentField","newManifest","JSON","stringify","getWritableManifest","value","clonedFile","clone","manifestCopy","reason","NameMismatch","location","npm","packageName","name","VersionMismatch","RepositoryMismatch","undefined","ShasumMismatch","shasum","sourceFilePath","filePath","path","virtualFile","iconPath","remaining","writableManifest","sort","a","b","packageJsonName","packageJsonVersion","packageJsonRepository","manifestPackageName","manifestPackageVersion","manifestRepository"],"mappings":"AACA,SAASA,gBAAgB,EAAEC,MAAM,EAAEC,aAAa,QAAQ,kBAAkB;AAC1E,OAAOC,eAAe,kBAAkB;AACxC,SAASC,YAAYC,EAAE,QAAQ,KAAK;AACpC,OAAOC,eAAe,OAAO;AAE7B,SAASC,SAAS,QAAQ,gBAAgB;AAC1C,SAASC,YAAY,QAAQ,QAAQ;AACrC,SAASC,eAAe,QAAQ,SAAS;AACzC,SACEC,eAAe,EACfC,gCAAgC,EAChCC,kBAAkB,QACb,WAAW;AAElB,SAASC,gBAAgB,EAAEC,2BAA2B,QAAQ,WAAW;AACzE,SAASC,eAAe,EAAEC,WAAW,QAAQ,kBAAkB;AAG/D,MAAMC,sBAA0D;IAC9DC,SAAS;IACTC,SAAS;IACTC,aAAa;IACbC,cAAc;IACdC,YAAY;IACZC,QAAQ;IACRC,oBAAoB;IACpBC,iBAAiB;AACnB;AAyBA;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,cACpBC,QAAgB,EAChBC,gBAAgB,IAAI,EACpBC,UAAmB,EACnBC,cAAiCzB,GAAG0B,SAAS;IAE7C,MAAMC,WAAqB,EAAE;IAC7B,MAAMC,SAAmB,EAAE;IAE3B,IAAIC,UAAU;IAEd,MAAMC,eAAe7B,UAAU8B,IAAI,CAACT,UAAUd,iBAAiBwB,QAAQ;IACvE,MAAMC,eAAe,MAAM9B,aAAa2B;IACxC,MAAMI,sBAAsBD,aAAaE,MAAM;IAE/C,MAAMC,cAAc,MAAMjC,aACxBF,UAAU8B,IAAI,CAACT,UAAUd,iBAAiB6B,WAAW;IAGvD,MAAMC,YAAkC;QACtCC,UAAUN;QACVO,aAAaJ;QACbZ,YAAY,MAAMiB,kBAChBnB,UACAY,qBACAV;QAEFkB,SAAS,MAAMC,YAAYrB,UAAUY;IACvC;IAEA,IAAIK;IACJ,IAAI;QACD,CAAA,EAAEA,QAAQ,EAAE,GAAGnC,gBAAgBkC,UAAS;IAC3C,EAAE,OAAOM,OAAO;QACd,IAAIA,iBAAiBtC,kCAAkC;YACrDsB,OAAOiB,IAAI,CAACD,MAAME,OAAO;YAEzB,6DAA6D;YAC7D,MAAMC,0BAA0BT;YAEhC,IAAIU,YAAY;YAChB,IAAIC,eAAeL;YACnB,MAAMM,cAAcC,OAAOC,IAAI,CAAC3C,6BAA6B4C,MAAM;YAEnE,0EAA0E;YAC1E,uEAAuE;YACvE,oEAAoE;YACpE,uBAAuB;YACvB,IAAK,IAAIC,WAAW,GAAGN,aAAaM,YAAYJ,aAAaI,WAAY;gBACvEf,WAAWgB,YACThB,WACI;oBAAE,GAAGQ,uBAAuB;oBAAER;gBAAS,IACvCQ,yBACJE;gBAGF,IAAI;oBACFO,wBAAwB;wBAAE,GAAGT,uBAAuB;wBAAER;oBAAS;oBAE/DS,YAAY;gBACd,EAAE,OAAOS,qBAAqB;oBAC5BR,eAAeQ;oBACf,mDAAmD,GACnD,IACE,CACEA,CAAAA,+BAA+BnD,gCAA+B,KAE/DgD,aAAaJ,eAAe,CAACF,WAC9B;wBACA,MAAM,IAAIU,MACR,CAAC,kFAAkF,EAAEd,MAAME,OAAO,CAAC,CAAC;oBAExG;oBAEAlB,OAAOiB,IAAI,CAACI,aAAaH,OAAO;gBAClC;YACF;YAEAjB,UAAU;QACZ,OAAO;YACL,MAAMe;QACR;IACF;IAEA,8EAA8E;IAC9E,0CAA0C;IAC1ChD,OAAO2C;IAEP,MAAMoB,oBAAoBpB,SAASJ,MAAM;IAEzC,qCAAqC;IACrC,MAAMyB,oBAAoB;QAAC;KAAa;IAExC,MAAMC,2BAA2BD,kBAAkBE,MAAM,CACvD,CAACC,MAAQ,CAACJ,iBAAiB,CAACI,IAAI;IAGlC,IAAIF,yBAAyBR,MAAM,GAAG,GAAG;QACvC1B,SAASkB,IAAI,CACX,CAAC,8CAA8C,EAAEgB,yBAAyBG,MAAM,CAC9E,CAACC,YAAYC;YACX,OAAO,CAAC,EAAED,WAAW,EAAE,EAAEC,aAAa,EAAE,CAAC;QAC3C,GACA,IACA,CAAC;IAEP;IAEA,IAAI3C,eAAe;QACjB,IAAI;YACF,MAAM4C,cAAc,CAAC,EAAEC,KAAKC,SAAS,CACnCC,oBAAoBX,oBACpB,MACA,GACA,EAAE,CAAC;YAEL,IAAI9B,WAAWsC,gBAAgBlC,aAAasC,KAAK,EAAE;gBACjD,MAAM9C,YACJxB,UAAU8B,IAAI,CAACT,UAAUd,iBAAiBwB,QAAQ,GAClDmC;YAEJ;QACF,EAAE,OAAOvB,OAAO;YACd,yEAAyE;YACzE,gCAAgC;YAChC,MAAM,IAAIc,MAAM,CAAC,qCAAqC,EAAEd,MAAME,OAAO,CAAC,CAAC;QACzE;IACF;IAEA,OAAO;QAAEP,UAAUoB;QAAmB9B;QAASF;QAAUC;IAAO;AAClE;AAEA;;;;;;;;CAQC,GACD,OAAO,SAAS2B,YACdjB,SAAoB,EACpBM,KAAuC;IAEvC,MAAM,EAAEL,QAAQ,EAAEC,WAAW,EAAE,GAAGF;IAClC,MAAMkC,aAAajC,SAASkC,KAAK;IACjC,MAAMC,eAAeF,WAAWrC,MAAM;IAEtC,OAAQS,MAAM+B,MAAM;QAClB,KAAKlE,4BAA4BmE,YAAY;YAC3CF,aAAaxD,MAAM,CAAC2D,QAAQ,CAACC,GAAG,CAACC,WAAW,GAAGvC,YAAYL,MAAM,CAAC6C,IAAI;YACtE;QAEF,KAAKvE,4BAA4BwE,eAAe;YAC9CP,aAAa5D,OAAO,GAAG0B,YAAYL,MAAM,CAACrB,OAAO;YACjD;QAEF,KAAKL,4BAA4ByE,kBAAkB;YACjDR,aAAazD,UAAU,GAAGuB,YAAYL,MAAM,CAAClB,UAAU,GACnDf,UAAUsC,YAAYL,MAAM,CAAClB,UAAU,IACvCkE;YACJ;QAEF,KAAK1E,4BAA4B2E,cAAc;YAC7CV,aAAaxD,MAAM,CAACmE,MAAM,GAAGhF,gBAAgBiC;YAC7C;QAEF,wBAAwB,GACxB;YACE3C,iBAAiBiD,MAAM+B,MAAM;IACjC;IAEAH,WAAWrC,MAAM,GAAGuC;IACpBF,WAAWD,KAAK,GAAGH,KAAKC,SAAS,CAACK;IAClC,OAAOF;AACT;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAe/B,kBACpBnB,QAAgB,EAChBiB,QAAc,EACdf,UAAmB;IAEnB,IAAI,CAAC3B,cAAc0C,WAAW;QAC5B,OAAO4C;IACT;IAEA,MAAMG,iBAAiB,AAAC/C,SAAmCrB,MAAM,EAAE2D,UAC/DC,KAAKS;IAET,IAAI,CAACD,gBAAgB;QACnB,OAAOH;IACT;IAEA,IAAI3D,YAAY;QACd,OAAO,IAAIb,YAAY;YACrB6E,MAAMvF,UAAU8B,IAAI,CAACT,UAAUgE;YAC/Bf,OAAO/C;QACT;IACF;IAEA,IAAI;QACF,MAAMiE,cAAc,MAAM/E,gBACxBT,UAAU8B,IAAI,CAACT,UAAUgE,iBACzB;QAEF,OAAOG;IACT,EAAE,OAAO7C,OAAO;QACd,MAAM,IAAIc,MAAM,CAAC,iCAAiC,EAAEd,MAAME,OAAO,CAAC,CAAC;IACrE;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,eAAeH,YACpBrB,QAAgB,EAChBiB,QAAc;IAEd,IAAI,CAAC1C,cAAc0C,WAAW;QAC5B,OAAO4C;IACT;IAEA,MAAMO,WAAW,AAACnD,SAAmCrB,MAAM,EAAE2D,UAAUC,KACnEY;IAEJ,IAAI,CAACA,UAAU;QACb,OAAOP;IACT;IAEA,IAAI;QACF,MAAMM,cAAc,MAAM/E,gBACxBT,UAAU8B,IAAI,CAACT,UAAUoE,WACzB;QAEF,OAAOD;IACT,EAAE,OAAO7C,OAAO;QACd,MAAM,IAAIc,MAAM,CAAC,+BAA+B,EAAEd,MAAME,OAAO,CAAC,CAAC;IACnE;AACF;AAEA;;;;;;CAMC,GACD,OAAO,SAASwB,oBAAoB/B,QAAsB;IACxD,MAAM,EAAEtB,UAAU,EAAE,GAAG0E,WAAW,GAAGpD;IAErC,MAAMa,OAAOD,OAAOC,IAAI,CACtBnC,aAAa;QAAE,GAAG0E,SAAS;QAAE1E;IAAW,IAAI0E;IAG9C,MAAMC,mBAAmBxC,KACtByC,IAAI,CAAC,CAACC,GAAGC,IAAMnF,mBAAmB,CAACkF,EAAE,GAAGlF,mBAAmB,CAACmF,EAAE,EAC9D/B,MAAM,CACL,CAAC7B,QAAQ4B,MAAS,CAAA;YAChB,GAAG5B,MAAM;YACT,CAAC4B,IAAI,EAAExB,QAAQ,CAACwB,IAAI;QACtB,CAAA,GACA,CAAC;IAGL,OAAO6B;AACT;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASpC,wBAAwB,EACtCjB,QAAQ,EACRC,WAAW,EACXhB,UAAU,EACVkB,OAAO,EACG;IACV,MAAMsD,kBAAkBxD,YAAYL,MAAM,CAAC6C,IAAI;IAC/C,MAAMiB,qBAAqBzD,YAAYL,MAAM,CAACrB,OAAO;IACrD,MAAMoF,wBAAwB1D,YAAYL,MAAM,CAAClB,UAAU;IAE3D,MAAMkF,sBAAsB5D,SAASJ,MAAM,CAACjB,MAAM,CAAC2D,QAAQ,CAACC,GAAG,CAACC,WAAW;IAC3E,MAAMqB,yBAAyB7D,SAASJ,MAAM,CAACrB,OAAO;IACtD,MAAMuF,qBAAqB9D,SAASJ,MAAM,CAAClB,UAAU;IAErD,IAAI+E,oBAAoBG,qBAAqB;QAC3C,MAAM,IAAI7F,iCACR,CAAC,CAAC,EAAEE,iBAAiBwB,QAAQ,CAAC,qBAAqB,EAAEmE,oBAAoB,uBAAuB,EAAE3F,iBAAiB6B,WAAW,CAAC,iBAAiB,EAAE2D,gBAAgB,GAAG,CAAC,EACtKvF,4BAA4BmE,YAAY;IAE5C;IAEA,IAAIqB,uBAAuBG,wBAAwB;QACjD,MAAM,IAAI9F,iCACR,CAAC,CAAC,EAAEE,iBAAiBwB,QAAQ,CAAC,wBAAwB,EAAEoE,uBAAuB,uBAAuB,EAAE5F,iBAAiB6B,WAAW,CAAC,oBAAoB,EAAE4D,mBAAmB,GAAG,CAAC,EAClLxF,4BAA4BwE,eAAe;IAE/C;IAEA,IAGE,AAFA,4EAA4E;IAC5E,wDAAwD;IACvDiB,CAAAA,yBAAyBG,kBAAiB,KAC3C,CAACvG,UAAUoG,uBAAuBG,qBAClC;QACA,MAAM,IAAI/F,iCACR,CAAC,CAAC,EAAEE,iBAAiBwB,QAAQ,CAAC,yCAAyC,EAAExB,iBAAiB6B,WAAW,CAAC,qBAAqB,CAAC,EAC5H5B,4BAA4ByE,kBAAkB;IAElD;IAEA3E,mBACE;QAAEgC;QAAUf;QAAYkB;IAAQ,GAChC,CAAC,CAAC,EAAElC,iBAAiBwB,QAAQ,CAAC,gDAAgD,CAAC;AAEnF"}
1
+ {"version":3,"sources":["../../../src/manifest/manifest.ts"],"sourcesContent":["import type { Json } from '@metamask/utils';\nimport { assertExhaustive, assert, isPlainObject } from '@metamask/utils';\nimport deepEqual from 'fast-deep-equal';\nimport { promises as fs } from 'fs';\nimport pathUtils from 'path';\n\nimport { deepClone } from '../deep-clone';\nimport { getErrorMessage } from '../errors';\nimport { readJsonFile } from '../fs';\nimport { validateNpmSnap } from '../npm';\nimport {\n getSnapChecksum,\n ProgrammaticallyFixableSnapError,\n validateSnapShasum,\n} from '../snaps';\nimport type { SnapFiles, UnvalidatedSnapFiles } from '../types';\nimport { NpmSnapFileNames, SnapValidationFailureReason } from '../types';\nimport { readVirtualFile, VirtualFile } from '../virtual-file';\nimport type { SnapManifest } from './validation';\n\nconst MANIFEST_SORT_ORDER: Record<keyof SnapManifest, number> = {\n $schema: 1,\n version: 2,\n description: 3,\n proposedName: 4,\n repository: 5,\n source: 6,\n initialPermissions: 7,\n manifestVersion: 8,\n};\n\n/**\n * The result from the `checkManifest` function.\n *\n * @property manifest - The fixed manifest object.\n * @property updated - Whether the manifest was updated.\n * @property warnings - An array of warnings that were encountered during\n * processing of the manifest files. These warnings are not logged to the\n * console automatically, so depending on the environment the function is called\n * in, a different method for logging can be used.\n * @property errors - An array of errors that were encountered during\n * processing of the manifest files. These errors are not logged to the\n * console automatically, so depending on the environment the function is called\n * in, a different method for logging can be used.\n */\nexport type CheckManifestResult = {\n manifest: SnapManifest;\n updated?: boolean;\n warnings: string[];\n errors: string[];\n};\n\nexport type WriteFileFunction = (path: string, data: string) => Promise<void>;\n\n/**\n * Validates a snap.manifest.json file. Attempts to fix the manifest and write\n * the fixed version to disk if `writeManifest` is true. Throws if validation\n * fails.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param writeManifest - Whether to write the fixed manifest to disk.\n * @param sourceCode - The source code of the Snap.\n * @param writeFileFn - The function to use to write the manifest to disk.\n * @returns Whether the manifest was updated, and an array of warnings that\n * were encountered during processing of the manifest files.\n */\nexport async function checkManifest(\n basePath: string,\n writeManifest = true,\n sourceCode?: string,\n writeFileFn: WriteFileFunction = fs.writeFile,\n): Promise<CheckManifestResult> {\n const warnings: string[] = [];\n const errors: string[] = [];\n\n let updated = false;\n\n const manifestPath = pathUtils.join(basePath, NpmSnapFileNames.Manifest);\n const manifestFile = await readJsonFile(manifestPath);\n const unvalidatedManifest = manifestFile.result;\n\n const packageFile = await readJsonFile(\n pathUtils.join(basePath, NpmSnapFileNames.PackageJson),\n );\n\n const snapFiles: UnvalidatedSnapFiles = {\n manifest: manifestFile,\n packageJson: packageFile,\n sourceCode: await getSnapSourceCode(\n basePath,\n unvalidatedManifest,\n sourceCode,\n ),\n svgIcon: await getSnapIcon(basePath, unvalidatedManifest),\n auxiliaryFiles:\n (await getSnapAuxiliaryFiles(basePath, unvalidatedManifest)) ?? [],\n };\n\n let manifest: VirtualFile<SnapManifest> | undefined;\n try {\n ({ manifest } = validateNpmSnap(snapFiles));\n } catch (error) {\n if (error instanceof ProgrammaticallyFixableSnapError) {\n errors.push(error.message);\n\n // If we get here, the files at least have the correct shape.\n const partiallyValidatedFiles = snapFiles as SnapFiles;\n\n let isInvalid = true;\n let currentError = error;\n const maxAttempts = Object.keys(SnapValidationFailureReason).length;\n\n // Attempt to fix all fixable validation failure reasons. All such reasons\n // are enumerated by the `SnapValidationFailureReason` enum, so we only\n // attempt to fix the manifest the same amount of times as there are\n // reasons in the enum.\n for (let attempts = 1; isInvalid && attempts <= maxAttempts; attempts++) {\n manifest = fixManifest(\n manifest\n ? { ...partiallyValidatedFiles, manifest }\n : partiallyValidatedFiles,\n currentError,\n );\n\n try {\n validateNpmSnapManifest({ ...partiallyValidatedFiles, manifest });\n\n isInvalid = false;\n } catch (nextValidationError) {\n currentError = nextValidationError;\n /* istanbul ignore next: this should be impossible */\n if (\n !(\n nextValidationError instanceof ProgrammaticallyFixableSnapError\n ) ||\n (attempts === maxAttempts && !isInvalid)\n ) {\n throw new Error(\n `Internal error: Failed to fix manifest. This is a bug, please report it. Reason:\\n${error.message}`,\n );\n }\n\n errors.push(currentError.message);\n }\n }\n\n updated = true;\n } else {\n throw error;\n }\n }\n\n // TypeScript assumes `manifest` can still be undefined, that is not the case.\n // But we assert to keep TypeScript happy.\n assert(manifest);\n\n const validatedManifest = manifest.result;\n\n // Check presence of recommended keys\n const recommendedFields = ['repository'] as const;\n\n const missingRecommendedFields = recommendedFields.filter(\n (key) => !validatedManifest[key],\n );\n\n if (missingRecommendedFields.length > 0) {\n warnings.push(\n `Missing recommended package.json properties:\\n${missingRecommendedFields.reduce(\n (allMissing, currentField) => {\n return `${allMissing}\\t${currentField}\\n`;\n },\n '',\n )}`,\n );\n }\n\n if (writeManifest) {\n try {\n const newManifest = `${JSON.stringify(\n getWritableManifest(validatedManifest),\n null,\n 2,\n )}\\n`;\n\n if (updated || newManifest !== manifestFile.value) {\n await writeFileFn(\n pathUtils.join(basePath, NpmSnapFileNames.Manifest),\n newManifest,\n );\n }\n } catch (error) {\n // Note: This error isn't pushed to the errors array, because it's not an\n // error in the manifest itself.\n throw new Error(`Failed to update snap.manifest.json: ${error.message}`);\n }\n }\n\n return { manifest: validatedManifest, updated, warnings, errors };\n}\n\n/**\n * Given the relevant Snap files (manifest, `package.json`, and bundle) and a\n * Snap manifest validation error, fixes the fault in the manifest that caused\n * the error.\n *\n * @param snapFiles - The contents of all Snap files.\n * @param error - The {@link ProgrammaticallyFixableSnapError} that was thrown.\n * @returns A copy of the manifest file where the cause of the error is fixed.\n */\nexport function fixManifest(\n snapFiles: SnapFiles,\n error: ProgrammaticallyFixableSnapError,\n): VirtualFile<SnapManifest> {\n const { manifest, packageJson } = snapFiles;\n const clonedFile = manifest.clone();\n const manifestCopy = clonedFile.result;\n\n switch (error.reason) {\n case SnapValidationFailureReason.NameMismatch:\n manifestCopy.source.location.npm.packageName = packageJson.result.name;\n break;\n\n case SnapValidationFailureReason.VersionMismatch:\n manifestCopy.version = packageJson.result.version;\n break;\n\n case SnapValidationFailureReason.RepositoryMismatch:\n manifestCopy.repository = packageJson.result.repository\n ? deepClone(packageJson.result.repository)\n : undefined;\n break;\n\n case SnapValidationFailureReason.ShasumMismatch:\n manifestCopy.source.shasum = getSnapChecksum(snapFiles);\n break;\n\n /* istanbul ignore next */\n default:\n assertExhaustive(error.reason);\n }\n\n clonedFile.result = manifestCopy;\n clonedFile.value = JSON.stringify(manifestCopy);\n return clonedFile;\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * bundle source file location and read the file.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @param sourceCode - Override source code for plugins.\n * @returns The contents of the bundle file, if any.\n */\nexport async function getSnapSourceCode(\n basePath: string,\n manifest: Json,\n sourceCode?: string,\n): Promise<VirtualFile | undefined> {\n if (!isPlainObject(manifest)) {\n return undefined;\n }\n\n const sourceFilePath = (manifest as Partial<SnapManifest>).source?.location\n ?.npm?.filePath;\n\n if (!sourceFilePath) {\n return undefined;\n }\n\n if (sourceCode) {\n return new VirtualFile({\n path: pathUtils.join(basePath, sourceFilePath),\n value: sourceCode,\n });\n }\n\n try {\n const virtualFile = await readVirtualFile(\n pathUtils.join(basePath, sourceFilePath),\n 'utf8',\n );\n return virtualFile;\n } catch (error) {\n throw new Error(\n `Failed to read snap bundle file: ${getErrorMessage(error)}`,\n );\n }\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * icon and read the file.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @returns The contents of the icon, if any.\n */\nexport async function getSnapIcon(\n basePath: string,\n manifest: Json,\n): Promise<VirtualFile | undefined> {\n if (!isPlainObject(manifest)) {\n return undefined;\n }\n\n const iconPath = (manifest as Partial<SnapManifest>).source?.location?.npm\n ?.iconPath;\n\n if (!iconPath) {\n return undefined;\n }\n\n try {\n const virtualFile = await readVirtualFile(\n pathUtils.join(basePath, iconPath),\n 'utf8',\n );\n return virtualFile;\n } catch (error) {\n throw new Error(`Failed to read snap icon file: ${getErrorMessage(error)}`);\n }\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the auxiliary files\n * and read them.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @returns A list of auxiliary files and their contents, if any.\n */\nexport async function getSnapAuxiliaryFiles(\n basePath: string,\n manifest: Json,\n): Promise<VirtualFile[] | undefined> {\n if (!isPlainObject(manifest)) {\n return undefined;\n }\n\n const filePaths = (manifest as Partial<SnapManifest>).source?.files;\n\n if (!filePaths) {\n return undefined;\n }\n\n try {\n return await Promise.all(\n filePaths.map(async (filePath) =>\n readVirtualFile(pathUtils.join(basePath, filePath), 'utf8'),\n ),\n );\n } catch (error) {\n throw new Error(`Failed to read snap files: ${getErrorMessage(error)}`);\n }\n}\n\n/**\n * Sorts the given manifest in our preferred sort order and removes the\n * `repository` field if it is falsy (it may be `null`).\n *\n * @param manifest - The manifest to sort and modify.\n * @returns The disk-ready manifest.\n */\nexport function getWritableManifest(manifest: SnapManifest): SnapManifest {\n const { repository, ...remaining } = manifest;\n\n const keys = Object.keys(\n repository ? { ...remaining, repository } : remaining,\n ) as (keyof SnapManifest)[];\n\n const writableManifest = keys\n .sort((a, b) => MANIFEST_SORT_ORDER[a] - MANIFEST_SORT_ORDER[b])\n .reduce<Partial<SnapManifest>>(\n (result, key) => ({\n ...result,\n [key]: manifest[key],\n }),\n {},\n );\n\n return writableManifest as SnapManifest;\n}\n\n/**\n * Validates the fields of an npm Snap manifest that has already passed JSON\n * Schema validation.\n *\n * @param snapFiles - The relevant snap files to validate.\n * @param snapFiles.manifest - The npm Snap manifest to validate.\n * @param snapFiles.packageJson - The npm Snap's `package.json`.\n * @param snapFiles.sourceCode - The Snap's source code.\n * @param snapFiles.svgIcon - The Snap's optional icon.\n * @param snapFiles.auxiliaryFiles - Any auxiliary files required by the snap at runtime.\n */\nexport function validateNpmSnapManifest({\n manifest,\n packageJson,\n sourceCode,\n svgIcon,\n auxiliaryFiles,\n}: SnapFiles) {\n const packageJsonName = packageJson.result.name;\n const packageJsonVersion = packageJson.result.version;\n const packageJsonRepository = packageJson.result.repository;\n\n const manifestPackageName = manifest.result.source.location.npm.packageName;\n const manifestPackageVersion = manifest.result.version;\n const manifestRepository = manifest.result.repository;\n\n if (packageJsonName !== manifestPackageName) {\n throw new ProgrammaticallyFixableSnapError(\n `\"${NpmSnapFileNames.Manifest}\" npm package name (\"${manifestPackageName}\") does not match the \"${NpmSnapFileNames.PackageJson}\" \"name\" field (\"${packageJsonName}\").`,\n SnapValidationFailureReason.NameMismatch,\n );\n }\n\n if (packageJsonVersion !== manifestPackageVersion) {\n throw new ProgrammaticallyFixableSnapError(\n `\"${NpmSnapFileNames.Manifest}\" npm package version (\"${manifestPackageVersion}\") does not match the \"${NpmSnapFileNames.PackageJson}\" \"version\" field (\"${packageJsonVersion}\").`,\n SnapValidationFailureReason.VersionMismatch,\n );\n }\n\n if (\n // The repository may be `undefined` in package.json but can only be defined\n // or `null` in the Snap manifest due to TS@<4.4 issues.\n (packageJsonRepository || manifestRepository) &&\n !deepEqual(packageJsonRepository, manifestRepository)\n ) {\n throw new ProgrammaticallyFixableSnapError(\n `\"${NpmSnapFileNames.Manifest}\" \"repository\" field does not match the \"${NpmSnapFileNames.PackageJson}\" \"repository\" field.`,\n SnapValidationFailureReason.RepositoryMismatch,\n );\n }\n\n validateSnapShasum(\n { manifest, sourceCode, svgIcon, auxiliaryFiles },\n `\"${NpmSnapFileNames.Manifest}\" \"shasum\" field does not match computed shasum.`,\n );\n}\n"],"names":["assertExhaustive","assert","isPlainObject","deepEqual","promises","fs","pathUtils","deepClone","getErrorMessage","readJsonFile","validateNpmSnap","getSnapChecksum","ProgrammaticallyFixableSnapError","validateSnapShasum","NpmSnapFileNames","SnapValidationFailureReason","readVirtualFile","VirtualFile","MANIFEST_SORT_ORDER","$schema","version","description","proposedName","repository","source","initialPermissions","manifestVersion","checkManifest","basePath","writeManifest","sourceCode","writeFileFn","writeFile","warnings","errors","updated","manifestPath","join","Manifest","manifestFile","unvalidatedManifest","result","packageFile","PackageJson","snapFiles","manifest","packageJson","getSnapSourceCode","svgIcon","getSnapIcon","auxiliaryFiles","getSnapAuxiliaryFiles","error","push","message","partiallyValidatedFiles","isInvalid","currentError","maxAttempts","Object","keys","length","attempts","fixManifest","validateNpmSnapManifest","nextValidationError","Error","validatedManifest","recommendedFields","missingRecommendedFields","filter","key","reduce","allMissing","currentField","newManifest","JSON","stringify","getWritableManifest","value","clonedFile","clone","manifestCopy","reason","NameMismatch","location","npm","packageName","name","VersionMismatch","RepositoryMismatch","undefined","ShasumMismatch","shasum","sourceFilePath","filePath","path","virtualFile","iconPath","filePaths","files","Promise","all","map","remaining","writableManifest","sort","a","b","packageJsonName","packageJsonVersion","packageJsonRepository","manifestPackageName","manifestPackageVersion","manifestRepository"],"mappings":"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"}
@@ -99,6 +99,7 @@ export const ChainIdsStruct = array(ChainIdStruct);
99
99
  snap_getEntropy: optional(object({})),
100
100
  wallet_snap: optional(SnapIdsStruct)
101
101
  });
102
+ export const SnapAuxilaryFilesStruct = array(string());
102
103
  export const SnapManifestStruct = object({
103
104
  version: VersionStruct,
104
105
  description: size(string(), 1, 280),
@@ -119,7 +120,8 @@ export const SnapManifestStruct = object({
119
120
  literal('https://registry.npmjs.org/')
120
121
  ])
121
122
  })
122
- })
123
+ }),
124
+ files: optional(SnapAuxilaryFilesStruct)
123
125
  }),
124
126
  initialPermissions: PermissionsStruct,
125
127
  manifestVersion: literal('0.1'),