@streamr/cli-tools 0.0.1-tatum.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 (142) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +6 -0
  3. package/LICENSE +661 -0
  4. package/OLD_CHANGELOG.md +141 -0
  5. package/README.md +225 -0
  6. package/bin/streamr-governance-vote.ts +51 -0
  7. package/bin/streamr-governance.ts +10 -0
  8. package/bin/streamr-mock-data-generate.ts +40 -0
  9. package/bin/streamr-mock-data.ts +10 -0
  10. package/bin/streamr-storage-node-add-stream.ts +12 -0
  11. package/bin/streamr-storage-node-list-streams.ts +20 -0
  12. package/bin/streamr-storage-node-list.ts +22 -0
  13. package/bin/streamr-storage-node-remove-stream.ts +12 -0
  14. package/bin/streamr-storage-node.ts +13 -0
  15. package/bin/streamr-stream-create.ts +29 -0
  16. package/bin/streamr-stream-grant-permission.ts +9 -0
  17. package/bin/streamr-stream-publish.ts +66 -0
  18. package/bin/streamr-stream-resend-from.ts +32 -0
  19. package/bin/streamr-stream-resend-last.ts +30 -0
  20. package/bin/streamr-stream-resend-range.ts +38 -0
  21. package/bin/streamr-stream-resend.ts +11 -0
  22. package/bin/streamr-stream-revoke-permission.ts +9 -0
  23. package/bin/streamr-stream-search.ts +61 -0
  24. package/bin/streamr-stream-show.ts +28 -0
  25. package/bin/streamr-stream-subscribe.ts +40 -0
  26. package/bin/streamr-stream.ts +17 -0
  27. package/bin/streamr-wallet-whoami.ts +10 -0
  28. package/bin/streamr-wallet.ts +10 -0
  29. package/bin/streamr.ts +14 -0
  30. package/dist/bin/streamr-governance-vote.d.ts +2 -0
  31. package/dist/bin/streamr-governance-vote.js +52 -0
  32. package/dist/bin/streamr-governance-vote.js.map +1 -0
  33. package/dist/bin/streamr-governance.d.ts +2 -0
  34. package/dist/bin/streamr-governance.js +15 -0
  35. package/dist/bin/streamr-governance.js.map +1 -0
  36. package/dist/bin/streamr-mock-data-generate.d.ts +2 -0
  37. package/dist/bin/streamr-mock-data-generate.js +40 -0
  38. package/dist/bin/streamr-mock-data-generate.js.map +1 -0
  39. package/dist/bin/streamr-mock-data.d.ts +2 -0
  40. package/dist/bin/streamr-mock-data.js +15 -0
  41. package/dist/bin/streamr-mock-data.js.map +1 -0
  42. package/dist/bin/streamr-storage-node-add-stream.d.ts +2 -0
  43. package/dist/bin/streamr-storage-node-add-stream.js +13 -0
  44. package/dist/bin/streamr-storage-node-add-stream.js.map +1 -0
  45. package/dist/bin/streamr-storage-node-list-streams.d.ts +2 -0
  46. package/dist/bin/streamr-storage-node-list-streams.js +24 -0
  47. package/dist/bin/streamr-storage-node-list-streams.js.map +1 -0
  48. package/dist/bin/streamr-storage-node-list.d.ts +2 -0
  49. package/dist/bin/streamr-storage-node-list.js +22 -0
  50. package/dist/bin/streamr-storage-node-list.js.map +1 -0
  51. package/dist/bin/streamr-storage-node-remove-stream.d.ts +2 -0
  52. package/dist/bin/streamr-storage-node-remove-stream.js +13 -0
  53. package/dist/bin/streamr-storage-node-remove-stream.js.map +1 -0
  54. package/dist/bin/streamr-storage-node.d.ts +2 -0
  55. package/dist/bin/streamr-storage-node.js +18 -0
  56. package/dist/bin/streamr-storage-node.js.map +1 -0
  57. package/dist/bin/streamr-stream-create.d.ts +2 -0
  58. package/dist/bin/streamr-stream-create.js +23 -0
  59. package/dist/bin/streamr-stream-create.js.map +1 -0
  60. package/dist/bin/streamr-stream-grant-permission.d.ts +2 -0
  61. package/dist/bin/streamr-stream-grant-permission.js +7 -0
  62. package/dist/bin/streamr-stream-grant-permission.js.map +1 -0
  63. package/dist/bin/streamr-stream-publish.d.ts +2 -0
  64. package/dist/bin/streamr-stream-publish.js +59 -0
  65. package/dist/bin/streamr-stream-publish.js.map +1 -0
  66. package/dist/bin/streamr-stream-resend-from.d.ts +2 -0
  67. package/dist/bin/streamr-stream-resend-from.js +27 -0
  68. package/dist/bin/streamr-stream-resend-from.js.map +1 -0
  69. package/dist/bin/streamr-stream-resend-last.d.ts +2 -0
  70. package/dist/bin/streamr-stream-resend-last.js +26 -0
  71. package/dist/bin/streamr-stream-resend-last.js.map +1 -0
  72. package/dist/bin/streamr-stream-resend-range.d.ts +2 -0
  73. package/dist/bin/streamr-stream-resend-range.js +33 -0
  74. package/dist/bin/streamr-stream-resend-range.js.map +1 -0
  75. package/dist/bin/streamr-stream-resend.d.ts +2 -0
  76. package/dist/bin/streamr-stream-resend.js +13 -0
  77. package/dist/bin/streamr-stream-resend.js.map +1 -0
  78. package/dist/bin/streamr-stream-revoke-permission.d.ts +2 -0
  79. package/dist/bin/streamr-stream-revoke-permission.js +7 -0
  80. package/dist/bin/streamr-stream-revoke-permission.js.map +1 -0
  81. package/dist/bin/streamr-stream-search.d.ts +2 -0
  82. package/dist/bin/streamr-stream-search.js +42 -0
  83. package/dist/bin/streamr-stream-search.js.map +1 -0
  84. package/dist/bin/streamr-stream-show.d.ts +2 -0
  85. package/dist/bin/streamr-stream-show.js +25 -0
  86. package/dist/bin/streamr-stream-show.js.map +1 -0
  87. package/dist/bin/streamr-stream-subscribe.d.ts +2 -0
  88. package/dist/bin/streamr-stream-subscribe.js +37 -0
  89. package/dist/bin/streamr-stream-subscribe.js.map +1 -0
  90. package/dist/bin/streamr-stream.d.ts +2 -0
  91. package/dist/bin/streamr-stream.js +22 -0
  92. package/dist/bin/streamr-stream.js.map +1 -0
  93. package/dist/bin/streamr-wallet-whoami.d.ts +2 -0
  94. package/dist/bin/streamr-wallet-whoami.js +11 -0
  95. package/dist/bin/streamr-wallet-whoami.js.map +1 -0
  96. package/dist/bin/streamr-wallet.d.ts +2 -0
  97. package/dist/bin/streamr-wallet.js +15 -0
  98. package/dist/bin/streamr-wallet.js.map +1 -0
  99. package/dist/bin/streamr.d.ts +2 -0
  100. package/dist/bin/streamr.js +19 -0
  101. package/dist/bin/streamr.js.map +1 -0
  102. package/dist/package.json +45 -0
  103. package/dist/src/client.d.ts +4 -0
  104. package/dist/src/client.js +36 -0
  105. package/dist/src/client.js.map +1 -0
  106. package/dist/src/command.d.ts +13 -0
  107. package/dist/src/command.js +45 -0
  108. package/dist/src/command.js.map +1 -0
  109. package/dist/src/common.d.ts +6 -0
  110. package/dist/src/common.js +32 -0
  111. package/dist/src/common.js.map +1 -0
  112. package/dist/src/config.d.ts +6 -0
  113. package/dist/src/config.js +58 -0
  114. package/dist/src/config.js.map +1 -0
  115. package/dist/src/logLevel.d.ts +1 -0
  116. package/dist/src/logLevel.js +11 -0
  117. package/dist/src/logLevel.js.map +1 -0
  118. package/dist/src/permission.d.ts +5 -0
  119. package/dist/src/permission.js +53 -0
  120. package/dist/src/permission.js.map +1 -0
  121. package/dist/src/resend.d.ts +3 -0
  122. package/dist/src/resend.js +32 -0
  123. package/dist/src/resend.js.map +1 -0
  124. package/package.json +45 -0
  125. package/src/client.ts +35 -0
  126. package/src/command.ts +51 -0
  127. package/src/common.ts +25 -0
  128. package/src/config.ts +56 -0
  129. package/src/logLevel.ts +9 -0
  130. package/src/permission.ts +53 -0
  131. package/src/resend.ts +37 -0
  132. package/test/mock-data.test.ts +19 -0
  133. package/test/storage-node.test.ts +32 -0
  134. package/test/stream-create.test.ts +26 -0
  135. package/test/stream-permission.test.ts +29 -0
  136. package/test/stream-publish-subscribe.test.ts +86 -0
  137. package/test/stream-resend.test.ts +66 -0
  138. package/test/stream-search.test.ts +24 -0
  139. package/test/stream-show.test.ts +31 -0
  140. package/test/utils.ts +85 -0
  141. package/test/wallet.test.ts +11 -0
  142. package/tsconfig.json +16 -0
@@ -0,0 +1,13 @@
1
+ import commander, { Command } from 'commander';
2
+ import { StreamrClientConfig } from 'streamr-client';
3
+ export interface Options {
4
+ privateKey?: string;
5
+ config?: string;
6
+ dev: boolean;
7
+ }
8
+ export declare const createCommand: () => commander.Command;
9
+ export interface CommandOpts {
10
+ autoDestroyClient?: boolean;
11
+ clientOptionsFactory?: (options: any) => StreamrClientConfig;
12
+ }
13
+ export declare const createClientCommand: (action: (...handleArgs: any[]) => Promise<void>, opts?: CommandOpts) => commander.Command;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createClientCommand = exports.createCommand = void 0;
7
+ const commander_1 = require("commander");
8
+ const package_json_1 = __importDefault(require("../package.json"));
9
+ const client_1 = require("./client");
10
+ const createCommand = () => {
11
+ return new commander_1.Command()
12
+ .version(package_json_1.default.version)
13
+ .showHelpAfterError()
14
+ .allowExcessArguments(false);
15
+ };
16
+ exports.createCommand = createCommand;
17
+ const createClientCommand = (action, opts = {
18
+ autoDestroyClient: true,
19
+ clientOptionsFactory: () => ({})
20
+ }) => {
21
+ return (0, exports.createCommand)()
22
+ .option('--private-key <key>', 'use an Ethereum private key to authenticate')
23
+ .option('--config <file>', 'read connection and authentication settings from a config file')
24
+ .option('--dev', 'use pre-defined development environment', false)
25
+ .action(async (...args) => {
26
+ const commandOptions = args[args.length - 1].opts();
27
+ try {
28
+ const client = (0, client_1.createClient)(commandOptions, opts.clientOptionsFactory(commandOptions));
29
+ try {
30
+ await action(...[client].concat(args));
31
+ }
32
+ finally {
33
+ if (opts.autoDestroyClient) {
34
+ await client.destroy();
35
+ }
36
+ }
37
+ }
38
+ catch (e) {
39
+ console.error(e);
40
+ process.exit(1);
41
+ }
42
+ });
43
+ };
44
+ exports.createClientCommand = createClientCommand;
45
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/command.ts"],"names":[],"mappings":";;;;;;AAAA,yCAA8C;AAE9C,mEAAiC;AACjC,qCAAuC;AAQhC,MAAM,aAAa,GAAG,GAAsB,EAAE;IACjD,OAAO,IAAI,mBAAO,EAAE;SACf,OAAO,CAAC,sBAAG,CAAC,OAAO,CAAC;SACpB,kBAAkB,EAAE;SACpB,oBAAoB,CAAC,KAAK,CAAC,CAAA;AACpC,CAAC,CAAA;AALY,QAAA,aAAa,iBAKzB;AAOM,MAAM,mBAAmB,GAAG,CAC/B,MAA+C,EAC/C,OAAoB;IAChB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;CACnC,EACgB,EAAE;IACnB,OAAO,IAAA,qBAAa,GAAE;SACjB,MAAM,CAAC,qBAAqB,EAAE,6CAA6C,CAAC;SAC5E,MAAM,CAAC,iBAAiB,EAAE,gEAAgE,CAAC;SAC3F,MAAM,CAAC,OAAO,EAAE,yCAAyC,EAAE,KAAK,CAAC;SACjE,MAAM,CAAC,KAAK,EAAE,GAAG,IAAW,EAAE,EAAE;QAC7B,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACnD,IAAI;YACA,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,cAAc,EAAE,IAAI,CAAC,oBAAqB,CAAC,cAAc,CAAC,CAAC,CAAA;YACvF,IAAI;gBACA,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAA;aACzC;oBAAS;gBACN,IAAI,IAAI,CAAC,iBAAiB,EAAE;oBACxB,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;iBACzB;aACJ;SACJ;QAAC,OAAO,CAAM,EAAE;YACb,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;SAClB;IACL,CAAC,CAAC,CAAA;AACV,CAAC,CAAA;AA3BY,QAAA,mBAAmB,uBA2B/B"}
@@ -0,0 +1,6 @@
1
+ export declare enum OptionType {
2
+ FLAG = 0,
3
+ ARGUMENT = 1
4
+ }
5
+ export declare const getOptionType: (value: string | boolean) => OptionType | never;
6
+ export declare function createFnParseInt(name: string): (s: string) => number;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFnParseInt = exports.getOptionType = exports.OptionType = void 0;
4
+ var OptionType;
5
+ (function (OptionType) {
6
+ OptionType[OptionType["FLAG"] = 0] = "FLAG";
7
+ OptionType[OptionType["ARGUMENT"] = 1] = "ARGUMENT"; // e.g. "--private-key 0x1234"
8
+ })(OptionType || (exports.OptionType = OptionType = {}));
9
+ const getOptionType = (value) => {
10
+ if (typeof value === 'boolean') {
11
+ return OptionType.FLAG;
12
+ }
13
+ else if (typeof value === 'string') {
14
+ return OptionType.ARGUMENT;
15
+ }
16
+ else {
17
+ throw new Error(`unknown option type (value: ${value})`);
18
+ }
19
+ };
20
+ exports.getOptionType = getOptionType;
21
+ function createFnParseInt(name) {
22
+ return (str) => {
23
+ const n = parseInt(str, 10);
24
+ if (isNaN(n)) {
25
+ console.error(`${name} must be an integer (was "${str}")`);
26
+ process.exit(1);
27
+ }
28
+ return n;
29
+ };
30
+ }
31
+ exports.createFnParseInt = createFnParseInt;
32
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/common.ts"],"names":[],"mappings":";;;AAAA,IAAY,UAGX;AAHD,WAAY,UAAU;IAClB,2CAAI,CAAA;IACJ,mDAAQ,CAAA,CAAE,8BAA8B;AAC5C,CAAC,EAHW,UAAU,0BAAV,UAAU,QAGrB;AAEM,MAAM,aAAa,GAAG,CAAC,KAAuB,EAAsB,EAAE;IACzE,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE;QAC5B,OAAO,UAAU,CAAC,IAAI,CAAA;KACzB;SAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAClC,OAAO,UAAU,CAAC,QAAQ,CAAA;KAC7B;SAAM;QACH,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,GAAG,CAAC,CAAA;KAC3D;AACL,CAAC,CAAA;AARY,QAAA,aAAa,iBAQzB;AAED,SAAgB,gBAAgB,CAAC,IAAY;IACzC,OAAO,CAAC,GAAW,EAAE,EAAE;QACnB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QAC3B,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE;YACV,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,6BAA6B,GAAG,IAAI,CAAC,CAAA;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;SAClB;QACD,OAAO,CAAC,CAAA;IACZ,CAAC,CAAA;AACL,CAAC;AATD,4CASC"}
@@ -0,0 +1,6 @@
1
+ import { StreamrClientConfig } from 'streamr-client';
2
+ interface Config {
3
+ client: StreamrClientConfig;
4
+ }
5
+ export declare const getConfig: (id?: string) => Config | undefined;
6
+ export {};
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getConfig = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const fs_1 = require("fs");
10
+ /*
11
+ * Validate that the config contains at least one root level element: the "client" block.
12
+ * The values of the "client" blocks are validated by StreamrClient when the configuration
13
+ * is used.
14
+ *
15
+ * We don't check other root level elements. It is ok to use a Broker config file as
16
+ * a cli-tools config file. In that case the file contains e.g. "plugins" block,
17
+ * but cli-tools can just ignore that block.
18
+ */
19
+ const validateConfig = (config, fileName) => {
20
+ const CLIENT_CONFIG_BLOCK = 'client';
21
+ if (config[CLIENT_CONFIG_BLOCK] === undefined) {
22
+ throw new Error(`Missing root element "${CLIENT_CONFIG_BLOCK}" in ${fileName}`);
23
+ }
24
+ };
25
+ const tryReadConfigFile = (fileName) => {
26
+ let content;
27
+ try {
28
+ content = (0, fs_1.readFileSync)(fileName, 'utf8');
29
+ }
30
+ catch (e) {
31
+ return undefined;
32
+ }
33
+ const json = JSON.parse(content);
34
+ validateConfig(json, fileName);
35
+ return json;
36
+ };
37
+ const getConfig = (id) => {
38
+ const CONFIG_DIRECTORY = path_1.default.join(os_1.default.homedir(), '.streamr', 'config');
39
+ if (id !== undefined) {
40
+ const fileNames = [
41
+ id,
42
+ path_1.default.join(CONFIG_DIRECTORY, `${id}.json`),
43
+ ];
44
+ for (const fileName of fileNames) {
45
+ const content = tryReadConfigFile(fileName);
46
+ if (content !== undefined) {
47
+ return content;
48
+ }
49
+ }
50
+ throw new Error('Config file not found');
51
+ }
52
+ else {
53
+ const fileName = path_1.default.join(CONFIG_DIRECTORY, `default.json`);
54
+ return tryReadConfigFile(fileName);
55
+ }
56
+ };
57
+ exports.getConfig = getConfig;
58
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":";;;;;;AAAA,gDAAuB;AACvB,4CAAmB;AACnB,2BAAiC;AAOjC;;;;;;;;GAQG;AACH,MAAM,cAAc,GAAG,CAAC,MAAW,EAAE,QAAgB,EAAgB,EAAE;IACnE,MAAM,mBAAmB,GAAG,QAAQ,CAAA;IACpC,IAAI,MAAM,CAAC,mBAAmB,CAAC,KAAK,SAAS,EAAE;QAC3C,MAAM,IAAI,KAAK,CAAC,yBAAyB,mBAAmB,QAAQ,QAAQ,EAAE,CAAC,CAAA;KAClF;AACL,CAAC,CAAA;AAED,MAAM,iBAAiB,GAAG,CAAC,QAAgB,EAA8B,EAAE;IACvE,IAAI,OAAO,CAAA;IACX,IAAI;QACA,OAAO,GAAG,IAAA,iBAAY,EAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;KAC3C;IAAC,OAAO,CAAM,EAAE;QACb,OAAO,SAAS,CAAA;KACnB;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAChC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC9B,OAAO,IAAI,CAAA;AACf,CAAC,CAAA;AAEM,MAAM,SAAS,GAAG,CAAC,EAAW,EAAsB,EAAE;IACzD,MAAM,gBAAgB,GAAG,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;IACtE,IAAI,EAAE,KAAK,SAAS,EAAE;QAClB,MAAM,SAAS,GAAG;YACd,EAAE;YACF,cAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,OAAO,CAAC;SAC5C,CAAA;QACD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;YAC9B,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;YAC3C,IAAI,OAAO,KAAK,SAAS,EAAE;gBACvB,OAAO,OAAO,CAAA;aACjB;SACJ;QACD,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;KAC3C;SAAM;QACH,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAA;QAC5D,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAA;KACrC;AACL,CAAC,CAAA;AAlBY,QAAA,SAAS,aAkBrB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /*
3
+ * Minimal logging for NetworkNode and other users of Logger.ts in the network package.
4
+ * This file needs to be imported before any of the network package classes
5
+ * so that the environment variable is updated before any Logger instances are created.
6
+ * The import is needed for the files where network packages are used (typically
7
+ * the files which call createClientCommand()).
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ process.env.LOG_LEVEL = process.env.LOG_LEVEL ?? 'error';
11
+ //# sourceMappingURL=logLevel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logLevel.js","sourceRoot":"","sources":["../../src/logLevel.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAEH,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { PermissionAssignment, Stream, StreamPermission } from 'streamr-client';
2
+ export declare const PERMISSIONS: Map<string, StreamPermission>;
3
+ export declare const getPermission: (id: string) => StreamPermission | never;
4
+ export declare const getPermissionId: (permission: StreamPermission) => string;
5
+ export declare const runModifyPermissionsCommand: (modify: (stream: Stream, assignment: PermissionAssignment) => Promise<void>, modification: string) => void;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runModifyPermissionsCommand = exports.getPermissionId = exports.getPermission = exports.PERMISSIONS = void 0;
4
+ const commander_1 = require("commander");
5
+ const streamr_client_1 = require("streamr-client");
6
+ const command_1 = require("./command");
7
+ const PUBLIC_USER_ID = 'public';
8
+ exports.PERMISSIONS = new Map([
9
+ ['subscribe', streamr_client_1.StreamPermission.SUBSCRIBE],
10
+ ['publish', streamr_client_1.StreamPermission.PUBLISH],
11
+ ['edit', streamr_client_1.StreamPermission.EDIT],
12
+ ['delete', streamr_client_1.StreamPermission.DELETE],
13
+ ['grant', streamr_client_1.StreamPermission.GRANT]
14
+ ]);
15
+ const getPermission = (id) => {
16
+ const result = exports.PERMISSIONS.get(id);
17
+ if (result === undefined) {
18
+ throw new Error(`unknown permission: ${id}`);
19
+ }
20
+ return result;
21
+ };
22
+ exports.getPermission = getPermission;
23
+ const getPermissionId = (permission) => {
24
+ return Array.from(exports.PERMISSIONS.entries()).find(([_id, p]) => p === permission)[0];
25
+ };
26
+ exports.getPermissionId = getPermissionId;
27
+ const runModifyPermissionsCommand = (modify, modification) => {
28
+ (0, command_1.createClientCommand)(async (client, streamId, user, permissionIds) => {
29
+ const stream = await client.getStream(streamId);
30
+ const permissions = permissionIds.map((permissionId) => (0, exports.getPermission)(permissionId));
31
+ let assignment;
32
+ if (user === PUBLIC_USER_ID) {
33
+ assignment = {
34
+ permissions,
35
+ public: true
36
+ };
37
+ }
38
+ else {
39
+ assignment = {
40
+ permissions,
41
+ user
42
+ };
43
+ }
44
+ await modify(stream, assignment);
45
+ })
46
+ .addArgument(new commander_1.Argument('<streamId>'))
47
+ .addArgument(new commander_1.Argument('<user>'))
48
+ .addArgument(new commander_1.Argument('<permissions...>').choices(Array.from(exports.PERMISSIONS.keys())))
49
+ .description(`${modification} permission: use keyword "public" as a user to ${modification} a public permission`)
50
+ .parseAsync(process.argv);
51
+ };
52
+ exports.runModifyPermissionsCommand = runModifyPermissionsCommand;
53
+ //# sourceMappingURL=permission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission.js","sourceRoot":"","sources":["../../src/permission.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,mDAA8F;AAC9F,uCAA+C;AAE/C,MAAM,cAAc,GAAG,QAAQ,CAAA;AAElB,QAAA,WAAW,GAAG,IAAI,GAAG,CAA2B;IACzD,CAAC,WAAW,EAAE,iCAAgB,CAAC,SAAS,CAAC;IACzC,CAAC,SAAS,EAAE,iCAAgB,CAAC,OAAO,CAAC;IACrC,CAAC,MAAM,EAAE,iCAAgB,CAAC,IAAI,CAAC;IAC/B,CAAC,QAAQ,EAAE,iCAAgB,CAAC,MAAM,CAAC;IACnC,CAAC,OAAO,EAAE,iCAAgB,CAAC,KAAK,CAAC;CACpC,CAAC,CAAA;AAEK,MAAM,aAAa,GAAG,CAAC,EAAU,EAA4B,EAAE;IAClE,MAAM,MAAM,GAAG,mBAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAClC,IAAI,MAAM,KAAK,SAAS,EAAE;QACtB,MAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAA;KAC/C;IACD,OAAO,MAAM,CAAA;AACjB,CAAC,CAAA;AANY,QAAA,aAAa,iBAMzB;AAEM,MAAM,eAAe,GAAG,CAAC,UAA4B,EAAU,EAAE;IACpE,OAAO,KAAK,CAAC,IAAI,CAAC,mBAAW,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAE,CAAC,CAAC,CAAC,CAAA;AACrF,CAAC,CAAA;AAFY,QAAA,eAAe,mBAE3B;AAEM,MAAM,2BAA2B,GAAG,CACvC,MAA2E,EAC3E,YAAoB,EAChB,EAAE;IACN,IAAA,6BAAmB,EAAC,KAAK,EAAE,MAAqB,EAAE,QAAgB,EAAE,IAAY,EAAE,aAAuB,EAAE,EAAE;QACzG,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QAC/C,MAAM,WAAW,GAAuB,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,IAAA,qBAAa,EAAC,YAAY,CAAC,CAAC,CAAA;QACxG,IAAI,UAAgC,CAAA;QACpC,IAAI,IAAI,KAAK,cAAc,EAAE;YACzB,UAAU,GAAG;gBACT,WAAW;gBACX,MAAM,EAAE,IAAI;aACf,CAAA;SACJ;aAAM;YACH,UAAU,GAAG;gBACT,WAAW;gBACX,IAAI;aACP,CAAA;SACJ;QACD,MAAM,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACpC,CAAC,CAAC;SACG,WAAW,CAAC,IAAI,oBAAQ,CAAC,YAAY,CAAC,CAAC;SACvC,WAAW,CAAC,IAAI,oBAAQ,CAAC,QAAQ,CAAC,CAAC;SACnC,WAAW,CAAC,IAAI,oBAAQ,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;SACrF,WAAW,CAAC,GAAG,YAAY,kDAAkD,YAAY,sBAAsB,CAAC;SAChH,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AACjC,CAAC,CAAA;AA1BY,QAAA,2BAA2B,+BA0BvC"}
@@ -0,0 +1,3 @@
1
+ import { StreamrClient, ResendOptions } from 'streamr-client';
2
+ export declare const assertBothOrNoneDefined: <T extends object>(option1: keyof T, option2: keyof T, errorMessage: string, commandOptions: T) => void | never;
3
+ export declare const resend: (streamId: string, resendOpts: ResendOptions, client: StreamrClient, subscribe: boolean) => Promise<void>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resend = exports.assertBothOrNoneDefined = void 0;
4
+ const assertBothOrNoneDefined = (option1, option2, errorMessage, commandOptions) => {
5
+ if ((option1 in commandOptions && !(option2 in commandOptions)) || (option2 in commandOptions && !(option1 in commandOptions))) {
6
+ console.error(`option ${errorMessage}`);
7
+ process.exit(1);
8
+ }
9
+ };
10
+ exports.assertBothOrNoneDefined = assertBothOrNoneDefined;
11
+ const resend = async (streamId, resendOpts, client, subscribe) => {
12
+ try {
13
+ const handler = (message) => {
14
+ console.info(JSON.stringify(message));
15
+ };
16
+ if (subscribe) {
17
+ await client.subscribe({
18
+ stream: streamId,
19
+ resend: resendOpts
20
+ }, handler);
21
+ }
22
+ else {
23
+ await client.resend(streamId, resendOpts, handler);
24
+ }
25
+ }
26
+ catch (err) {
27
+ console.error(err.message ? err.message : err);
28
+ process.exit(1);
29
+ }
30
+ };
31
+ exports.resend = resend;
32
+ //# sourceMappingURL=resend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resend.js","sourceRoot":"","sources":["../../src/resend.ts"],"names":[],"mappings":";;;AAEO,MAAM,uBAAuB,GAAG,CACnC,OAAgB,EAChB,OAAgB,EAChB,YAAoB,EACpB,cAAiB,EACL,EAAE;IACd,IAAI,CAAC,OAAO,IAAI,cAAc,IAAI,CAAC,CAAC,OAAO,IAAI,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,cAAc,IAAI,CAAC,CAAC,OAAO,IAAI,cAAc,CAAC,CAAC,EAAE;QAC5H,OAAO,CAAC,KAAK,CAAC,UAAU,YAAY,EAAE,CAAC,CAAA;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAClB;AACL,CAAC,CAAA;AAVY,QAAA,uBAAuB,2BAUnC;AAEM,MAAM,MAAM,GAAG,KAAK,EACvB,QAAgB,EAChB,UAAyB,EACzB,MAAqB,EACrB,SAAkB,EACL,EAAE;IACf,IAAI;QACA,MAAM,OAAO,GAAG,CAAC,OAAY,EAAE,EAAE;YAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;QACzC,CAAC,CAAA;QACD,IAAI,SAAS,EAAE;YACX,MAAM,MAAM,CAAC,SAAS,CAAC;gBACnB,MAAM,EAAE,QAAQ;gBAChB,MAAM,EAAE,UAAU;aACrB,EAAE,OAAO,CAAC,CAAA;SACd;aAAM;YACH,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAA;SACrD;KACJ;IAAC,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAClB;AACL,CAAC,CAAA;AAtBY,QAAA,MAAM,UAsBlB"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@streamr/cli-tools",
3
+ "version": "0.0.1-tatum.0",
4
+ "description": "Command line tools for Streamr",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/streamr-dev/network.git",
8
+ "directory": "packages/cli-tools"
9
+ },
10
+ "bin": {
11
+ "streamr": "dist/bin/streamr.js"
12
+ },
13
+ "scripts": {
14
+ "build": "tsc -b tsconfig.json",
15
+ "check": "tsc -p ./tsconfig.json --noEmit",
16
+ "clean": "jest --clearCache || true; rm -rf dist *.tsbuildinfo node_modules/.cache || true",
17
+ "eslint": "eslint --cache --cache-location=node_modules/.cache/.eslintcache/ '*/**/*.{js,ts}'",
18
+ "test": "npm run build && jest --forceExit"
19
+ },
20
+ "keywords": [
21
+ "streamr",
22
+ "cli",
23
+ "tool",
24
+ "utility"
25
+ ],
26
+ "author": "Streamr Network AG <contact@streamr.com>",
27
+ "license": "AGPL-3.0",
28
+ "dependencies": {
29
+ "@ethersproject/wallet": "^5.5.0",
30
+ "@snapshot-labs/snapshot.js": "^0.5.4",
31
+ "@streamr/utils": "0.0.1-tatum.0",
32
+ "commander": "^11.0.0",
33
+ "easy-table": "^1.1.1",
34
+ "event-stream": "^4.0.1",
35
+ "lodash": "^4.17.21",
36
+ "streamr-client": "0.0.1-tatum.0"
37
+ },
38
+ "devDependencies": {
39
+ "@streamr/test-utils": "0.0.1-tatum.0",
40
+ "@types/event-stream": "^4.0.0",
41
+ "@types/lodash": "^4.14.197",
42
+ "@types/merge2": "^1.4.0",
43
+ "merge2": "^1.4.1"
44
+ }
45
+ }
package/src/client.ts ADDED
@@ -0,0 +1,35 @@
1
+ import omit from 'lodash/omit'
2
+ import merge from 'lodash/merge'
3
+ import { StreamrClientConfig, StreamrClient, CONFIG_TEST } from 'streamr-client'
4
+ import { Options } from './command'
5
+ import { getConfig } from './config'
6
+
7
+ export const getClientConfig = (commandOptions: Options, overridenOptions: StreamrClientConfig = {}): StreamrClientConfig => {
8
+ const environmentOptions = commandOptions.dev ? omit(CONFIG_TEST, 'auth') : undefined
9
+ const configFileJson = getConfig(commandOptions.config)?.client
10
+ const authenticationOptions = (commandOptions.privateKey !== undefined) ? { auth: { privateKey: commandOptions.privateKey } } : undefined
11
+ return merge(
12
+ environmentOptions,
13
+ configFileJson,
14
+ authenticationOptions,
15
+ overridenOptions
16
+ )
17
+ }
18
+
19
+ const addInterruptHandler = (client: StreamrClient) => {
20
+ process.on('SIGINT', async () => {
21
+ try {
22
+ await client.destroy()
23
+ } catch {
24
+ // no-op
25
+ }
26
+ process.exit()
27
+ })
28
+ }
29
+
30
+ export const createClient = (commandOptions: Options, overridenOptions: StreamrClientConfig = {}): StreamrClient => {
31
+ const config = getClientConfig(commandOptions, overridenOptions)
32
+ const client = new StreamrClient(config)
33
+ addInterruptHandler(client)
34
+ return client
35
+ }
package/src/command.ts ADDED
@@ -0,0 +1,51 @@
1
+ import commander, { Command } from 'commander'
2
+ import { StreamrClientConfig } from 'streamr-client'
3
+ import pkg from '../package.json'
4
+ import { createClient } from './client'
5
+
6
+ export interface Options {
7
+ privateKey?: string
8
+ config?: string
9
+ dev: boolean
10
+ }
11
+
12
+ export const createCommand = (): commander.Command => {
13
+ return new Command()
14
+ .version(pkg.version)
15
+ .showHelpAfterError()
16
+ .allowExcessArguments(false)
17
+ }
18
+
19
+ export interface CommandOpts {
20
+ autoDestroyClient?: boolean
21
+ clientOptionsFactory?: (options: any) => StreamrClientConfig
22
+ }
23
+
24
+ export const createClientCommand = (
25
+ action: (...handleArgs: any[]) => Promise<void>,
26
+ opts: CommandOpts = {
27
+ autoDestroyClient: true,
28
+ clientOptionsFactory: () => ({})
29
+ }
30
+ ): commander.Command => {
31
+ return createCommand()
32
+ .option('--private-key <key>', 'use an Ethereum private key to authenticate')
33
+ .option('--config <file>', 'read connection and authentication settings from a config file')
34
+ .option('--dev', 'use pre-defined development environment', false)
35
+ .action(async (...args: any[]) => {
36
+ const commandOptions = args[args.length - 1].opts()
37
+ try {
38
+ const client = createClient(commandOptions, opts.clientOptionsFactory!(commandOptions))
39
+ try {
40
+ await action(...[client].concat(args))
41
+ } finally {
42
+ if (opts.autoDestroyClient) {
43
+ await client.destroy()
44
+ }
45
+ }
46
+ } catch (e: any) {
47
+ console.error(e)
48
+ process.exit(1)
49
+ }
50
+ })
51
+ }
package/src/common.ts ADDED
@@ -0,0 +1,25 @@
1
+ export enum OptionType {
2
+ FLAG, // e.g. "--enable"
3
+ ARGUMENT // e.g. "--private-key 0x1234"
4
+ }
5
+
6
+ export const getOptionType = (value: string | boolean): OptionType | never => {
7
+ if (typeof value === 'boolean') {
8
+ return OptionType.FLAG
9
+ } else if (typeof value === 'string') {
10
+ return OptionType.ARGUMENT
11
+ } else {
12
+ throw new Error(`unknown option type (value: ${value})`)
13
+ }
14
+ }
15
+
16
+ export function createFnParseInt(name: string): (s: string) => number {
17
+ return (str: string) => {
18
+ const n = parseInt(str, 10)
19
+ if (isNaN(n)) {
20
+ console.error(`${name} must be an integer (was "${str}")`)
21
+ process.exit(1)
22
+ }
23
+ return n
24
+ }
25
+ }
package/src/config.ts ADDED
@@ -0,0 +1,56 @@
1
+ import path from 'path'
2
+ import os from 'os'
3
+ import { readFileSync } from 'fs'
4
+ import { StreamrClientConfig } from 'streamr-client'
5
+
6
+ interface Config {
7
+ client: StreamrClientConfig
8
+ }
9
+
10
+ /*
11
+ * Validate that the config contains at least one root level element: the "client" block.
12
+ * The values of the "client" blocks are validated by StreamrClient when the configuration
13
+ * is used.
14
+ *
15
+ * We don't check other root level elements. It is ok to use a Broker config file as
16
+ * a cli-tools config file. In that case the file contains e.g. "plugins" block,
17
+ * but cli-tools can just ignore that block.
18
+ */
19
+ const validateConfig = (config: any, fileName: string): void | never => {
20
+ const CLIENT_CONFIG_BLOCK = 'client'
21
+ if (config[CLIENT_CONFIG_BLOCK] === undefined) {
22
+ throw new Error(`Missing root element "${CLIENT_CONFIG_BLOCK}" in ${fileName}`)
23
+ }
24
+ }
25
+
26
+ const tryReadConfigFile = (fileName: string): Config | undefined | never => {
27
+ let content
28
+ try {
29
+ content = readFileSync(fileName, 'utf8')
30
+ } catch (e: any) {
31
+ return undefined
32
+ }
33
+ const json = JSON.parse(content)
34
+ validateConfig(json, fileName)
35
+ return json
36
+ }
37
+
38
+ export const getConfig = (id?: string): Config | undefined => {
39
+ const CONFIG_DIRECTORY = path.join(os.homedir(), '.streamr', 'config')
40
+ if (id !== undefined) {
41
+ const fileNames = [
42
+ id,
43
+ path.join(CONFIG_DIRECTORY, `${id}.json`),
44
+ ]
45
+ for (const fileName of fileNames) {
46
+ const content = tryReadConfigFile(fileName)
47
+ if (content !== undefined) {
48
+ return content
49
+ }
50
+ }
51
+ throw new Error('Config file not found')
52
+ } else {
53
+ const fileName = path.join(CONFIG_DIRECTORY, `default.json`)
54
+ return tryReadConfigFile(fileName)
55
+ }
56
+ }
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Minimal logging for NetworkNode and other users of Logger.ts in the network package.
3
+ * This file needs to be imported before any of the network package classes
4
+ * so that the environment variable is updated before any Logger instances are created.
5
+ * The import is needed for the files where network packages are used (typically
6
+ * the files which call createClientCommand()).
7
+ */
8
+
9
+ process.env.LOG_LEVEL = process.env.LOG_LEVEL ?? 'error'
@@ -0,0 +1,53 @@
1
+ import { Argument } from 'commander'
2
+ import { PermissionAssignment, Stream, StreamPermission, StreamrClient } from 'streamr-client'
3
+ import { createClientCommand } from './command'
4
+
5
+ const PUBLIC_USER_ID = 'public'
6
+
7
+ export const PERMISSIONS = new Map<string, StreamPermission>([
8
+ ['subscribe', StreamPermission.SUBSCRIBE],
9
+ ['publish', StreamPermission.PUBLISH],
10
+ ['edit', StreamPermission.EDIT],
11
+ ['delete', StreamPermission.DELETE],
12
+ ['grant', StreamPermission.GRANT]
13
+ ])
14
+
15
+ export const getPermission = (id: string): StreamPermission | never => {
16
+ const result = PERMISSIONS.get(id)
17
+ if (result === undefined) {
18
+ throw new Error(`unknown permission: ${id}`)
19
+ }
20
+ return result
21
+ }
22
+
23
+ export const getPermissionId = (permission: StreamPermission): string => {
24
+ return Array.from(PERMISSIONS.entries()).find(([_id, p]) => p === permission)![0]
25
+ }
26
+
27
+ export const runModifyPermissionsCommand = (
28
+ modify: (stream: Stream, assignment: PermissionAssignment) => Promise<void>,
29
+ modification: string,
30
+ ): void => {
31
+ createClientCommand(async (client: StreamrClient, streamId: string, user: string, permissionIds: string[]) => {
32
+ const stream = await client.getStream(streamId)
33
+ const permissions: StreamPermission[] = permissionIds.map((permissionId) => getPermission(permissionId))
34
+ let assignment: PermissionAssignment
35
+ if (user === PUBLIC_USER_ID) {
36
+ assignment = {
37
+ permissions,
38
+ public: true
39
+ }
40
+ } else {
41
+ assignment = {
42
+ permissions,
43
+ user
44
+ }
45
+ }
46
+ await modify(stream, assignment)
47
+ })
48
+ .addArgument(new Argument('<streamId>'))
49
+ .addArgument(new Argument('<user>'))
50
+ .addArgument(new Argument('<permissions...>').choices(Array.from(PERMISSIONS.keys())))
51
+ .description(`${modification} permission: use keyword "public" as a user to ${modification} a public permission`)
52
+ .parseAsync(process.argv)
53
+ }
package/src/resend.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { StreamrClient, ResendOptions } from 'streamr-client'
2
+
3
+ export const assertBothOrNoneDefined = <T extends object>(
4
+ option1: keyof T,
5
+ option2: keyof T,
6
+ errorMessage: string,
7
+ commandOptions: T
8
+ ): void | never => {
9
+ if ((option1 in commandOptions && !(option2 in commandOptions)) || (option2 in commandOptions && !(option1 in commandOptions))) {
10
+ console.error(`option ${errorMessage}`)
11
+ process.exit(1)
12
+ }
13
+ }
14
+
15
+ export const resend = async (
16
+ streamId: string,
17
+ resendOpts: ResendOptions,
18
+ client: StreamrClient,
19
+ subscribe: boolean
20
+ ): Promise<void> => {
21
+ try {
22
+ const handler = (message: any) => {
23
+ console.info(JSON.stringify(message))
24
+ }
25
+ if (subscribe) {
26
+ await client.subscribe({
27
+ stream: streamId,
28
+ resend: resendOpts
29
+ }, handler)
30
+ } else {
31
+ await client.resend(streamId, resendOpts, handler)
32
+ }
33
+ } catch (err) {
34
+ console.error(err.message ? err.message : err)
35
+ process.exit(1)
36
+ }
37
+ }
@@ -0,0 +1,19 @@
1
+ import { collect } from '@streamr/utils'
2
+ import 'jest-extended'
3
+ import { startCommand } from './utils'
4
+
5
+ describe('mock-data', () => {
6
+
7
+ it('generate', async () => {
8
+ const abortController = new AbortController()
9
+ const outputIterable = startCommand('mock-data generate', {
10
+ abortSignal: abortController.signal,
11
+ devEnvironment: false
12
+ })
13
+ const firstLine = (await collect(outputIterable, 1))[0]
14
+ abortController.abort()
15
+ const json = JSON.parse(firstLine)
16
+ expect(json).toBeObject()
17
+ })
18
+
19
+ })