@metamask/snaps-controllers 13.0.0 → 13.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 (50) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/dist/index.cjs +1 -0
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +1 -0
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.mts +1 -0
  7. package/dist/index.d.mts.map +1 -1
  8. package/dist/index.mjs +1 -0
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/snaps/SnapController.cjs +19 -0
  11. package/dist/snaps/SnapController.cjs.map +1 -1
  12. package/dist/snaps/SnapController.d.cts +16 -1
  13. package/dist/snaps/SnapController.d.cts.map +1 -1
  14. package/dist/snaps/SnapController.d.mts +16 -1
  15. package/dist/snaps/SnapController.d.mts.map +1 -1
  16. package/dist/snaps/SnapController.mjs +19 -0
  17. package/dist/snaps/SnapController.mjs.map +1 -1
  18. package/dist/snaps/constants.cjs +1 -0
  19. package/dist/snaps/constants.cjs.map +1 -1
  20. package/dist/snaps/constants.d.cts.map +1 -1
  21. package/dist/snaps/constants.d.mts.map +1 -1
  22. package/dist/snaps/constants.mjs +1 -0
  23. package/dist/snaps/constants.mjs.map +1 -1
  24. package/dist/snaps/index.cjs +1 -0
  25. package/dist/snaps/index.cjs.map +1 -1
  26. package/dist/snaps/index.d.cts +1 -0
  27. package/dist/snaps/index.d.cts.map +1 -1
  28. package/dist/snaps/index.d.mts +1 -0
  29. package/dist/snaps/index.d.mts.map +1 -1
  30. package/dist/snaps/index.mjs +1 -0
  31. package/dist/snaps/index.mjs.map +1 -1
  32. package/dist/utils.d.cts +1 -1
  33. package/dist/utils.d.mts +1 -1
  34. package/dist/websocket/WebSocketService.cjs +194 -0
  35. package/dist/websocket/WebSocketService.cjs.map +1 -0
  36. package/dist/websocket/WebSocketService.d.cts +33 -0
  37. package/dist/websocket/WebSocketService.d.cts.map +1 -0
  38. package/dist/websocket/WebSocketService.d.mts +33 -0
  39. package/dist/websocket/WebSocketService.d.mts.map +1 -0
  40. package/dist/websocket/WebSocketService.mjs +190 -0
  41. package/dist/websocket/WebSocketService.mjs.map +1 -0
  42. package/dist/websocket/index.cjs +18 -0
  43. package/dist/websocket/index.cjs.map +1 -0
  44. package/dist/websocket/index.d.cts +2 -0
  45. package/dist/websocket/index.d.cts.map +1 -0
  46. package/dist/websocket/index.d.mts +2 -0
  47. package/dist/websocket/index.d.mts.map +1 -0
  48. package/dist/websocket/index.mjs +2 -0
  49. package/dist/websocket/index.mjs.map +1 -0
  50. package/package.json +6 -6
@@ -41,5 +41,6 @@ exports.CLIENT_ONLY_HANDLERS = Object.freeze([
41
41
  snaps_utils_1.HandlerType.OnAssetsLookup,
42
42
  snaps_utils_1.HandlerType.OnAssetsConversion,
43
43
  snaps_utils_1.HandlerType.OnAssetHistoricalPrice,
44
+ snaps_utils_1.HandlerType.OnWebSocketEvent,
44
45
  ]);
45
46
  //# sourceMappingURL=constants.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":";;;AAAA,mEAA6D;AAC7D,uDAAoD;AAEpD,gEAAgE;AACnD,QAAA,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/C,aAAa;IACb,kBAAkB;IAClB,aAAa;IACb,gBAAgB;IAChB,kCAAc,CAAC,OAAO;IACtB,kCAAc,CAAC,QAAQ;IACvB,kCAAc,CAAC,cAAc;IAC7B,kCAAc,CAAC,gBAAgB;IAC/B,kCAAc,CAAC,kBAAkB;IACjC,kCAAc,CAAC,gBAAgB;CAChC,CAAC,CAAC;AAEU,QAAA,wCAAwC,GAAG;IACtD,SAAS,EAAE,QAAiB;IAC5B,MAAM,EAAE;QACN,UAAU,EAAE,KAAM;KACnB;CACF,CAAC;AAEF;;GAEG;AACU,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAE1C,+DAA+D;AAClD,QAAA,eAAe,GAAG,UAAU,CAAC;AAE1C,+DAA+D;AAClD,QAAA,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,yBAAW,CAAC,eAAe;IAC3B,yBAAW,CAAC,WAAW;IACvB,yBAAW,CAAC,aAAa;IACzB,yBAAW,CAAC,SAAS;IACrB,yBAAW,CAAC,YAAY;IACxB,yBAAW,CAAC,UAAU;IACtB,yBAAW,CAAC,cAAc;IAC1B,yBAAW,CAAC,WAAW;IACvB,yBAAW,CAAC,cAAc;IAC1B,yBAAW,CAAC,kBAAkB;IAC9B,yBAAW,CAAC,sBAAsB;CACnC,CAAC,CAAC","sourcesContent":["import { SnapEndowments } from '@metamask/snaps-rpc-methods';\nimport { HandlerType } from '@metamask/snaps-utils';\n\n// These permissions are allowed without being on the allowlist.\nexport const ALLOWED_PERMISSIONS = Object.freeze([\n 'snap_dialog',\n 'snap_manageState',\n 'snap_notify',\n 'snap_getLocale',\n SnapEndowments.Cronjob,\n SnapEndowments.HomePage,\n SnapEndowments.LifecycleHooks,\n SnapEndowments.EthereumProvider,\n SnapEndowments.TransactionInsight,\n SnapEndowments.SignatureInsight,\n]);\n\nexport const LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS = {\n algorithm: 'PBKDF2' as const,\n params: {\n iterations: 10_000,\n },\n};\n\n/**\n * The timeout for debouncing state updates.\n */\nexport const STATE_DEBOUNCE_TIMEOUT = 500;\n\n// The origin used to indicate requests coming from the client.\nexport const METAMASK_ORIGIN = 'metamask';\n\n// These handlers are only allowed to be invoked by the client.\nexport const CLIENT_ONLY_HANDLERS = Object.freeze([\n HandlerType.OnClientRequest,\n HandlerType.OnSignature,\n HandlerType.OnTransaction,\n HandlerType.OnCronjob,\n HandlerType.OnNameLookup,\n HandlerType.OnHomePage,\n HandlerType.OnSettingsPage,\n HandlerType.OnUserInput,\n HandlerType.OnAssetsLookup,\n HandlerType.OnAssetsConversion,\n HandlerType.OnAssetHistoricalPrice,\n]);\n"]}
1
+ {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":";;;AAAA,mEAA6D;AAC7D,uDAAoD;AAEpD,gEAAgE;AACnD,QAAA,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/C,aAAa;IACb,kBAAkB;IAClB,aAAa;IACb,gBAAgB;IAChB,kCAAc,CAAC,OAAO;IACtB,kCAAc,CAAC,QAAQ;IACvB,kCAAc,CAAC,cAAc;IAC7B,kCAAc,CAAC,gBAAgB;IAC/B,kCAAc,CAAC,kBAAkB;IACjC,kCAAc,CAAC,gBAAgB;CAChC,CAAC,CAAC;AAEU,QAAA,wCAAwC,GAAG;IACtD,SAAS,EAAE,QAAiB;IAC5B,MAAM,EAAE;QACN,UAAU,EAAE,KAAM;KACnB;CACF,CAAC;AAEF;;GAEG;AACU,QAAA,sBAAsB,GAAG,GAAG,CAAC;AAE1C,+DAA+D;AAClD,QAAA,eAAe,GAAG,UAAU,CAAC;AAE1C,+DAA+D;AAClD,QAAA,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,yBAAW,CAAC,eAAe;IAC3B,yBAAW,CAAC,WAAW;IACvB,yBAAW,CAAC,aAAa;IACzB,yBAAW,CAAC,SAAS;IACrB,yBAAW,CAAC,YAAY;IACxB,yBAAW,CAAC,UAAU;IACtB,yBAAW,CAAC,cAAc;IAC1B,yBAAW,CAAC,WAAW;IACvB,yBAAW,CAAC,cAAc;IAC1B,yBAAW,CAAC,kBAAkB;IAC9B,yBAAW,CAAC,sBAAsB;IAClC,yBAAW,CAAC,gBAAgB;CAC7B,CAAC,CAAC","sourcesContent":["import { SnapEndowments } from '@metamask/snaps-rpc-methods';\nimport { HandlerType } from '@metamask/snaps-utils';\n\n// These permissions are allowed without being on the allowlist.\nexport const ALLOWED_PERMISSIONS = Object.freeze([\n 'snap_dialog',\n 'snap_manageState',\n 'snap_notify',\n 'snap_getLocale',\n SnapEndowments.Cronjob,\n SnapEndowments.HomePage,\n SnapEndowments.LifecycleHooks,\n SnapEndowments.EthereumProvider,\n SnapEndowments.TransactionInsight,\n SnapEndowments.SignatureInsight,\n]);\n\nexport const LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS = {\n algorithm: 'PBKDF2' as const,\n params: {\n iterations: 10_000,\n },\n};\n\n/**\n * The timeout for debouncing state updates.\n */\nexport const STATE_DEBOUNCE_TIMEOUT = 500;\n\n// The origin used to indicate requests coming from the client.\nexport const METAMASK_ORIGIN = 'metamask';\n\n// These handlers are only allowed to be invoked by the client.\nexport const CLIENT_ONLY_HANDLERS = Object.freeze([\n HandlerType.OnClientRequest,\n HandlerType.OnSignature,\n HandlerType.OnTransaction,\n HandlerType.OnCronjob,\n HandlerType.OnNameLookup,\n HandlerType.OnHomePage,\n HandlerType.OnSettingsPage,\n HandlerType.OnUserInput,\n HandlerType.OnAssetsLookup,\n HandlerType.OnAssetsConversion,\n HandlerType.OnAssetHistoricalPrice,\n HandlerType.OnWebSocketEvent,\n]);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAGpD,eAAO,MAAM,mBAAmB,mBAW9B,CAAC;AAEH,eAAO,MAAM,wCAAwC;;;;;CAKpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAG1C,eAAO,MAAM,eAAe,aAAa,CAAC;AAG1C,eAAO,MAAM,oBAAoB,wBAY/B,CAAC"}
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAGpD,eAAO,MAAM,mBAAmB,mBAW9B,CAAC;AAEH,eAAO,MAAM,wCAAwC;;;;;CAKpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAG1C,eAAO,MAAM,eAAe,aAAa,CAAC;AAG1C,eAAO,MAAM,oBAAoB,wBAa/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAGpD,eAAO,MAAM,mBAAmB,mBAW9B,CAAC;AAEH,eAAO,MAAM,wCAAwC;;;;;CAKpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAG1C,eAAO,MAAM,eAAe,aAAa,CAAC;AAG1C,eAAO,MAAM,oBAAoB,wBAY/B,CAAC"}
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAGpD,eAAO,MAAM,mBAAmB,mBAW9B,CAAC;AAEH,eAAO,MAAM,wCAAwC;;;;;CAKpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAG1C,eAAO,MAAM,eAAe,aAAa,CAAC;AAG1C,eAAO,MAAM,oBAAoB,wBAa/B,CAAC"}
@@ -38,5 +38,6 @@ export const CLIENT_ONLY_HANDLERS = Object.freeze([
38
38
  HandlerType.OnAssetsLookup,
39
39
  HandlerType.OnAssetsConversion,
40
40
  HandlerType.OnAssetHistoricalPrice,
41
+ HandlerType.OnWebSocketEvent,
41
42
  ]);
42
43
  //# sourceMappingURL=constants.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oCAAoC;AAC7D,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAEpD,gEAAgE;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/C,aAAa;IACb,kBAAkB;IAClB,aAAa;IACb,gBAAgB;IAChB,cAAc,CAAC,OAAO;IACtB,cAAc,CAAC,QAAQ;IACvB,cAAc,CAAC,cAAc;IAC7B,cAAc,CAAC,gBAAgB;IAC/B,cAAc,CAAC,kBAAkB;IACjC,cAAc,CAAC,gBAAgB;CAChC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wCAAwC,GAAG;IACtD,SAAS,EAAE,QAAiB;IAC5B,MAAM,EAAE;QACN,UAAU,EAAE,KAAM;KACnB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,WAAW,CAAC,eAAe;IAC3B,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,YAAY;IACxB,WAAW,CAAC,UAAU;IACtB,WAAW,CAAC,cAAc;IAC1B,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,cAAc;IAC1B,WAAW,CAAC,kBAAkB;IAC9B,WAAW,CAAC,sBAAsB;CACnC,CAAC,CAAC","sourcesContent":["import { SnapEndowments } from '@metamask/snaps-rpc-methods';\nimport { HandlerType } from '@metamask/snaps-utils';\n\n// These permissions are allowed without being on the allowlist.\nexport const ALLOWED_PERMISSIONS = Object.freeze([\n 'snap_dialog',\n 'snap_manageState',\n 'snap_notify',\n 'snap_getLocale',\n SnapEndowments.Cronjob,\n SnapEndowments.HomePage,\n SnapEndowments.LifecycleHooks,\n SnapEndowments.EthereumProvider,\n SnapEndowments.TransactionInsight,\n SnapEndowments.SignatureInsight,\n]);\n\nexport const LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS = {\n algorithm: 'PBKDF2' as const,\n params: {\n iterations: 10_000,\n },\n};\n\n/**\n * The timeout for debouncing state updates.\n */\nexport const STATE_DEBOUNCE_TIMEOUT = 500;\n\n// The origin used to indicate requests coming from the client.\nexport const METAMASK_ORIGIN = 'metamask';\n\n// These handlers are only allowed to be invoked by the client.\nexport const CLIENT_ONLY_HANDLERS = Object.freeze([\n HandlerType.OnClientRequest,\n HandlerType.OnSignature,\n HandlerType.OnTransaction,\n HandlerType.OnCronjob,\n HandlerType.OnNameLookup,\n HandlerType.OnHomePage,\n HandlerType.OnSettingsPage,\n HandlerType.OnUserInput,\n HandlerType.OnAssetsLookup,\n HandlerType.OnAssetsConversion,\n HandlerType.OnAssetHistoricalPrice,\n]);\n"]}
1
+ {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../src/snaps/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oCAAoC;AAC7D,OAAO,EAAE,WAAW,EAAE,8BAA8B;AAEpD,gEAAgE;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC/C,aAAa;IACb,kBAAkB;IAClB,aAAa;IACb,gBAAgB;IAChB,cAAc,CAAC,OAAO;IACtB,cAAc,CAAC,QAAQ;IACvB,cAAc,CAAC,cAAc;IAC7B,cAAc,CAAC,gBAAgB;IAC/B,cAAc,CAAC,kBAAkB;IACjC,cAAc,CAAC,gBAAgB;CAChC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wCAAwC,GAAG;IACtD,SAAS,EAAE,QAAiB;IAC5B,MAAM,EAAE;QACN,UAAU,EAAE,KAAM;KACnB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,WAAW,CAAC,eAAe;IAC3B,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,aAAa;IACzB,WAAW,CAAC,SAAS;IACrB,WAAW,CAAC,YAAY;IACxB,WAAW,CAAC,UAAU;IACtB,WAAW,CAAC,cAAc;IAC1B,WAAW,CAAC,WAAW;IACvB,WAAW,CAAC,cAAc;IAC1B,WAAW,CAAC,kBAAkB;IAC9B,WAAW,CAAC,sBAAsB;IAClC,WAAW,CAAC,gBAAgB;CAC7B,CAAC,CAAC","sourcesContent":["import { SnapEndowments } from '@metamask/snaps-rpc-methods';\nimport { HandlerType } from '@metamask/snaps-utils';\n\n// These permissions are allowed without being on the allowlist.\nexport const ALLOWED_PERMISSIONS = Object.freeze([\n 'snap_dialog',\n 'snap_manageState',\n 'snap_notify',\n 'snap_getLocale',\n SnapEndowments.Cronjob,\n SnapEndowments.HomePage,\n SnapEndowments.LifecycleHooks,\n SnapEndowments.EthereumProvider,\n SnapEndowments.TransactionInsight,\n SnapEndowments.SignatureInsight,\n]);\n\nexport const LEGACY_ENCRYPTION_KEY_DERIVATION_OPTIONS = {\n algorithm: 'PBKDF2' as const,\n params: {\n iterations: 10_000,\n },\n};\n\n/**\n * The timeout for debouncing state updates.\n */\nexport const STATE_DEBOUNCE_TIMEOUT = 500;\n\n// The origin used to indicate requests coming from the client.\nexport const METAMASK_ORIGIN = 'metamask';\n\n// These handlers are only allowed to be invoked by the client.\nexport const CLIENT_ONLY_HANDLERS = Object.freeze([\n HandlerType.OnClientRequest,\n HandlerType.OnSignature,\n HandlerType.OnTransaction,\n HandlerType.OnCronjob,\n HandlerType.OnNameLookup,\n HandlerType.OnHomePage,\n HandlerType.OnSettingsPage,\n HandlerType.OnUserInput,\n HandlerType.OnAssetsLookup,\n HandlerType.OnAssetsConversion,\n HandlerType.OnAssetHistoricalPrice,\n HandlerType.OnWebSocketEvent,\n]);\n"]}
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./constants.cjs"), exports);
17
18
  __exportStar(require("./location/index.cjs"), exports);
18
19
  __exportStar(require("./SnapController.cjs"), exports);
19
20
  __exportStar(require("./selectors.cjs"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAA2B;AAC3B,uDAAiC;AACjC,kDAA4B;AAC5B,uDAA2B","sourcesContent":["export * from './location';\nexport * from './SnapController';\nexport * from './selectors';\nexport * from './registry';\n"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAA4B;AAC5B,uDAA2B;AAC3B,uDAAiC;AACjC,kDAA4B;AAC5B,uDAA2B","sourcesContent":["export * from './constants';\nexport * from './location';\nexport * from './SnapController';\nexport * from './selectors';\nexport * from './registry';\n"]}
@@ -1,3 +1,4 @@
1
+ export * from "./constants.cjs";
1
2
  export * from "./location/index.cjs";
2
3
  export * from "./SnapController.cjs";
3
4
  export * from "./selectors.cjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":"AAAA,qCAA2B;AAC3B,qCAAiC;AACjC,gCAA4B;AAC5B,qCAA2B"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":"AAAA,gCAA4B;AAC5B,qCAA2B;AAC3B,qCAAiC;AACjC,gCAA4B;AAC5B,qCAA2B"}
@@ -1,3 +1,4 @@
1
+ export * from "./constants.mjs";
1
2
  export * from "./location/index.mjs";
2
3
  export * from "./SnapController.mjs";
3
4
  export * from "./selectors.mjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":"AAAA,qCAA2B;AAC3B,qCAAiC;AACjC,gCAA4B;AAC5B,qCAA2B"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":"AAAA,gCAA4B;AAC5B,qCAA2B;AAC3B,qCAAiC;AACjC,gCAA4B;AAC5B,qCAA2B"}
@@ -1,3 +1,4 @@
1
+ export * from "./constants.mjs";
1
2
  export * from "./location/index.mjs";
2
3
  export * from "./SnapController.mjs";
3
4
  export * from "./selectors.mjs";
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":"AAAA,qCAA2B;AAC3B,qCAAiC;AACjC,gCAA4B;AAC5B,qCAA2B","sourcesContent":["export * from './location';\nexport * from './SnapController';\nexport * from './selectors';\nexport * from './registry';\n"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/snaps/index.ts"],"names":[],"mappings":"AAAA,gCAA4B;AAC5B,qCAA2B;AAC3B,qCAAiC;AACjC,gCAA4B;AAC5B,qCAA2B","sourcesContent":["export * from './constants';\nexport * from './location';\nexport * from './SnapController';\nexport * from './selectors';\nexport * from './registry';\n"]}
package/dist/utils.d.cts CHANGED
@@ -232,7 +232,7 @@ export declare function fetchSnap(snapId: SnapId, location: SnapLocation): Promi
232
232
  type: string;
233
233
  url: string;
234
234
  } | undefined;
235
- initialConnections?: Record<string & URL, {}> | undefined;
235
+ initialConnections?: Record<string, {}> | undefined;
236
236
  platformVersion?: import("@metamask/utils").SemVerVersion | undefined;
237
237
  $schema?: string | undefined;
238
238
  }>;
package/dist/utils.d.mts CHANGED
@@ -232,7 +232,7 @@ export declare function fetchSnap(snapId: SnapId, location: SnapLocation): Promi
232
232
  type: string;
233
233
  url: string;
234
234
  } | undefined;
235
- initialConnections?: Record<string & URL, {}> | undefined;
235
+ initialConnections?: Record<string, {}> | undefined;
236
236
  platformVersion?: import("@metamask/utils").SemVerVersion | undefined;
237
237
  $schema?: string | undefined;
238
238
  }>;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebSocketService = void 0;
4
+ const rpc_errors_1 = require("@metamask/rpc-errors");
5
+ const snaps_utils_1 = require("@metamask/snaps-utils");
6
+ const utils_1 = require("@metamask/utils");
7
+ const nanoid_1 = require("nanoid");
8
+ const snaps_1 = require("../snaps/index.cjs");
9
+ const serviceName = 'WebSocketService';
10
+ class WebSocketService {
11
+ #messenger;
12
+ #sockets;
13
+ constructor({ messenger }) {
14
+ this.#messenger = messenger;
15
+ this.#sockets = new Map();
16
+ this.#messenger.registerActionHandler(`${serviceName}:open`, async (...args) => this.#open(...args));
17
+ this.#messenger.registerActionHandler(`${serviceName}:close`, (...args) => this.#close(...args));
18
+ this.#messenger.registerActionHandler(`${serviceName}:sendMessage`, async (...args) => this.#sendMessage(...args));
19
+ this.#messenger.registerActionHandler(`${serviceName}:getAll`, (...args) => this.#getAll(...args));
20
+ this.#messenger.subscribe('SnapController:snapUpdated', (snap) => {
21
+ this.#closeAll(snap.id);
22
+ });
23
+ this.#messenger.subscribe('SnapController:snapUninstalled', (snap) => {
24
+ this.#closeAll(snap.id);
25
+ });
26
+ // Due to local Snaps not currently emitting snapUninstalled we also have to
27
+ // listen to snapInstalled.
28
+ this.#messenger.subscribe('SnapController:snapInstalled', (snap) => {
29
+ this.#closeAll(snap.id);
30
+ });
31
+ }
32
+ /**
33
+ * Get information about a given WebSocket connection with an ID.
34
+ *
35
+ * @param snapId - The Snap ID.
36
+ * @param id - The identifier for the WebSocket connection.
37
+ * @returns Information abou the WebSocket connection.
38
+ * @throws If the WebSocket connection cannot be found.
39
+ */
40
+ #get(snapId, id) {
41
+ const socket = this.#sockets.get(id);
42
+ (0, utils_1.assert)(socket && socket.snapId === snapId, `Socket with ID "${id}" not found.`);
43
+ return socket;
44
+ }
45
+ /**
46
+ * Check whether a given Snap ID already has an open connection for a URL and protocol.
47
+ *
48
+ * @param snapId - The Snap ID.
49
+ * @param url - The URL.
50
+ * @param protocols - A protocols parameter.
51
+ * @returns True if a matching connection already exists, otherwise false.
52
+ */
53
+ #exists(snapId, url, protocols) {
54
+ return this.#getAll(snapId).some((socket) => socket.url === url && (0, snaps_utils_1.isEqual)(socket.protocols, protocols));
55
+ }
56
+ /**
57
+ * Handle sending a specific WebSocketEvent to a Snap.
58
+ *
59
+ * @param snapId - The Snap ID.
60
+ * @param event - The WebSocketEvent.
61
+ */
62
+ #handleEvent(snapId, event) {
63
+ this.#messenger
64
+ .call('SnapController:handleRequest', {
65
+ origin: snaps_1.METAMASK_ORIGIN,
66
+ snapId,
67
+ handler: snaps_utils_1.HandlerType.OnWebSocketEvent,
68
+ request: { method: '', params: { event } },
69
+ })
70
+ .catch((error) => {
71
+ (0, snaps_utils_1.logError)(`An error occurred while handling a WebSocket message for Snap "${snapId}":`, error);
72
+ });
73
+ }
74
+ /**
75
+ * Open a WebSocket connection.
76
+ *
77
+ * @param snapId - The Snap ID.
78
+ * @param url - The URL for the WebSocket connection.
79
+ * @param protocols - An optional parameter for protocols.
80
+ * @returns The identifier for the opened connection.
81
+ * @throws If the connection fails.
82
+ */
83
+ async #open(snapId, url, protocols = []) {
84
+ (0, utils_1.assert)(!this.#exists(snapId, url, protocols), `An open WebSocket connection to ${url} already exists.`);
85
+ const parsedUrl = new URL(url);
86
+ const { origin } = parsedUrl;
87
+ const id = (0, nanoid_1.nanoid)();
88
+ // eslint-disable-next-line no-restricted-globals
89
+ const socket = new WebSocket(url, protocols);
90
+ socket.binaryType = 'arraybuffer';
91
+ const { promise, resolve, reject } = (0, utils_1.createDeferredPromise)();
92
+ socket.addEventListener('open', () => {
93
+ resolve();
94
+ this.#handleEvent(snapId, {
95
+ type: 'open',
96
+ id,
97
+ origin,
98
+ });
99
+ });
100
+ socket.addEventListener('close', (event) => {
101
+ this.#handleEvent(snapId, {
102
+ type: 'close',
103
+ id,
104
+ origin,
105
+ code: event.code,
106
+ reason: event.reason,
107
+ // wasClean is not available on mobile.
108
+ wasClean: event.wasClean ?? null,
109
+ });
110
+ });
111
+ const errorListener = () => {
112
+ reject(rpc_errors_1.rpcErrors.resourceUnavailable('An error occurred while opening the WebSocket.'));
113
+ };
114
+ socket.addEventListener('error', errorListener);
115
+ socket.addEventListener('message', (event) => {
116
+ const isText = typeof event.data === 'string';
117
+ const data = isText
118
+ ? { type: 'text', message: event.data }
119
+ : {
120
+ type: 'binary',
121
+ // We request that the WebSocket gives us an array buffer.
122
+ message: Array.from(new Uint8Array(event.data)),
123
+ };
124
+ this.#handleEvent(snapId, {
125
+ type: 'message',
126
+ id,
127
+ origin,
128
+ data,
129
+ });
130
+ });
131
+ this.#sockets.set(id, {
132
+ id,
133
+ snapId,
134
+ url,
135
+ protocols,
136
+ socket,
137
+ openPromise: promise,
138
+ });
139
+ await promise;
140
+ socket.removeEventListener('error', errorListener);
141
+ return id;
142
+ }
143
+ /**
144
+ * Close a given WebSocket connection.
145
+ *
146
+ * @param snapId - The Snap ID.
147
+ * @param id - The identifier for the WebSocket connection.
148
+ */
149
+ #close(snapId, id) {
150
+ const { socket } = this.#get(snapId, id);
151
+ socket.close();
152
+ this.#sockets.delete(id);
153
+ }
154
+ /**
155
+ * Close all open connections for a given Snap ID.
156
+ *
157
+ * @param snapId - The Snap ID.
158
+ */
159
+ #closeAll(snapId) {
160
+ for (const socket of this.#getAll(snapId)) {
161
+ this.#close(snapId, socket.id);
162
+ }
163
+ }
164
+ /**
165
+ * Send a message from a given Snap ID to a WebSocket connection.
166
+ *
167
+ * @param snapId - The Snap ID.
168
+ * @param id - The identifier for the WebSocket connection.
169
+ * @param data - The message to send.
170
+ */
171
+ async #sendMessage(snapId, id, data) {
172
+ const { socket, openPromise } = this.#get(snapId, id);
173
+ await openPromise;
174
+ const wrappedData = Array.isArray(data) ? new Uint8Array(data) : data;
175
+ socket.send(wrappedData);
176
+ }
177
+ /**
178
+ * Get a list of all open WebSocket connections for a Snap ID.
179
+ *
180
+ * @param snapId - The Snap ID.
181
+ * @returns A list of WebSocket connections.
182
+ */
183
+ #getAll(snapId) {
184
+ return [...this.#sockets.values()]
185
+ .filter((socket) => socket.snapId === snapId)
186
+ .map((socket) => ({
187
+ id: socket.id,
188
+ url: socket.url,
189
+ protocols: socket.protocols,
190
+ }));
191
+ }
192
+ }
193
+ exports.WebSocketService = WebSocketService;
194
+ //# sourceMappingURL=WebSocketService.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSocketService.cjs","sourceRoot":"","sources":["../../src/websocket/WebSocketService.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RestrictedMessenger } from '@metamask/base-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type {\n GetWebSocketsResult,\n SnapId,\n WebSocketEvent,\n} from '@metamask/snaps-sdk';\nimport { HandlerType, isEqual, logError } from '@metamask/snaps-utils';\nimport { assert, createDeferredPromise } from '@metamask/utils';\nimport { nanoid } from 'nanoid';\n\nimport type {\n HandleSnapRequest,\n SnapInstalled,\n SnapUninstalled,\n SnapUpdated,\n} from '../snaps';\nimport { METAMASK_ORIGIN } from '../snaps';\n\nconst serviceName = 'WebSocketService';\n\nexport type WebSocketServiceOpenAction = {\n type: `${typeof serviceName}:open`;\n handler: (\n snapId: SnapId,\n url: string,\n protocols?: string[],\n ) => Promise<string>;\n};\n\nexport type WebSocketServiceCloseAction = {\n type: `${typeof serviceName}:close`;\n handler: (snapId: SnapId, id: string) => void;\n};\n\nexport type WebSocketServiceSendMessageAction = {\n type: `${typeof serviceName}:sendMessage`;\n handler: (\n snapId: SnapId,\n id: string,\n data: string | number[],\n ) => Promise<void>;\n};\n\nexport type WebSocketServiceGetAllAction = {\n type: `${typeof serviceName}:getAll`;\n handler: (snapId: SnapId) => GetWebSocketsResult;\n};\n\nexport type WebSocketServiceActions =\n | WebSocketServiceOpenAction\n | WebSocketServiceCloseAction\n | WebSocketServiceSendMessageAction\n | WebSocketServiceGetAllAction;\n\nexport type WebSocketServiceAllowedActions = HandleSnapRequest;\n\nexport type WebSocketServiceEvents =\n | SnapUninstalled\n | SnapUpdated\n | SnapInstalled;\n\nexport type WebSocketServiceMessenger = RestrictedMessenger<\n 'WebSocketService',\n WebSocketServiceActions | WebSocketServiceAllowedActions,\n WebSocketServiceEvents,\n WebSocketServiceAllowedActions['type'],\n WebSocketServiceEvents['type']\n>;\n\ntype WebSocketServiceArgs = {\n messenger: WebSocketServiceMessenger;\n};\n\ntype InternalSocket = {\n id: string;\n snapId: SnapId;\n url: string;\n protocols: string[];\n openPromise: Promise<void>;\n // eslint-disable-next-line no-restricted-globals\n socket: WebSocket;\n};\n\nexport class WebSocketService {\n readonly #messenger: WebSocketServiceMessenger;\n\n readonly #sockets: Map<string, InternalSocket>;\n\n constructor({ messenger }: WebSocketServiceArgs) {\n this.#messenger = messenger;\n this.#sockets = new Map();\n\n this.#messenger.registerActionHandler(\n `${serviceName}:open`,\n async (...args) => this.#open(...args),\n );\n\n this.#messenger.registerActionHandler(`${serviceName}:close`, (...args) =>\n this.#close(...args),\n );\n\n this.#messenger.registerActionHandler(\n `${serviceName}:sendMessage`,\n async (...args) => this.#sendMessage(...args),\n );\n\n this.#messenger.registerActionHandler(`${serviceName}:getAll`, (...args) =>\n this.#getAll(...args),\n );\n\n this.#messenger.subscribe('SnapController:snapUpdated', (snap) => {\n this.#closeAll(snap.id);\n });\n\n this.#messenger.subscribe('SnapController:snapUninstalled', (snap) => {\n this.#closeAll(snap.id);\n });\n\n // Due to local Snaps not currently emitting snapUninstalled we also have to\n // listen to snapInstalled.\n this.#messenger.subscribe('SnapController:snapInstalled', (snap) => {\n this.#closeAll(snap.id);\n });\n }\n\n /**\n * Get information about a given WebSocket connection with an ID.\n *\n * @param snapId - The Snap ID.\n * @param id - The identifier for the WebSocket connection.\n * @returns Information abou the WebSocket connection.\n * @throws If the WebSocket connection cannot be found.\n */\n #get(snapId: SnapId, id: string) {\n const socket = this.#sockets.get(id);\n\n assert(\n socket && socket.snapId === snapId,\n `Socket with ID \"${id}\" not found.`,\n );\n\n return socket;\n }\n\n /**\n * Check whether a given Snap ID already has an open connection for a URL and protocol.\n *\n * @param snapId - The Snap ID.\n * @param url - The URL.\n * @param protocols - A protocols parameter.\n * @returns True if a matching connection already exists, otherwise false.\n */\n #exists(snapId: SnapId, url: string, protocols: string[]) {\n return this.#getAll(snapId).some(\n (socket) => socket.url === url && isEqual(socket.protocols, protocols),\n );\n }\n\n /**\n * Handle sending a specific WebSocketEvent to a Snap.\n *\n * @param snapId - The Snap ID.\n * @param event - The WebSocketEvent.\n */\n #handleEvent(snapId: SnapId, event: WebSocketEvent) {\n this.#messenger\n .call('SnapController:handleRequest', {\n origin: METAMASK_ORIGIN,\n snapId,\n handler: HandlerType.OnWebSocketEvent,\n request: { method: '', params: { event } },\n })\n .catch((error) => {\n logError(\n `An error occurred while handling a WebSocket message for Snap \"${snapId}\":`,\n error,\n );\n });\n }\n\n /**\n * Open a WebSocket connection.\n *\n * @param snapId - The Snap ID.\n * @param url - The URL for the WebSocket connection.\n * @param protocols - An optional parameter for protocols.\n * @returns The identifier for the opened connection.\n * @throws If the connection fails.\n */\n async #open(snapId: SnapId, url: string, protocols: string[] = []) {\n assert(\n !this.#exists(snapId, url, protocols),\n `An open WebSocket connection to ${url} already exists.`,\n );\n\n const parsedUrl = new URL(url);\n const { origin } = parsedUrl;\n\n const id = nanoid();\n\n // eslint-disable-next-line no-restricted-globals\n const socket = new WebSocket(url, protocols);\n socket.binaryType = 'arraybuffer';\n\n const { promise, resolve, reject } = createDeferredPromise();\n\n socket.addEventListener('open', () => {\n resolve();\n this.#handleEvent(snapId, {\n type: 'open',\n id,\n origin,\n });\n });\n\n socket.addEventListener('close', (event) => {\n this.#handleEvent(snapId, {\n type: 'close',\n id,\n origin,\n code: event.code,\n reason: event.reason,\n // wasClean is not available on mobile.\n wasClean: event.wasClean ?? null,\n });\n });\n\n const errorListener = () => {\n reject(\n rpcErrors.resourceUnavailable(\n 'An error occurred while opening the WebSocket.',\n ),\n );\n };\n\n socket.addEventListener('error', errorListener);\n\n socket.addEventListener('message', (event) => {\n const isText = typeof event.data === 'string';\n const data = isText\n ? { type: 'text' as const, message: event.data }\n : {\n type: 'binary' as const,\n // We request that the WebSocket gives us an array buffer.\n message: Array.from(new Uint8Array(event.data)),\n };\n\n this.#handleEvent(snapId, {\n type: 'message',\n id,\n origin,\n data,\n });\n });\n\n this.#sockets.set(id, {\n id,\n snapId,\n url,\n protocols,\n socket,\n openPromise: promise,\n });\n\n await promise;\n\n socket.removeEventListener('error', errorListener);\n\n return id;\n }\n\n /**\n * Close a given WebSocket connection.\n *\n * @param snapId - The Snap ID.\n * @param id - The identifier for the WebSocket connection.\n */\n #close(snapId: SnapId, id: string) {\n const { socket } = this.#get(snapId, id);\n\n socket.close();\n\n this.#sockets.delete(id);\n }\n\n /**\n * Close all open connections for a given Snap ID.\n *\n * @param snapId - The Snap ID.\n */\n #closeAll(snapId: SnapId) {\n for (const socket of this.#getAll(snapId)) {\n this.#close(snapId, socket.id);\n }\n }\n\n /**\n * Send a message from a given Snap ID to a WebSocket connection.\n *\n * @param snapId - The Snap ID.\n * @param id - The identifier for the WebSocket connection.\n * @param data - The message to send.\n */\n async #sendMessage(snapId: SnapId, id: string, data: string | number[]) {\n const { socket, openPromise } = this.#get(snapId, id);\n\n await openPromise;\n\n const wrappedData = Array.isArray(data) ? new Uint8Array(data) : data;\n\n socket.send(wrappedData);\n }\n\n /**\n * Get a list of all open WebSocket connections for a Snap ID.\n *\n * @param snapId - The Snap ID.\n * @returns A list of WebSocket connections.\n */\n #getAll(snapId: SnapId) {\n return [...this.#sockets.values()]\n .filter((socket) => socket.snapId === snapId)\n .map((socket) => ({\n id: socket.id,\n url: socket.url,\n protocols: socket.protocols,\n }));\n }\n}\n"]}
@@ -0,0 +1,33 @@
1
+ import type { RestrictedMessenger } from "@metamask/base-controller";
2
+ import type { GetWebSocketsResult, SnapId } from "@metamask/snaps-sdk";
3
+ import type { HandleSnapRequest, SnapInstalled, SnapUninstalled, SnapUpdated } from "../snaps/index.cjs";
4
+ declare const serviceName = "WebSocketService";
5
+ export type WebSocketServiceOpenAction = {
6
+ type: `${typeof serviceName}:open`;
7
+ handler: (snapId: SnapId, url: string, protocols?: string[]) => Promise<string>;
8
+ };
9
+ export type WebSocketServiceCloseAction = {
10
+ type: `${typeof serviceName}:close`;
11
+ handler: (snapId: SnapId, id: string) => void;
12
+ };
13
+ export type WebSocketServiceSendMessageAction = {
14
+ type: `${typeof serviceName}:sendMessage`;
15
+ handler: (snapId: SnapId, id: string, data: string | number[]) => Promise<void>;
16
+ };
17
+ export type WebSocketServiceGetAllAction = {
18
+ type: `${typeof serviceName}:getAll`;
19
+ handler: (snapId: SnapId) => GetWebSocketsResult;
20
+ };
21
+ export type WebSocketServiceActions = WebSocketServiceOpenAction | WebSocketServiceCloseAction | WebSocketServiceSendMessageAction | WebSocketServiceGetAllAction;
22
+ export type WebSocketServiceAllowedActions = HandleSnapRequest;
23
+ export type WebSocketServiceEvents = SnapUninstalled | SnapUpdated | SnapInstalled;
24
+ export type WebSocketServiceMessenger = RestrictedMessenger<'WebSocketService', WebSocketServiceActions | WebSocketServiceAllowedActions, WebSocketServiceEvents, WebSocketServiceAllowedActions['type'], WebSocketServiceEvents['type']>;
25
+ type WebSocketServiceArgs = {
26
+ messenger: WebSocketServiceMessenger;
27
+ };
28
+ export declare class WebSocketService {
29
+ #private;
30
+ constructor({ messenger }: WebSocketServiceArgs);
31
+ }
32
+ export {};
33
+ //# sourceMappingURL=WebSocketService.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSocketService.d.cts","sourceRoot":"","sources":["../../src/websocket/WebSocketService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kCAAkC;AAErE,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EAEP,4BAA4B;AAK7B,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,WAAW,EACZ,2BAAiB;AAGlB,QAAA,MAAM,WAAW,qBAAqB,CAAC;AAEvC,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,GAAG,OAAO,WAAW,OAAO,CAAC;IACnC,OAAO,EAAE,CACP,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAAE,KACjB,OAAO,CAAC,MAAM,CAAC,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,GAAG,OAAO,WAAW,QAAQ,CAAC;IACpC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,GAAG,OAAO,WAAW,cAAc,CAAC;IAC1C,OAAO,EAAE,CACP,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KACpB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,GAAG,OAAO,WAAW,SAAS,CAAC;IACrC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,mBAAmB,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,0BAA0B,GAC1B,2BAA2B,GAC3B,iCAAiC,GACjC,4BAA4B,CAAC;AAEjC,MAAM,MAAM,8BAA8B,GAAG,iBAAiB,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAC9B,eAAe,GACf,WAAW,GACX,aAAa,CAAC;AAElB,MAAM,MAAM,yBAAyB,GAAG,mBAAmB,CACzD,kBAAkB,EAClB,uBAAuB,GAAG,8BAA8B,EACxD,sBAAsB,EACtB,8BAA8B,CAAC,MAAM,CAAC,EACtC,sBAAsB,CAAC,MAAM,CAAC,CAC/B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,SAAS,EAAE,yBAAyB,CAAC;CACtC,CAAC;AAYF,qBAAa,gBAAgB;;gBAKf,EAAE,SAAS,EAAE,EAAE,oBAAoB;CAgPhD"}
@@ -0,0 +1,33 @@
1
+ import type { RestrictedMessenger } from "@metamask/base-controller";
2
+ import type { GetWebSocketsResult, SnapId } from "@metamask/snaps-sdk";
3
+ import type { HandleSnapRequest, SnapInstalled, SnapUninstalled, SnapUpdated } from "../snaps/index.mjs";
4
+ declare const serviceName = "WebSocketService";
5
+ export type WebSocketServiceOpenAction = {
6
+ type: `${typeof serviceName}:open`;
7
+ handler: (snapId: SnapId, url: string, protocols?: string[]) => Promise<string>;
8
+ };
9
+ export type WebSocketServiceCloseAction = {
10
+ type: `${typeof serviceName}:close`;
11
+ handler: (snapId: SnapId, id: string) => void;
12
+ };
13
+ export type WebSocketServiceSendMessageAction = {
14
+ type: `${typeof serviceName}:sendMessage`;
15
+ handler: (snapId: SnapId, id: string, data: string | number[]) => Promise<void>;
16
+ };
17
+ export type WebSocketServiceGetAllAction = {
18
+ type: `${typeof serviceName}:getAll`;
19
+ handler: (snapId: SnapId) => GetWebSocketsResult;
20
+ };
21
+ export type WebSocketServiceActions = WebSocketServiceOpenAction | WebSocketServiceCloseAction | WebSocketServiceSendMessageAction | WebSocketServiceGetAllAction;
22
+ export type WebSocketServiceAllowedActions = HandleSnapRequest;
23
+ export type WebSocketServiceEvents = SnapUninstalled | SnapUpdated | SnapInstalled;
24
+ export type WebSocketServiceMessenger = RestrictedMessenger<'WebSocketService', WebSocketServiceActions | WebSocketServiceAllowedActions, WebSocketServiceEvents, WebSocketServiceAllowedActions['type'], WebSocketServiceEvents['type']>;
25
+ type WebSocketServiceArgs = {
26
+ messenger: WebSocketServiceMessenger;
27
+ };
28
+ export declare class WebSocketService {
29
+ #private;
30
+ constructor({ messenger }: WebSocketServiceArgs);
31
+ }
32
+ export {};
33
+ //# sourceMappingURL=WebSocketService.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSocketService.d.mts","sourceRoot":"","sources":["../../src/websocket/WebSocketService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kCAAkC;AAErE,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EAEP,4BAA4B;AAK7B,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,WAAW,EACZ,2BAAiB;AAGlB,QAAA,MAAM,WAAW,qBAAqB,CAAC;AAEvC,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,GAAG,OAAO,WAAW,OAAO,CAAC;IACnC,OAAO,EAAE,CACP,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAAE,KACjB,OAAO,CAAC,MAAM,CAAC,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,GAAG,OAAO,WAAW,QAAQ,CAAC;IACpC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,GAAG,OAAO,WAAW,cAAc,CAAC;IAC1C,OAAO,EAAE,CACP,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KACpB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,GAAG,OAAO,WAAW,SAAS,CAAC;IACrC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,mBAAmB,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,0BAA0B,GAC1B,2BAA2B,GAC3B,iCAAiC,GACjC,4BAA4B,CAAC;AAEjC,MAAM,MAAM,8BAA8B,GAAG,iBAAiB,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAC9B,eAAe,GACf,WAAW,GACX,aAAa,CAAC;AAElB,MAAM,MAAM,yBAAyB,GAAG,mBAAmB,CACzD,kBAAkB,EAClB,uBAAuB,GAAG,8BAA8B,EACxD,sBAAsB,EACtB,8BAA8B,CAAC,MAAM,CAAC,EACtC,sBAAsB,CAAC,MAAM,CAAC,CAC/B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,SAAS,EAAE,yBAAyB,CAAC;CACtC,CAAC;AAYF,qBAAa,gBAAgB;;gBAKf,EAAE,SAAS,EAAE,EAAE,oBAAoB;CAgPhD"}
@@ -0,0 +1,190 @@
1
+ import { rpcErrors } from "@metamask/rpc-errors";
2
+ import { HandlerType, isEqual, logError } from "@metamask/snaps-utils";
3
+ import { assert, createDeferredPromise } from "@metamask/utils";
4
+ import { nanoid } from "nanoid";
5
+ import { METAMASK_ORIGIN } from "../snaps/index.mjs";
6
+ const serviceName = 'WebSocketService';
7
+ export class WebSocketService {
8
+ #messenger;
9
+ #sockets;
10
+ constructor({ messenger }) {
11
+ this.#messenger = messenger;
12
+ this.#sockets = new Map();
13
+ this.#messenger.registerActionHandler(`${serviceName}:open`, async (...args) => this.#open(...args));
14
+ this.#messenger.registerActionHandler(`${serviceName}:close`, (...args) => this.#close(...args));
15
+ this.#messenger.registerActionHandler(`${serviceName}:sendMessage`, async (...args) => this.#sendMessage(...args));
16
+ this.#messenger.registerActionHandler(`${serviceName}:getAll`, (...args) => this.#getAll(...args));
17
+ this.#messenger.subscribe('SnapController:snapUpdated', (snap) => {
18
+ this.#closeAll(snap.id);
19
+ });
20
+ this.#messenger.subscribe('SnapController:snapUninstalled', (snap) => {
21
+ this.#closeAll(snap.id);
22
+ });
23
+ // Due to local Snaps not currently emitting snapUninstalled we also have to
24
+ // listen to snapInstalled.
25
+ this.#messenger.subscribe('SnapController:snapInstalled', (snap) => {
26
+ this.#closeAll(snap.id);
27
+ });
28
+ }
29
+ /**
30
+ * Get information about a given WebSocket connection with an ID.
31
+ *
32
+ * @param snapId - The Snap ID.
33
+ * @param id - The identifier for the WebSocket connection.
34
+ * @returns Information abou the WebSocket connection.
35
+ * @throws If the WebSocket connection cannot be found.
36
+ */
37
+ #get(snapId, id) {
38
+ const socket = this.#sockets.get(id);
39
+ assert(socket && socket.snapId === snapId, `Socket with ID "${id}" not found.`);
40
+ return socket;
41
+ }
42
+ /**
43
+ * Check whether a given Snap ID already has an open connection for a URL and protocol.
44
+ *
45
+ * @param snapId - The Snap ID.
46
+ * @param url - The URL.
47
+ * @param protocols - A protocols parameter.
48
+ * @returns True if a matching connection already exists, otherwise false.
49
+ */
50
+ #exists(snapId, url, protocols) {
51
+ return this.#getAll(snapId).some((socket) => socket.url === url && isEqual(socket.protocols, protocols));
52
+ }
53
+ /**
54
+ * Handle sending a specific WebSocketEvent to a Snap.
55
+ *
56
+ * @param snapId - The Snap ID.
57
+ * @param event - The WebSocketEvent.
58
+ */
59
+ #handleEvent(snapId, event) {
60
+ this.#messenger
61
+ .call('SnapController:handleRequest', {
62
+ origin: METAMASK_ORIGIN,
63
+ snapId,
64
+ handler: HandlerType.OnWebSocketEvent,
65
+ request: { method: '', params: { event } },
66
+ })
67
+ .catch((error) => {
68
+ logError(`An error occurred while handling a WebSocket message for Snap "${snapId}":`, error);
69
+ });
70
+ }
71
+ /**
72
+ * Open a WebSocket connection.
73
+ *
74
+ * @param snapId - The Snap ID.
75
+ * @param url - The URL for the WebSocket connection.
76
+ * @param protocols - An optional parameter for protocols.
77
+ * @returns The identifier for the opened connection.
78
+ * @throws If the connection fails.
79
+ */
80
+ async #open(snapId, url, protocols = []) {
81
+ assert(!this.#exists(snapId, url, protocols), `An open WebSocket connection to ${url} already exists.`);
82
+ const parsedUrl = new URL(url);
83
+ const { origin } = parsedUrl;
84
+ const id = nanoid();
85
+ // eslint-disable-next-line no-restricted-globals
86
+ const socket = new WebSocket(url, protocols);
87
+ socket.binaryType = 'arraybuffer';
88
+ const { promise, resolve, reject } = createDeferredPromise();
89
+ socket.addEventListener('open', () => {
90
+ resolve();
91
+ this.#handleEvent(snapId, {
92
+ type: 'open',
93
+ id,
94
+ origin,
95
+ });
96
+ });
97
+ socket.addEventListener('close', (event) => {
98
+ this.#handleEvent(snapId, {
99
+ type: 'close',
100
+ id,
101
+ origin,
102
+ code: event.code,
103
+ reason: event.reason,
104
+ // wasClean is not available on mobile.
105
+ wasClean: event.wasClean ?? null,
106
+ });
107
+ });
108
+ const errorListener = () => {
109
+ reject(rpcErrors.resourceUnavailable('An error occurred while opening the WebSocket.'));
110
+ };
111
+ socket.addEventListener('error', errorListener);
112
+ socket.addEventListener('message', (event) => {
113
+ const isText = typeof event.data === 'string';
114
+ const data = isText
115
+ ? { type: 'text', message: event.data }
116
+ : {
117
+ type: 'binary',
118
+ // We request that the WebSocket gives us an array buffer.
119
+ message: Array.from(new Uint8Array(event.data)),
120
+ };
121
+ this.#handleEvent(snapId, {
122
+ type: 'message',
123
+ id,
124
+ origin,
125
+ data,
126
+ });
127
+ });
128
+ this.#sockets.set(id, {
129
+ id,
130
+ snapId,
131
+ url,
132
+ protocols,
133
+ socket,
134
+ openPromise: promise,
135
+ });
136
+ await promise;
137
+ socket.removeEventListener('error', errorListener);
138
+ return id;
139
+ }
140
+ /**
141
+ * Close a given WebSocket connection.
142
+ *
143
+ * @param snapId - The Snap ID.
144
+ * @param id - The identifier for the WebSocket connection.
145
+ */
146
+ #close(snapId, id) {
147
+ const { socket } = this.#get(snapId, id);
148
+ socket.close();
149
+ this.#sockets.delete(id);
150
+ }
151
+ /**
152
+ * Close all open connections for a given Snap ID.
153
+ *
154
+ * @param snapId - The Snap ID.
155
+ */
156
+ #closeAll(snapId) {
157
+ for (const socket of this.#getAll(snapId)) {
158
+ this.#close(snapId, socket.id);
159
+ }
160
+ }
161
+ /**
162
+ * Send a message from a given Snap ID to a WebSocket connection.
163
+ *
164
+ * @param snapId - The Snap ID.
165
+ * @param id - The identifier for the WebSocket connection.
166
+ * @param data - The message to send.
167
+ */
168
+ async #sendMessage(snapId, id, data) {
169
+ const { socket, openPromise } = this.#get(snapId, id);
170
+ await openPromise;
171
+ const wrappedData = Array.isArray(data) ? new Uint8Array(data) : data;
172
+ socket.send(wrappedData);
173
+ }
174
+ /**
175
+ * Get a list of all open WebSocket connections for a Snap ID.
176
+ *
177
+ * @param snapId - The Snap ID.
178
+ * @returns A list of WebSocket connections.
179
+ */
180
+ #getAll(snapId) {
181
+ return [...this.#sockets.values()]
182
+ .filter((socket) => socket.snapId === snapId)
183
+ .map((socket) => ({
184
+ id: socket.id,
185
+ url: socket.url,
186
+ protocols: socket.protocols,
187
+ }));
188
+ }
189
+ }
190
+ //# sourceMappingURL=WebSocketService.mjs.map