@metamask/snaps-jest 0.35.1-flask.1

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 (89) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +587 -0
  3. package/dist/cjs/environment.js +205 -0
  4. package/dist/cjs/environment.js.map +1 -0
  5. package/dist/cjs/helpers.js +67 -0
  6. package/dist/cjs/helpers.js.map +1 -0
  7. package/dist/cjs/index.js +42 -0
  8. package/dist/cjs/index.js.map +1 -0
  9. package/dist/cjs/internals/environment.js +19 -0
  10. package/dist/cjs/internals/environment.js.map +1 -0
  11. package/dist/cjs/internals/index.js +28 -0
  12. package/dist/cjs/internals/index.js.map +1 -0
  13. package/dist/cjs/internals/interface.js +103 -0
  14. package/dist/cjs/internals/interface.js.map +1 -0
  15. package/dist/cjs/internals/logger.js +14 -0
  16. package/dist/cjs/internals/logger.js.map +1 -0
  17. package/dist/cjs/internals/network.js +146 -0
  18. package/dist/cjs/internals/network.js.map +1 -0
  19. package/dist/cjs/internals/request.js +121 -0
  20. package/dist/cjs/internals/request.js.map +1 -0
  21. package/dist/cjs/internals/server.js +75 -0
  22. package/dist/cjs/internals/server.js.map +1 -0
  23. package/dist/cjs/internals/structs.js +124 -0
  24. package/dist/cjs/internals/structs.js.map +1 -0
  25. package/dist/cjs/internals/types.js +6 -0
  26. package/dist/cjs/internals/types.js.map +1 -0
  27. package/dist/cjs/internals/wait-for.js +63 -0
  28. package/dist/cjs/internals/wait-for.js.map +1 -0
  29. package/dist/cjs/matchers.js +117 -0
  30. package/dist/cjs/matchers.js.map +1 -0
  31. package/dist/cjs/options.js +29 -0
  32. package/dist/cjs/options.js.map +1 -0
  33. package/dist/cjs/setup.js +10 -0
  34. package/dist/cjs/setup.js.map +1 -0
  35. package/dist/cjs/types.js +13 -0
  36. package/dist/cjs/types.js.map +1 -0
  37. package/dist/esm/environment.js +182 -0
  38. package/dist/esm/environment.js.map +1 -0
  39. package/dist/esm/helpers.js +82 -0
  40. package/dist/esm/helpers.js.map +1 -0
  41. package/dist/esm/index.js +6 -0
  42. package/dist/esm/index.js.map +1 -0
  43. package/dist/esm/internals/environment.js +14 -0
  44. package/dist/esm/internals/environment.js.map +1 -0
  45. package/dist/esm/internals/index.js +12 -0
  46. package/dist/esm/internals/index.js.map +1 -0
  47. package/dist/esm/internals/interface.js +100 -0
  48. package/dist/esm/internals/interface.js.map +1 -0
  49. package/dist/esm/internals/logger.js +4 -0
  50. package/dist/esm/internals/logger.js.map +1 -0
  51. package/dist/esm/internals/network.js +141 -0
  52. package/dist/esm/internals/network.js.map +1 -0
  53. package/dist/esm/internals/request.js +120 -0
  54. package/dist/esm/internals/request.js.map +1 -0
  55. package/dist/esm/internals/server.js +68 -0
  56. package/dist/esm/internals/server.js.map +1 -0
  57. package/dist/esm/internals/structs.js +100 -0
  58. package/dist/esm/internals/structs.js.map +1 -0
  59. package/dist/esm/internals/types.js +3 -0
  60. package/dist/esm/internals/types.js.map +1 -0
  61. package/dist/esm/internals/wait-for.js +63 -0
  62. package/dist/esm/internals/wait-for.js.map +1 -0
  63. package/dist/esm/matchers.js +108 -0
  64. package/dist/esm/matchers.js.map +1 -0
  65. package/dist/esm/options.js +26 -0
  66. package/dist/esm/options.js.map +1 -0
  67. package/dist/esm/setup.js +6 -0
  68. package/dist/esm/setup.js.map +1 -0
  69. package/dist/esm/types.js +3 -0
  70. package/dist/esm/types.js.map +1 -0
  71. package/dist/types/environment.d.ts +53 -0
  72. package/dist/types/helpers.d.ts +28 -0
  73. package/dist/types/index.d.ts +4 -0
  74. package/dist/types/internals/environment.d.ts +7 -0
  75. package/dist/types/internals/index.d.ts +9 -0
  76. package/dist/types/internals/interface.d.ts +25 -0
  77. package/dist/types/internals/logger.d.ts +2 -0
  78. package/dist/types/internals/network.d.ts +87 -0
  79. package/dist/types/internals/request.d.ts +58 -0
  80. package/dist/types/internals/server.d.ts +14 -0
  81. package/dist/types/internals/structs.d.ts +164 -0
  82. package/dist/types/internals/types.d.ts +19 -0
  83. package/dist/types/internals/wait-for.d.ts +38 -0
  84. package/dist/types/matchers.d.ts +29 -0
  85. package/dist/types/options.d.ts +92 -0
  86. package/dist/types/setup.d.ts +1 -0
  87. package/dist/types/types.d.ts +241 -0
  88. package/jest-preset.js +18 -0
  89. package/package.json +120 -0
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ MockOptionsStruct: function() {
13
+ return MockOptionsStruct;
14
+ },
15
+ mock: function() {
16
+ return mock;
17
+ },
18
+ mockJsonRpc: function() {
19
+ return mockJsonRpc;
20
+ }
21
+ });
22
+ const _snapssimulator = require("@metamask/snaps-simulator");
23
+ const _utils = require("@metamask/utils");
24
+ const _superstruct = require("superstruct");
25
+ const _logger = require("./logger");
26
+ /**
27
+ * The default headers to use for mocked responses. These headers are used to
28
+ * enable CORS.
29
+ */ const DEFAULT_HEADERS = {
30
+ /* eslint-disable @typescript-eslint/naming-convention */ 'Access-Control-Allow-Origin': '*',
31
+ 'Access-Control-Allow-Credentials': 'true',
32
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
33
+ 'Access-Control-Allow-Headers': 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers'
34
+ };
35
+ const log = (0, _utils.createModuleLogger)(_logger.rootLogger, 'network');
36
+ const MockOptionsBaseStruct = (0, _superstruct.object)({
37
+ response: (0, _superstruct.defaulted)((0, _superstruct.object)({
38
+ status: (0, _superstruct.defaulted)((0, _superstruct.number)(), 200),
39
+ headers: (0, _superstruct.defaulted)((0, _superstruct.record)((0, _superstruct.string)(), (0, _superstruct.unknown)()), DEFAULT_HEADERS),
40
+ contentType: (0, _superstruct.defaulted)((0, _superstruct.string)(), 'text/plain'),
41
+ body: (0, _superstruct.defaulted)((0, _superstruct.string)(), '')
42
+ }), {})
43
+ });
44
+ const MockOptionsUrlStruct = (0, _superstruct.object)({
45
+ url: (0, _superstruct.union)([
46
+ (0, _superstruct.string)(),
47
+ (0, _superstruct.regexp)()
48
+ ]),
49
+ partial: (0, _superstruct.optional)((0, _superstruct.boolean)())
50
+ });
51
+ const MockOptionsConditionStruct = (0, _superstruct.object)({
52
+ condition: (0, _superstruct.func)()
53
+ });
54
+ const MockOptionsStruct = (0, _superstruct.union)([
55
+ (0, _superstruct.assign)(MockOptionsBaseStruct, MockOptionsUrlStruct),
56
+ (0, _superstruct.assign)(MockOptionsBaseStruct, MockOptionsConditionStruct)
57
+ ]);
58
+ /**
59
+ * Check if the given URL matches the given request, or if the condition
60
+ * function returns `true`.
61
+ *
62
+ * @param request - The request to check.
63
+ * @param options - The options for the network mocking.
64
+ * @returns Whether the URL matches the request.
65
+ */ function matches(request, options) {
66
+ if ('url' in options) {
67
+ const { url, partial } = options;
68
+ if (typeof url === 'string') {
69
+ if (partial) {
70
+ return request.url().startsWith(url);
71
+ }
72
+ return url === request.url();
73
+ }
74
+ return url.test(request.url());
75
+ }
76
+ const { condition } = options;
77
+ return condition(request);
78
+ }
79
+ async function mock(page, options) {
80
+ await page.setRequestInterception(true);
81
+ const parsedOptions = (0, _superstruct.create)(options, MockOptionsStruct);
82
+ /**
83
+ * The mock handler.
84
+ *
85
+ * @param request - The request to handle.
86
+ */ function handler(request) {
87
+ // If the request is already handled, Puppeteer will throw an error if we
88
+ // try to continue the request.
89
+ if (request.isInterceptResolutionHandled()) {
90
+ return;
91
+ }
92
+ if (!matches(request, parsedOptions)) {
93
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
94
+ request.continue();
95
+ return;
96
+ }
97
+ log('Mocking request to %s', request.url());
98
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
99
+ request.respond(parsedOptions.response);
100
+ }
101
+ /**
102
+ * Unmock the page.
103
+ */ async function unmock() {
104
+ await page.setRequestInterception(false);
105
+ page.off('request', handler);
106
+ }
107
+ page.on('request', handler);
108
+ return {
109
+ unmock
110
+ };
111
+ }
112
+ const MockJsonRpcOptionsStruct = (0, _superstruct.object)({
113
+ method: (0, _superstruct.string)(),
114
+ result: _utils.UnsafeJsonStruct
115
+ });
116
+ async function mockJsonRpc(page, { method, result }) {
117
+ return await mock(page, {
118
+ condition: (request)=>{
119
+ if (request.url() !== _snapssimulator.JSON_RPC_ENDPOINT) {
120
+ return false;
121
+ }
122
+ const body = request.postData();
123
+ if (!body) {
124
+ return false;
125
+ }
126
+ try {
127
+ const json = JSON.parse(body);
128
+ return json.method === method;
129
+ } catch (error) {
130
+ log(`Unable to mock "${method}" request to Ethereum provider: %s`, error.message);
131
+ return false;
132
+ }
133
+ },
134
+ response: {
135
+ status: 200,
136
+ contentType: 'application/json',
137
+ body: JSON.stringify({
138
+ jsonrpc: '2.0',
139
+ id: 1,
140
+ result
141
+ })
142
+ }
143
+ });
144
+ }
145
+
146
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/internals/network.ts"],"sourcesContent":["import { JSON_RPC_ENDPOINT } from '@metamask/snaps-simulator';\nimport { createModuleLogger, UnsafeJsonStruct } from '@metamask/utils';\nimport { Page, HTTPRequest } from 'puppeteer';\nimport {\n assign,\n boolean,\n create,\n defaulted,\n Infer,\n number,\n object,\n optional,\n record,\n regexp,\n string,\n Struct,\n union,\n unknown,\n func,\n} from 'superstruct';\n\nimport { DeepPartial } from '../types';\nimport { rootLogger } from './logger';\n\n/**\n * The default headers to use for mocked responses. These headers are used to\n * enable CORS.\n */\nconst DEFAULT_HEADERS = {\n /* eslint-disable @typescript-eslint/naming-convention */\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Credentials': 'true',\n 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',\n 'Access-Control-Allow-Headers':\n 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers',\n /* eslint-enable @typescript-eslint/naming-convention */\n};\n\nconst log = createModuleLogger(rootLogger, 'network');\n\nexport type Unmock = () => Promise<void>;\n\nexport type Mock = {\n /**\n * A function that can be used to unmock the URL.\n */\n unmock: Unmock;\n};\n\n/**\n * A function that can return `true` if the given request should be mocked, or\n * false if not.\n *\n * @param request - The request to check.\n * @returns Whether to mock the request.\n */\nexport type ConditionFunction = (request: HTTPRequest) => boolean;\n\nconst MockOptionsBaseStruct = object({\n response: defaulted(\n object({\n status: defaulted(number(), 200),\n headers: defaulted(record(string(), unknown()), DEFAULT_HEADERS),\n contentType: defaulted(string(), 'text/plain'),\n body: defaulted(string(), ''),\n }),\n {},\n ),\n});\n\nconst MockOptionsUrlStruct = object({\n url: union([string(), regexp()]),\n partial: optional(boolean()),\n});\n\nconst MockOptionsConditionStruct = object({\n condition: func() as unknown as Struct<ConditionFunction, null>,\n});\n\nexport const MockOptionsStruct = union([\n assign(MockOptionsBaseStruct, MockOptionsUrlStruct),\n assign(MockOptionsBaseStruct, MockOptionsConditionStruct),\n]);\n\n/**\n * The options for the network mocking.\n *\n * @property url - The URL to mock. If a string is provided, the URL will be\n * matched exactly. If a RegExp is provided, the URL will be matched against it.\n * This option is incompatible with the `condition` option.\n * @property partial - If enabled, the request will be mocked if the URL starts\n * with the given URL. This option is ignored if a RegExp is provided to the\n * `url` option. This option is incompatible with the `condition` option.\n * @property condition - A function which gets the {@link HTTPRequest} as\n * parameter and returns a boolean to indicate whether the response should be\n * mocked or not. This option is incompatible with the `url` and `partial`\n * options.\n * @property response - The response to send for the request.\n * @property response.status - The status code to send for the response.\n * Defaults to `200`.\n * @property response.headers - The headers to send for the response. Defaults\n * to headers that enable CORS.\n * @property response.contentType - The content type to send for the response.\n * Defaults to `text/plain`.\n */\nexport type MockOptions = Infer<typeof MockOptionsStruct>;\n\n/**\n * Check if the given URL matches the given request, or if the condition\n * function returns `true`.\n *\n * @param request - The request to check.\n * @param options - The options for the network mocking.\n * @returns Whether the URL matches the request.\n */\nfunction matches(request: HTTPRequest, options: MockOptions) {\n if ('url' in options) {\n const { url, partial } = options;\n if (typeof url === 'string') {\n if (partial) {\n return request.url().startsWith(url);\n }\n\n return url === request.url();\n }\n\n return url.test(request.url());\n }\n\n const { condition } = options;\n return condition(request);\n}\n\n/**\n * Enable network mocking for the given page, and all its sub-frames.\n *\n * @param page - The page to enable network mocking on.\n * @param options - The options for the network mocking.\n * @returns A {@link Mock} object, with an `unmock` function.\n */\nexport async function mock(\n page: Page,\n options: DeepPartial<MockOptions>,\n): Promise<Mock> {\n await page.setRequestInterception(true);\n\n const parsedOptions = create(options, MockOptionsStruct);\n\n /**\n * The mock handler.\n *\n * @param request - The request to handle.\n */\n function handler(request: HTTPRequest) {\n // If the request is already handled, Puppeteer will throw an error if we\n // try to continue the request.\n if (request.isInterceptResolutionHandled()) {\n return;\n }\n\n if (!matches(request, parsedOptions)) {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n request.continue();\n return;\n }\n\n log('Mocking request to %s', request.url());\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n request.respond(parsedOptions.response);\n }\n\n /**\n * Unmock the page.\n */\n async function unmock() {\n await page.setRequestInterception(false);\n page.off('request', handler);\n }\n\n page.on('request', handler);\n\n return {\n unmock,\n };\n}\n\nconst MockJsonRpcOptionsStruct = object({\n method: string(),\n result: UnsafeJsonStruct,\n});\n\nexport type MockJsonRpcOptions = Infer<typeof MockJsonRpcOptionsStruct>;\n\n/**\n * Mock an Ethereum JSON-RPC request. This intercepts all requests to the\n * Ethereum provider, and returns the `result` instead.\n *\n * @param page - The page to enable network JSON-RPC mocking on.\n * @param options - The options for the JSON-RPC mock.\n * @param options.method - The JSON-RPC method to mock. Any other methods will be\n * forwarded to the provider.\n * @param options.result - The JSON response to return.\n * @returns A {@link Mock} object, with an `unmock` function.\n */\nexport async function mockJsonRpc(\n page: Page,\n { method, result }: MockJsonRpcOptions,\n) {\n return await mock(page, {\n condition: (request: HTTPRequest) => {\n if (request.url() !== JSON_RPC_ENDPOINT) {\n return false;\n }\n\n const body = request.postData();\n if (!body) {\n return false;\n }\n\n try {\n const json = JSON.parse(body);\n return json.method === method;\n } catch (error) {\n log(\n `Unable to mock \"${method}\" request to Ethereum provider: %s`,\n error.message,\n );\n return false;\n }\n },\n response: {\n status: 200,\n contentType: 'application/json',\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n result,\n }),\n },\n });\n}\n"],"names":["MockOptionsStruct","mock","mockJsonRpc","DEFAULT_HEADERS","log","createModuleLogger","rootLogger","MockOptionsBaseStruct","object","response","defaulted","status","number","headers","record","string","unknown","contentType","body","MockOptionsUrlStruct","url","union","regexp","partial","optional","boolean","MockOptionsConditionStruct","condition","func","assign","matches","request","options","startsWith","test","page","setRequestInterception","parsedOptions","create","handler","isInterceptResolutionHandled","continue","respond","unmock","off","on","MockJsonRpcOptionsStruct","method","result","UnsafeJsonStruct","JSON_RPC_ENDPOINT","postData","json","JSON","parse","error","message","stringify","jsonrpc","id"],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ request: function() {
13
+ return request;
14
+ },
15
+ sendTransaction: function() {
16
+ return sendTransaction;
17
+ },
18
+ runCronjob: function() {
19
+ return runCronjob;
20
+ }
21
+ });
22
+ const _snapsutils = require("@metamask/snaps-utils");
23
+ const _utils = require("@metamask/utils");
24
+ const _pptrtestinglibrary = require("pptr-testing-library");
25
+ const _superstruct = require("superstruct");
26
+ const _interface = require("./interface");
27
+ const _logger = require("./logger");
28
+ const _structs = require("./structs");
29
+ const _waitfor = require("./wait-for");
30
+ const log = (0, _utils.createModuleLogger)(_logger.rootLogger, 'request');
31
+ /**
32
+ * Send a request to the snap.
33
+ *
34
+ * @param page - The page to send the request from.
35
+ * @param args - The request arguments.
36
+ * @returns The request ID.
37
+ */ async function sendRequest(page, args) {
38
+ const document = await (0, _pptrtestinglibrary.getDocument)(page);
39
+ const button = await _pptrtestinglibrary.queries.getByTestId(document, `navigation-${args.handler}`);
40
+ // Navigate to the request handler page.
41
+ await button.click();
42
+ return await page.evaluate((payload)=>{
43
+ window.__SIMULATOR_API__.dispatch({
44
+ type: 'simulation/sendRequest',
45
+ payload
46
+ });
47
+ return window.__SIMULATOR_API__.getRequestId();
48
+ }, args);
49
+ }
50
+ function request(page, { origin = 'metamask.io', ...options }, handler = _snapsutils.HandlerType.OnRpcRequest) {
51
+ const doRequest = async ()=>{
52
+ const args = {
53
+ origin,
54
+ handler,
55
+ request: {
56
+ jsonrpc: '2.0',
57
+ id: 1,
58
+ ...options
59
+ }
60
+ };
61
+ log('Sending request %o', args);
62
+ const promise = (0, _waitfor.waitForResponse)(page, handler);
63
+ const id = await sendRequest(page, args);
64
+ const response = await promise;
65
+ log('Received response %o', response);
66
+ const notifications = await (0, _interface.getNotifications)(page, id);
67
+ return {
68
+ id,
69
+ response,
70
+ notifications
71
+ };
72
+ };
73
+ // This is a bit hacky, but it allows us to add the `getInterface` method
74
+ // to the response promise.
75
+ const response = doRequest();
76
+ response.getInterface = async (getInterfaceOptions)=>{
77
+ return await (0, _interface.getInterface)(page, getInterfaceOptions);
78
+ };
79
+ return response;
80
+ }
81
+ async function sendTransaction(page, options) {
82
+ const { origin: transactionOrigin, chainId, ...transaction } = (0, _superstruct.create)(options, _structs.TransactionOptionsStruct);
83
+ const args = {
84
+ origin: '',
85
+ handler: _snapsutils.HandlerType.OnTransaction,
86
+ request: {
87
+ jsonrpc: '2.0',
88
+ method: '',
89
+ params: {
90
+ chainId,
91
+ transaction,
92
+ transactionOrigin
93
+ }
94
+ }
95
+ };
96
+ log('Sending transaction %o', args);
97
+ const promise = (0, _waitfor.waitForResponse)(page, _snapsutils.HandlerType.OnTransaction);
98
+ const id = await sendRequest(page, args);
99
+ const response = await promise;
100
+ log('Received response %o', response);
101
+ if ((0, _utils.hasProperty)(response, 'error')) {
102
+ return {
103
+ id,
104
+ response,
105
+ notifications: []
106
+ };
107
+ }
108
+ (0, _utils.assert)((0, _utils.isPlainObject)(response.result));
109
+ (0, _utils.assert)((0, _utils.hasProperty)(response.result, 'content'));
110
+ return {
111
+ id,
112
+ response,
113
+ notifications: [],
114
+ content: response.result.content
115
+ };
116
+ }
117
+ function runCronjob(page, options) {
118
+ return request(page, options, _snapsutils.HandlerType.OnCronjob);
119
+ }
120
+
121
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/internals/request.ts"],"sourcesContent":["import { Component } from '@metamask/snaps-ui';\nimport { HandlerType, SnapRpcHookArgs } from '@metamask/snaps-utils';\nimport {\n assert,\n createModuleLogger,\n hasProperty,\n isPlainObject,\n} from '@metamask/utils';\nimport { getDocument, queries } from 'pptr-testing-library';\nimport { Page } from 'puppeteer';\nimport { create } from 'superstruct';\n\nimport {\n CronjobOptions,\n RequestOptions,\n SnapRequest,\n SnapResponse,\n TransactionOptions,\n} from '../types';\nimport { getInterface, getNotifications } from './interface';\nimport { rootLogger } from './logger';\nimport { TransactionOptionsStruct } from './structs';\nimport { waitForResponse } from './wait-for';\n\nconst log = createModuleLogger(rootLogger, 'request');\n\n/**\n * Send a request to the snap.\n *\n * @param page - The page to send the request from.\n * @param args - The request arguments.\n * @returns The request ID.\n */\nasync function sendRequest(page: Page, args: SnapRpcHookArgs) {\n const document = await getDocument(page);\n const button = await queries.getByTestId(\n document,\n `navigation-${args.handler}`,\n );\n\n // Navigate to the request handler page.\n await button.click();\n\n return await page.evaluate((payload) => {\n window.__SIMULATOR_API__.dispatch({\n type: 'simulation/sendRequest',\n payload,\n });\n\n return window.__SIMULATOR_API__.getRequestId();\n }, args);\n}\n\n/**\n * Send a request to the snap.\n *\n * @param page - The page to send the request from.\n * @param options - The request options.\n * @param options.origin - The origin of the request. Defaults to `metamask.io`.\n * @param handler - The handler to use. Defaults to `onRpcRequest`.\n * @returns The response.\n */\nexport function request(\n page: Page,\n { origin = 'metamask.io', ...options }: RequestOptions,\n handler:\n | HandlerType.OnRpcRequest\n | HandlerType.OnCronjob = HandlerType.OnRpcRequest,\n) {\n const doRequest = async (): Promise<SnapResponse> => {\n const args: SnapRpcHookArgs = {\n origin,\n handler,\n request: {\n jsonrpc: '2.0',\n id: 1,\n ...options,\n },\n };\n\n log('Sending request %o', args);\n\n const promise = waitForResponse(page, handler);\n const id = await sendRequest(page, args);\n const response = await promise;\n\n log('Received response %o', response);\n\n const notifications = await getNotifications(page, id);\n\n return { id, response, notifications };\n };\n\n // This is a bit hacky, but it allows us to add the `getInterface` method\n // to the response promise.\n const response = doRequest() as SnapRequest;\n\n response.getInterface = async (getInterfaceOptions) => {\n return await getInterface(page, getInterfaceOptions);\n };\n\n return response;\n}\n\n/**\n * Send a transaction to the snap.\n *\n * @param page - The page to send the transaction from.\n * @param options - The transaction options.\n * @returns The response.\n */\nexport async function sendTransaction(\n page: Page,\n options: Partial<TransactionOptions>,\n) {\n const {\n origin: transactionOrigin,\n chainId,\n ...transaction\n } = create(options, TransactionOptionsStruct);\n\n const args: SnapRpcHookArgs = {\n origin: '',\n handler: HandlerType.OnTransaction,\n request: {\n jsonrpc: '2.0',\n method: '',\n params: {\n chainId,\n transaction,\n transactionOrigin,\n },\n },\n };\n\n log('Sending transaction %o', args);\n\n const promise = waitForResponse(page, HandlerType.OnTransaction);\n const id = await sendRequest(page, args);\n const response = await promise;\n\n log('Received response %o', response);\n\n if (hasProperty(response, 'error')) {\n return { id, response, notifications: [] };\n }\n\n assert(isPlainObject(response.result));\n assert(hasProperty(response.result, 'content'));\n\n return {\n id,\n response,\n notifications: [],\n content: response.result.content as Component,\n };\n}\n\n/**\n * Run a cronjob.\n *\n * @param page - The page to run the cronjob from.\n * @param options - The request options.\n * @returns The response.\n */\nexport function runCronjob(page: Page, options: CronjobOptions) {\n return request(page, options, HandlerType.OnCronjob);\n}\n"],"names":["request","sendTransaction","runCronjob","log","createModuleLogger","rootLogger","sendRequest","page","args","document","getDocument","button","queries","getByTestId","handler","click","evaluate","payload","window","__SIMULATOR_API__","dispatch","type","getRequestId","origin","options","HandlerType","OnRpcRequest","doRequest","jsonrpc","id","promise","waitForResponse","response","notifications","getNotifications","getInterface","getInterfaceOptions","transactionOrigin","chainId","transaction","create","TransactionOptionsStruct","OnTransaction","method","params","hasProperty","assert","isPlainObject","result","content","OnCronjob"],"mappings":";;;;;;;;;;;IA8DgBA,OAAO;eAAPA;;IAiDMC,eAAe;eAAfA;;IAsDNC,UAAU;eAAVA;;;4BApK6B;uBAMtC;oCAC8B;6BAEd;2BASwB;wBACpB;yBACc;yBACT;AAEhC,MAAMC,MAAMC,IAAAA,yBAAkB,EAACC,kBAAU,EAAE;AAE3C;;;;;;CAMC,GACD,eAAeC,YAAYC,IAAU,EAAEC,IAAqB;IAC1D,MAAMC,WAAW,MAAMC,IAAAA,+BAAW,EAACH;IACnC,MAAMI,SAAS,MAAMC,2BAAO,CAACC,WAAW,CACtCJ,UACA,CAAC,WAAW,EAAED,KAAKM,OAAO,CAAC,CAAC;IAG9B,wCAAwC;IACxC,MAAMH,OAAOI,KAAK;IAElB,OAAO,MAAMR,KAAKS,QAAQ,CAAC,CAACC;QAC1BC,OAAOC,iBAAiB,CAACC,QAAQ,CAAC;YAChCC,MAAM;YACNJ;QACF;QAEA,OAAOC,OAAOC,iBAAiB,CAACG,YAAY;IAC9C,GAAGd;AACL;AAWO,SAASR,QACdO,IAAU,EACV,EAAEgB,SAAS,aAAa,EAAE,GAAGC,SAAyB,EACtDV,UAE4BW,uBAAW,CAACC,YAAY;IAEpD,MAAMC,YAAY;QAChB,MAAMnB,OAAwB;YAC5Be;YACAT;YACAd,SAAS;gBACP4B,SAAS;gBACTC,IAAI;gBACJ,GAAGL,OAAO;YACZ;QACF;QAEArB,IAAI,sBAAsBK;QAE1B,MAAMsB,UAAUC,IAAAA,wBAAe,EAACxB,MAAMO;QACtC,MAAMe,KAAK,MAAMvB,YAAYC,MAAMC;QACnC,MAAMwB,WAAW,MAAMF;QAEvB3B,IAAI,wBAAwB6B;QAE5B,MAAMC,gBAAgB,MAAMC,IAAAA,2BAAgB,EAAC3B,MAAMsB;QAEnD,OAAO;YAAEA;YAAIG;YAAUC;QAAc;IACvC;IAEA,yEAAyE;IACzE,2BAA2B;IAC3B,MAAMD,WAAWL;IAEjBK,SAASG,YAAY,GAAG,OAAOC;QAC7B,OAAO,MAAMD,IAAAA,uBAAY,EAAC5B,MAAM6B;IAClC;IAEA,OAAOJ;AACT;AASO,eAAe/B,gBACpBM,IAAU,EACViB,OAAoC;IAEpC,MAAM,EACJD,QAAQc,iBAAiB,EACzBC,OAAO,EACP,GAAGC,aACJ,GAAGC,IAAAA,mBAAM,EAAChB,SAASiB,iCAAwB;IAE5C,MAAMjC,OAAwB;QAC5Be,QAAQ;QACRT,SAASW,uBAAW,CAACiB,aAAa;QAClC1C,SAAS;YACP4B,SAAS;YACTe,QAAQ;YACRC,QAAQ;gBACNN;gBACAC;gBACAF;YACF;QACF;IACF;IAEAlC,IAAI,0BAA0BK;IAE9B,MAAMsB,UAAUC,IAAAA,wBAAe,EAACxB,MAAMkB,uBAAW,CAACiB,aAAa;IAC/D,MAAMb,KAAK,MAAMvB,YAAYC,MAAMC;IACnC,MAAMwB,WAAW,MAAMF;IAEvB3B,IAAI,wBAAwB6B;IAE5B,IAAIa,IAAAA,kBAAW,EAACb,UAAU,UAAU;QAClC,OAAO;YAAEH;YAAIG;YAAUC,eAAe,EAAE;QAAC;IAC3C;IAEAa,IAAAA,aAAM,EAACC,IAAAA,oBAAa,EAACf,SAASgB,MAAM;IACpCF,IAAAA,aAAM,EAACD,IAAAA,kBAAW,EAACb,SAASgB,MAAM,EAAE;IAEpC,OAAO;QACLnB;QACAG;QACAC,eAAe,EAAE;QACjBgB,SAASjB,SAASgB,MAAM,CAACC,OAAO;IAClC;AACF;AASO,SAAS/C,WAAWK,IAAU,EAAEiB,OAAuB;IAC5D,OAAOxB,QAAQO,MAAMiB,SAASC,uBAAW,CAACyB,SAAS;AACrD"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "startServer", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return startServer;
9
+ }
10
+ });
11
+ const _snapsutils = require("@metamask/snaps-utils");
12
+ const _utils = require("@metamask/utils");
13
+ const _express = /*#__PURE__*/ _interop_require_default(require("express"));
14
+ const _fs = require("fs");
15
+ const _http = require("http");
16
+ const _path = require("path");
17
+ const _logger = require("./logger");
18
+ function _interop_require_default(obj) {
19
+ return obj && obj.__esModule ? obj : {
20
+ default: obj
21
+ };
22
+ }
23
+ const SNAPS_EXECUTION_ENVIRONMENTS_PATH = (0, _path.resolve)((0, _path.dirname)(require.resolve('@metamask/snaps-execution-environments/package.json')), 'dist', 'browserify', 'iframe');
24
+ const SNAPS_SIMULATOR_PATH = (0, _path.resolve)((0, _path.dirname)(require.resolve('@metamask/snaps-simulator/package.json')), 'dist', 'webpack', 'test');
25
+ /**
26
+ * Check that:
27
+ *
28
+ * - The root directory exists.
29
+ * - The root directory contains a `snap.manifest.json` file.
30
+ * - The file path in the manifest exists.
31
+ *
32
+ * @param root - The root directory.
33
+ * @throws If any of the checks fail.
34
+ */ async function assertRoot(root) {
35
+ if (!root) {
36
+ throw new Error('You must specify a root directory.');
37
+ }
38
+ if (!await (0, _snapsutils.isDirectory)(root, false)) {
39
+ throw new Error(`Root directory "${root}" is not a directory.`);
40
+ }
41
+ const manifestPath = (0, _path.resolve)(root, 'snap.manifest.json');
42
+ const manifest = await _fs.promises.readFile(manifestPath, 'utf8').then(JSON.parse);
43
+ (0, _snapsutils.assertIsSnapManifest)(manifest);
44
+ const filePath = (0, _path.resolve)(root, manifest.source.location.npm.filePath);
45
+ if (!await (0, _snapsutils.isFile)(filePath)) {
46
+ throw new Error(`File "${filePath}" does not exist, or is not a file. Did you forget to build your snap?`);
47
+ }
48
+ }
49
+ async function startServer(options) {
50
+ await assertRoot(options.root);
51
+ const log = (0, _utils.createModuleLogger)(_logger.rootLogger, 'server');
52
+ const app = (0, _express.default)();
53
+ app.use((_request, response, next)=>{
54
+ response.header('Access-Control-Allow-Origin', '*');
55
+ response.header('Access-Control-Allow-Credentials', 'true');
56
+ response.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
57
+ response.header('Access-Control-Allow-Headers', 'Content-Type');
58
+ next();
59
+ });
60
+ app.use('/environment', _express.default.static(SNAPS_EXECUTION_ENVIRONMENTS_PATH));
61
+ app.use('/simulator', _express.default.static(SNAPS_SIMULATOR_PATH));
62
+ app.use(_express.default.static((0, _path.resolve)(process.cwd(), options.root)));
63
+ const server = (0, _http.createServer)(app);
64
+ return await new Promise((resolve, reject)=>{
65
+ server.listen(options.port, ()=>{
66
+ resolve(server);
67
+ });
68
+ server.on('error', (error)=>{
69
+ log(error);
70
+ reject(error);
71
+ });
72
+ });
73
+ }
74
+
75
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/internals/server.ts"],"sourcesContent":["import {\n assertIsSnapManifest,\n isDirectory,\n isFile,\n SnapManifest,\n} from '@metamask/snaps-utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport express from 'express';\nimport { promises as fs } from 'fs';\nimport { createServer, Server } from 'http';\nimport { resolve as pathResolve, dirname } from 'path';\n\nimport { SnapsEnvironmentOptions } from '../options';\nimport { rootLogger } from './logger';\n\nconst SNAPS_EXECUTION_ENVIRONMENTS_PATH = pathResolve(\n dirname(\n require.resolve('@metamask/snaps-execution-environments/package.json'),\n ),\n 'dist',\n 'browserify',\n 'iframe',\n);\n\nconst SNAPS_SIMULATOR_PATH = pathResolve(\n dirname(require.resolve('@metamask/snaps-simulator/package.json')),\n 'dist',\n 'webpack',\n 'test',\n);\n\nexport type ServerOptions = Required<\n // We need a double `Required` for the type to be inferred correctly.\n Required<SnapsEnvironmentOptions>['server']\n>;\n\n/**\n * Check that:\n *\n * - The root directory exists.\n * - The root directory contains a `snap.manifest.json` file.\n * - The file path in the manifest exists.\n *\n * @param root - The root directory.\n * @throws If any of the checks fail.\n */\nasync function assertRoot(root: string) {\n if (!root) {\n throw new Error('You must specify a root directory.');\n }\n\n if (!(await isDirectory(root, false))) {\n throw new Error(`Root directory \"${root}\" is not a directory.`);\n }\n\n const manifestPath = pathResolve(root, 'snap.manifest.json');\n const manifest: SnapManifest = await fs\n .readFile(manifestPath, 'utf8')\n .then(JSON.parse);\n\n assertIsSnapManifest(manifest);\n const filePath = pathResolve(root, manifest.source.location.npm.filePath);\n\n if (!(await isFile(filePath))) {\n throw new Error(\n `File \"${filePath}\" does not exist, or is not a file. Did you forget to build your snap?`,\n );\n }\n}\n\n/**\n * Start an HTTP server on `localhost` with a random port. This is used to serve\n * the static files for the environment.\n *\n * @param options - The options to use.\n * @param options.port - The port to use for the server.\n * @param options.root - The root directory to serve from the server.\n * @returns The HTTP server.\n */\nexport async function startServer(options: ServerOptions) {\n await assertRoot(options.root);\n\n const log = createModuleLogger(rootLogger, 'server');\n const app = express();\n\n app.use((_request, response, next) => {\n response.header('Access-Control-Allow-Origin', '*');\n response.header('Access-Control-Allow-Credentials', 'true');\n response.header('Access-Control-Allow-Methods', 'GET, OPTIONS');\n response.header('Access-Control-Allow-Headers', 'Content-Type');\n\n next();\n });\n\n app.use('/environment', express.static(SNAPS_EXECUTION_ENVIRONMENTS_PATH));\n app.use('/simulator', express.static(SNAPS_SIMULATOR_PATH));\n app.use(express.static(pathResolve(process.cwd(), options.root)));\n\n const server = createServer(app);\n return await new Promise<Server>((resolve, reject) => {\n server.listen(options.port, () => {\n resolve(server);\n });\n\n server.on('error', (error) => {\n log(error);\n reject(error);\n });\n });\n}\n"],"names":["startServer","SNAPS_EXECUTION_ENVIRONMENTS_PATH","pathResolve","dirname","require","resolve","SNAPS_SIMULATOR_PATH","assertRoot","root","Error","isDirectory","manifestPath","manifest","fs","readFile","then","JSON","parse","assertIsSnapManifest","filePath","source","location","npm","isFile","options","log","createModuleLogger","rootLogger","app","express","use","_request","response","next","header","static","process","cwd","server","createServer","Promise","reject","listen","port","on","error"],"mappings":";;;;+BA+EsBA;;;eAAAA;;;4BA1Ef;uBAC4B;gEACf;oBACW;sBACM;sBACW;wBAGrB;;;;;;AAE3B,MAAMC,oCAAoCC,IAAAA,aAAW,EACnDC,IAAAA,aAAO,EACLC,QAAQC,OAAO,CAAC,yDAElB,QACA,cACA;AAGF,MAAMC,uBAAuBJ,IAAAA,aAAW,EACtCC,IAAAA,aAAO,EAACC,QAAQC,OAAO,CAAC,4CACxB,QACA,WACA;AAQF;;;;;;;;;CASC,GACD,eAAeE,WAAWC,IAAY;IACpC,IAAI,CAACA,MAAM;QACT,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAI,CAAE,MAAMC,IAAAA,uBAAW,EAACF,MAAM,QAAS;QACrC,MAAM,IAAIC,MAAM,CAAC,gBAAgB,EAAED,KAAK,qBAAqB,CAAC;IAChE;IAEA,MAAMG,eAAeT,IAAAA,aAAW,EAACM,MAAM;IACvC,MAAMI,WAAyB,MAAMC,YAAE,CACpCC,QAAQ,CAACH,cAAc,QACvBI,IAAI,CAACC,KAAKC,KAAK;IAElBC,IAAAA,gCAAoB,EAACN;IACrB,MAAMO,WAAWjB,IAAAA,aAAW,EAACM,MAAMI,SAASQ,MAAM,CAACC,QAAQ,CAACC,GAAG,CAACH,QAAQ;IAExE,IAAI,CAAE,MAAMI,IAAAA,kBAAM,EAACJ,WAAY;QAC7B,MAAM,IAAIV,MACR,CAAC,MAAM,EAAEU,SAAS,sEAAsE,CAAC;IAE7F;AACF;AAWO,eAAenB,YAAYwB,OAAsB;IACtD,MAAMjB,WAAWiB,QAAQhB,IAAI;IAE7B,MAAMiB,MAAMC,IAAAA,yBAAkB,EAACC,kBAAU,EAAE;IAC3C,MAAMC,MAAMC,IAAAA,gBAAO;IAEnBD,IAAIE,GAAG,CAAC,CAACC,UAAUC,UAAUC;QAC3BD,SAASE,MAAM,CAAC,+BAA+B;QAC/CF,SAASE,MAAM,CAAC,oCAAoC;QACpDF,SAASE,MAAM,CAAC,gCAAgC;QAChDF,SAASE,MAAM,CAAC,gCAAgC;QAEhDD;IACF;IAEAL,IAAIE,GAAG,CAAC,gBAAgBD,gBAAO,CAACM,MAAM,CAAClC;IACvC2B,IAAIE,GAAG,CAAC,cAAcD,gBAAO,CAACM,MAAM,CAAC7B;IACrCsB,IAAIE,GAAG,CAACD,gBAAO,CAACM,MAAM,CAACjC,IAAAA,aAAW,EAACkC,QAAQC,GAAG,IAAIb,QAAQhB,IAAI;IAE9D,MAAM8B,SAASC,IAAAA,kBAAY,EAACX;IAC5B,OAAO,MAAM,IAAIY,QAAgB,CAACnC,SAASoC;QACzCH,OAAOI,MAAM,CAAClB,QAAQmB,IAAI,EAAE;YAC1BtC,QAAQiC;QACV;QAEAA,OAAOM,EAAE,CAAC,SAAS,CAACC;YAClBpB,IAAIoB;YACJJ,OAAOI;QACT;IACF;AACF"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ TransactionOptionsStruct: function() {
13
+ return TransactionOptionsStruct;
14
+ },
15
+ SnapOptionsStruct: function() {
16
+ return SnapOptionsStruct;
17
+ },
18
+ InterfaceStruct: function() {
19
+ return InterfaceStruct;
20
+ },
21
+ SnapResponseStruct: function() {
22
+ return SnapResponseStruct;
23
+ }
24
+ });
25
+ const _rpcmethods = require("@metamask/rpc-methods");
26
+ const _snapsui = require("@metamask/snaps-ui");
27
+ const _snapsutils = require("@metamask/snaps-utils");
28
+ const _utils = require("@metamask/utils");
29
+ const _crypto = require("crypto");
30
+ const _superstruct = require("superstruct");
31
+ // TODO: Export this from `@metamask/utils` instead.
32
+ const BytesLikeStruct = (0, _superstruct.union)([
33
+ (0, _superstruct.bigint)(),
34
+ (0, _superstruct.number)(),
35
+ (0, _superstruct.string)(),
36
+ (0, _superstruct.instance)(Uint8Array)
37
+ ]);
38
+ const TransactionOptionsStruct = (0, _superstruct.object)({
39
+ /**
40
+ * The CAIP-2 chain ID to send the transaction on. Defaults to `eip155:1`.
41
+ */ chainId: (0, _superstruct.defaulted)((0, _superstruct.string)(), 'eip155:1'),
42
+ /**
43
+ * The origin to send the transaction from. Defaults to `metamask.io`.
44
+ */ origin: (0, _superstruct.defaulted)((0, _superstruct.string)(), 'metamask.io'),
45
+ /**
46
+ * The address to send the transaction from. Defaults to a randomly generated
47
+ * address.
48
+ */ // TODO: Move this coercer to `@metamask/utils`.
49
+ from: (0, _superstruct.coerce)(_utils.StrictHexStruct, (0, _superstruct.optional)(BytesLikeStruct), (value)=>{
50
+ if (value) {
51
+ return (0, _utils.valueToBytes)(value);
52
+ }
53
+ return (0, _utils.bytesToHex)((0, _crypto.randomBytes)(20));
54
+ }),
55
+ /**
56
+ * The address to send the transaction to. Defaults to a randomly generated
57
+ * address.
58
+ */ // TODO: Move this coercer to `@metamask/utils`.
59
+ to: (0, _superstruct.coerce)(_utils.StrictHexStruct, (0, _superstruct.optional)(BytesLikeStruct), (value)=>{
60
+ if (value) {
61
+ return (0, _utils.valueToBytes)(value);
62
+ }
63
+ return (0, _utils.bytesToHex)((0, _crypto.randomBytes)(20));
64
+ }),
65
+ /**
66
+ * The value to send with the transaction. The value may be specified as a
67
+ * `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `0`.
68
+ */ value: (0, _superstruct.defaulted)((0, _superstruct.coerce)(_utils.StrictHexStruct, BytesLikeStruct, (value)=>(0, _utils.bytesToHex)((0, _utils.valueToBytes)(value))), '0x0'),
69
+ /**
70
+ * The gas limit to use for the transaction. The gas limit may be specified
71
+ * as a `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `21_000`.
72
+ */ gasLimit: (0, _superstruct.defaulted)((0, _superstruct.coerce)(_utils.StrictHexStruct, BytesLikeStruct, (value)=>(0, _utils.bytesToHex)((0, _utils.valueToBytes)(value))), (0, _utils.valueToBytes)(21000)),
73
+ /**
74
+ * The max fee per gas (in Wei) to use for the transaction. The max fee per
75
+ * gas may be specified as a `number`, `bigint`, `string`, or `Uint8Array`.
76
+ * Defaults to `1`.
77
+ */ maxFeePerGas: (0, _superstruct.defaulted)((0, _superstruct.coerce)(_utils.StrictHexStruct, BytesLikeStruct, (value)=>(0, _utils.bytesToHex)((0, _utils.valueToBytes)(value))), (0, _utils.valueToBytes)(1)),
78
+ /**
79
+ * The max priority fee per gas (in Wei) to use for the transaction. The max
80
+ * priority fee per gas may be specified as a `number`, `bigint`, `string`,
81
+ * or `Uint8Array`. Defaults to `1`.
82
+ */ maxPriorityFeePerGas: (0, _superstruct.defaulted)((0, _superstruct.coerce)(_utils.StrictHexStruct, BytesLikeStruct, (value)=>(0, _utils.bytesToHex)((0, _utils.valueToBytes)(value))), (0, _utils.valueToBytes)(1)),
83
+ /**
84
+ * The nonce to use for the transaction. The nonce may be specified as a
85
+ * `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `0`.
86
+ */ nonce: (0, _superstruct.defaulted)((0, _superstruct.coerce)(_utils.StrictHexStruct, BytesLikeStruct, (value)=>(0, _utils.bytesToHex)((0, _utils.valueToBytes)(value))), (0, _utils.valueToBytes)(0)),
87
+ /**
88
+ * The data to send with the transaction. The data may be specified as a
89
+ * `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `0x`.
90
+ */ data: (0, _superstruct.defaulted)((0, _superstruct.coerce)((0, _superstruct.union)([
91
+ _utils.StrictHexStruct,
92
+ (0, _superstruct.literal)('0x')
93
+ ]), BytesLikeStruct, (value)=>(0, _utils.bytesToHex)((0, _utils.valueToBytes)(value))), '0x')
94
+ });
95
+ const SnapOptionsStruct = (0, _superstruct.object)({
96
+ /**
97
+ * The timeout in milliseconds to use for requests to the snap. Defaults to
98
+ * `1000`.
99
+ */ timeout: (0, _superstruct.defaulted)((0, _superstruct.optional)((0, _superstruct.number)()), 1000)
100
+ });
101
+ const InterfaceStruct = (0, _superstruct.type)({
102
+ content: (0, _superstruct.optional)(_snapsui.ComponentStruct)
103
+ });
104
+ const SnapResponseStruct = (0, _superstruct.assign)(InterfaceStruct, (0, _superstruct.object)({
105
+ id: (0, _superstruct.string)(),
106
+ response: (0, _superstruct.union)([
107
+ (0, _superstruct.object)({
108
+ result: _utils.JsonStruct
109
+ }),
110
+ (0, _superstruct.object)({
111
+ error: _utils.JsonStruct
112
+ })
113
+ ]),
114
+ notifications: (0, _superstruct.array)((0, _superstruct.object)({
115
+ id: (0, _superstruct.string)(),
116
+ message: (0, _superstruct.string)(),
117
+ type: (0, _superstruct.union)([
118
+ (0, _snapsutils.enumValue)(_rpcmethods.NotificationType.InApp),
119
+ (0, _snapsutils.enumValue)(_rpcmethods.NotificationType.Native)
120
+ ])
121
+ }))
122
+ }));
123
+
124
+ //# sourceMappingURL=structs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/internals/structs.ts"],"sourcesContent":["import { NotificationType } from '@metamask/rpc-methods';\nimport { ComponentStruct } from '@metamask/snaps-ui';\nimport { enumValue } from '@metamask/snaps-utils';\nimport {\n bytesToHex,\n JsonStruct,\n StrictHexStruct,\n valueToBytes,\n} from '@metamask/utils';\nimport { randomBytes } from 'crypto';\nimport {\n array,\n assign,\n bigint,\n coerce,\n defaulted,\n instance,\n literal,\n number,\n object,\n optional,\n string,\n type,\n union,\n} from 'superstruct';\n\n// TODO: Export this from `@metamask/utils` instead.\nconst BytesLikeStruct = union([\n bigint(),\n number(),\n string(),\n instance(Uint8Array),\n]);\n\nexport const TransactionOptionsStruct = object({\n /**\n * The CAIP-2 chain ID to send the transaction on. Defaults to `eip155:1`.\n */\n chainId: defaulted(string(), 'eip155:1'),\n\n /**\n * The origin to send the transaction from. Defaults to `metamask.io`.\n */\n origin: defaulted(string(), 'metamask.io'),\n\n /**\n * The address to send the transaction from. Defaults to a randomly generated\n * address.\n */\n // TODO: Move this coercer to `@metamask/utils`.\n from: coerce(StrictHexStruct, optional(BytesLikeStruct), (value) => {\n if (value) {\n return valueToBytes(value);\n }\n\n return bytesToHex(randomBytes(20));\n }),\n\n /**\n * The address to send the transaction to. Defaults to a randomly generated\n * address.\n */\n // TODO: Move this coercer to `@metamask/utils`.\n to: coerce(StrictHexStruct, optional(BytesLikeStruct), (value) => {\n if (value) {\n return valueToBytes(value);\n }\n\n return bytesToHex(randomBytes(20));\n }),\n\n /**\n * The value to send with the transaction. The value may be specified as a\n * `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `0`.\n */\n value: defaulted(\n coerce(StrictHexStruct, BytesLikeStruct, (value) =>\n bytesToHex(valueToBytes(value)),\n ),\n '0x0',\n ),\n\n /**\n * The gas limit to use for the transaction. The gas limit may be specified\n * as a `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `21_000`.\n */\n gasLimit: defaulted(\n coerce(StrictHexStruct, BytesLikeStruct, (value) =>\n bytesToHex(valueToBytes(value)),\n ),\n valueToBytes(21_000),\n ),\n\n /**\n * The max fee per gas (in Wei) to use for the transaction. The max fee per\n * gas may be specified as a `number`, `bigint`, `string`, or `Uint8Array`.\n * Defaults to `1`.\n */\n maxFeePerGas: defaulted(\n coerce(StrictHexStruct, BytesLikeStruct, (value) =>\n bytesToHex(valueToBytes(value)),\n ),\n valueToBytes(1),\n ),\n\n /**\n * The max priority fee per gas (in Wei) to use for the transaction. The max\n * priority fee per gas may be specified as a `number`, `bigint`, `string`,\n * or `Uint8Array`. Defaults to `1`.\n */\n maxPriorityFeePerGas: defaulted(\n coerce(StrictHexStruct, BytesLikeStruct, (value) =>\n bytesToHex(valueToBytes(value)),\n ),\n valueToBytes(1),\n ),\n\n /**\n * The nonce to use for the transaction. The nonce may be specified as a\n * `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `0`.\n */\n nonce: defaulted(\n coerce(StrictHexStruct, BytesLikeStruct, (value) =>\n bytesToHex(valueToBytes(value)),\n ),\n valueToBytes(0),\n ),\n\n /**\n * The data to send with the transaction. The data may be specified as a\n * `number`, `bigint`, `string`, or `Uint8Array`. Defaults to `0x`.\n */\n data: defaulted(\n coerce(union([StrictHexStruct, literal('0x')]), BytesLikeStruct, (value) =>\n bytesToHex(valueToBytes(value)),\n ),\n '0x',\n ),\n});\n\nexport const SnapOptionsStruct = object({\n /**\n * The timeout in milliseconds to use for requests to the snap. Defaults to\n * `1000`.\n */\n timeout: defaulted(optional(number()), 1000),\n});\n\nexport const InterfaceStruct = type({\n content: optional(ComponentStruct),\n});\n\nexport const SnapResponseStruct = assign(\n InterfaceStruct,\n object({\n id: string(),\n\n response: union([\n object({\n result: JsonStruct,\n }),\n object({\n error: JsonStruct,\n }),\n ]),\n\n notifications: array(\n object({\n id: string(),\n message: string(),\n type: union([\n enumValue(NotificationType.InApp),\n enumValue(NotificationType.Native),\n ]),\n }),\n ),\n }),\n);\n"],"names":["TransactionOptionsStruct","SnapOptionsStruct","InterfaceStruct","SnapResponseStruct","BytesLikeStruct","union","bigint","number","string","instance","Uint8Array","object","chainId","defaulted","origin","from","coerce","StrictHexStruct","optional","value","valueToBytes","bytesToHex","randomBytes","to","gasLimit","maxFeePerGas","maxPriorityFeePerGas","nonce","data","literal","timeout","type","content","ComponentStruct","assign","id","response","result","JsonStruct","error","notifications","array","message","enumValue","NotificationType","InApp","Native"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/internals/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ waitFor: function() {
13
+ return waitFor;
14
+ },
15
+ waitForResponse: function() {
16
+ return waitForResponse;
17
+ }
18
+ });
19
+ const _utils = require("@metamask/utils");
20
+ const _pptrtestinglibrary = require("pptr-testing-library");
21
+ const _logger = require("./logger");
22
+ const log = (0, _utils.createModuleLogger)(_logger.rootLogger, 'wait-for');
23
+ async function waitFor(fn, { timeout = 3000, message } = {}) {
24
+ try {
25
+ let result;
26
+ await (0, _pptrtestinglibrary.waitFor)(// eslint-disable-next-line @typescript-eslint/no-misused-promises
27
+ async ()=>{
28
+ // Puppeteer's `waitFor` function does not support returning a value
29
+ // from the condition function, so we need to use a variable outside
30
+ // the scope of the function.
31
+ result = await fn();
32
+ }, {
33
+ timeout
34
+ });
35
+ (0, _utils.assert)(result !== undefined);
36
+ return result;
37
+ } catch (error) {
38
+ if (message) {
39
+ throw new Error(message);
40
+ }
41
+ throw error;
42
+ }
43
+ }
44
+ async function waitForResponse(page, type) {
45
+ log('Waiting for response of type %s.', type);
46
+ return await page.evaluate(async (_type)=>{
47
+ return new Promise((resolve)=>{
48
+ window.__SIMULATOR_API__.dispatch({
49
+ type: `${_type}/clearResponse`
50
+ });
51
+ const unsubscribe = window.__SIMULATOR_API__.subscribe(()=>{
52
+ const state = window.__SIMULATOR_API__.getState();
53
+ const { pending, response } = state[_type];
54
+ if (!pending && response) {
55
+ unsubscribe();
56
+ resolve(response);
57
+ }
58
+ });
59
+ });
60
+ }, type);
61
+ }
62
+
63
+ //# sourceMappingURL=wait-for.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/internals/wait-for.ts"],"sourcesContent":["import { HandlerType } from '@metamask/snaps-utils';\nimport { assert, createModuleLogger } from '@metamask/utils';\nimport { waitFor as waitForPuppeteer } from 'pptr-testing-library';\nimport { Page } from 'puppeteer';\n\nimport { SnapResponse } from '../types';\nimport { rootLogger } from './logger';\n\nexport type WaitForOptions = {\n /**\n * The timeout in milliseconds.\n */\n timeout?: number;\n\n /**\n * The error message to throw if the condition is not met.\n */\n message?: string;\n};\n\nconst log = createModuleLogger(rootLogger, 'wait-for');\n\n/**\n * Wait for a condition to be true. This is a wrapper around\n * `pptr-testing-library`'s `waitFor` function, with the addition of a custom\n * error message.\n *\n * @param fn - The condition to wait for.\n * @param options - The options.\n * @param options.timeout - The timeout in milliseconds.\n * @param options.message - The error message to throw if the condition is not\n * met.\n * @returns A promise that resolves when the condition is met. The promise\n * resolves to the return value of the condition function.\n */\nexport async function waitFor<Result>(\n fn: () => Promise<Result>,\n { timeout = 3000, message }: WaitForOptions = {},\n) {\n try {\n let result: Result | undefined;\n\n await waitForPuppeteer(\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async () => {\n // Puppeteer's `waitFor` function does not support returning a value\n // from the condition function, so we need to use a variable outside\n // the scope of the function.\n result = await fn();\n },\n {\n timeout,\n },\n );\n\n assert(result !== undefined);\n return result;\n } catch (error) {\n if (message) {\n throw new Error(message);\n }\n\n throw error;\n }\n}\n\n/**\n * Wait for a JSON-RPC response.\n *\n * @param page - The page to wait for the response on.\n * @param type - The type of response to wait for.\n * @returns The JSON-RPC response.\n */\nexport async function waitForResponse(\n page: Page,\n type:\n | HandlerType.OnTransaction\n | HandlerType.OnRpcRequest\n | HandlerType.OnCronjob,\n) {\n log('Waiting for response of type %s.', type);\n\n return await page.evaluate(async (_type) => {\n return new Promise<SnapResponse['response']>((resolve) => {\n window.__SIMULATOR_API__.dispatch({\n type: `${_type}/clearResponse`,\n });\n\n const unsubscribe = window.__SIMULATOR_API__.subscribe(() => {\n const state = window.__SIMULATOR_API__.getState();\n const { pending, response } = state[_type];\n\n if (!pending && response) {\n unsubscribe();\n\n resolve(response);\n }\n });\n });\n }, type);\n}\n"],"names":["waitFor","waitForResponse","log","createModuleLogger","rootLogger","fn","timeout","message","result","waitForPuppeteer","assert","undefined","error","Error","page","type","evaluate","_type","Promise","resolve","window","__SIMULATOR_API__","dispatch","unsubscribe","subscribe","state","getState","pending","response"],"mappings":";;;;;;;;;;;IAmCsBA,OAAO;eAAPA;;IAsCAC,eAAe;eAAfA;;;uBAxEqB;oCACC;wBAIjB;AAc3B,MAAMC,MAAMC,IAAAA,yBAAkB,EAACC,kBAAU,EAAE;AAepC,eAAeJ,QACpBK,EAAyB,EACzB,EAAEC,UAAU,IAAI,EAAEC,OAAO,EAAkB,GAAG,CAAC,CAAC;IAEhD,IAAI;QACF,IAAIC;QAEJ,MAAMC,IAAAA,2BAAgB,EACpB,kEAAkE;QAClE;YACE,oEAAoE;YACpE,oEAAoE;YACpE,6BAA6B;YAC7BD,SAAS,MAAMH;QACjB,GACA;YACEC;QACF;QAGFI,IAAAA,aAAM,EAACF,WAAWG;QAClB,OAAOH;IACT,EAAE,OAAOI,OAAO;QACd,IAAIL,SAAS;YACX,MAAM,IAAIM,MAAMN;QAClB;QAEA,MAAMK;IACR;AACF;AASO,eAAeX,gBACpBa,IAAU,EACVC,IAGyB;IAEzBb,IAAI,oCAAoCa;IAExC,OAAO,MAAMD,KAAKE,QAAQ,CAAC,OAAOC;QAChC,OAAO,IAAIC,QAAkC,CAACC;YAC5CC,OAAOC,iBAAiB,CAACC,QAAQ,CAAC;gBAChCP,MAAM,CAAC,EAAEE,MAAM,cAAc,CAAC;YAChC;YAEA,MAAMM,cAAcH,OAAOC,iBAAiB,CAACG,SAAS,CAAC;gBACrD,MAAMC,QAAQL,OAAOC,iBAAiB,CAACK,QAAQ;gBAC/C,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAGH,KAAK,CAACR,MAAM;gBAE1C,IAAI,CAACU,WAAWC,UAAU;oBACxBL;oBAEAJ,QAAQS;gBACV;YACF;QACF;IACF,GAAGb;AACL"}