@heroku/skynet 1.13.0 → 2.0.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 (62) hide show
  1. package/dist/commands/allowlist/add.d.ts +11 -0
  2. package/dist/commands/allowlist/add.js +34 -0
  3. package/dist/commands/allowlist/remove.d.ts +10 -0
  4. package/dist/commands/allowlist/remove.js +27 -0
  5. package/dist/commands/allowlists.d.ts +7 -0
  6. package/dist/commands/allowlists.js +24 -0
  7. package/dist/commands/categories/add.d.ts +10 -0
  8. package/dist/commands/categories/add.js +33 -0
  9. package/dist/commands/categories/get.d.ts +7 -0
  10. package/dist/commands/categories/get.js +19 -0
  11. package/dist/commands/categories/remove.d.ts +9 -0
  12. package/dist/commands/categories/remove.js +26 -0
  13. package/dist/commands/deprovision.d.ts +14 -0
  14. package/dist/commands/deprovision.js +80 -0
  15. package/dist/commands/suspend/app-owner.d.ts +15 -0
  16. package/dist/commands/suspend/app-owner.js +87 -0
  17. package/dist/commands/suspend/apps.d.ts +13 -0
  18. package/dist/commands/suspend/apps.js +54 -0
  19. package/dist/commands/suspend/user.d.ts +17 -0
  20. package/dist/commands/suspend/user.js +110 -0
  21. package/dist/commands/suspensions.d.ts +9 -0
  22. package/dist/commands/suspensions.js +25 -0
  23. package/dist/commands/unsuspend/apps.d.ts +11 -0
  24. package/dist/commands/unsuspend/apps.js +48 -0
  25. package/dist/commands/unsuspend/user.d.ts +11 -0
  26. package/dist/commands/unsuspend/user.js +49 -0
  27. package/dist/commands/userpass/add.d.ts +10 -0
  28. package/dist/commands/userpass/add.js +33 -0
  29. package/dist/commands/userpass/remove.d.ts +10 -0
  30. package/dist/commands/userpass/remove.js +33 -0
  31. package/dist/lib/heroku.d.ts +13 -0
  32. package/dist/lib/heroku.js +32 -0
  33. package/dist/lib/skynet.d.ts +32 -0
  34. package/dist/lib/skynet.js +215 -0
  35. package/dist/lib/sudo.d.ts +1 -0
  36. package/dist/lib/sudo.js +7 -0
  37. package/dist/lib/utils.d.ts +5 -0
  38. package/dist/lib/utils.js +57 -0
  39. package/oclif.manifest.json +730 -0
  40. package/package.json +61 -23
  41. package/commands/allowlist/add.js +0 -38
  42. package/commands/allowlist/remove.js +0 -29
  43. package/commands/allowlists.js +0 -30
  44. package/commands/categories/add.js +0 -40
  45. package/commands/categories/get.js +0 -27
  46. package/commands/categories/remove.js +0 -33
  47. package/commands/deprovision.js +0 -42
  48. package/commands/suspend/app-owner.js +0 -58
  49. package/commands/suspend/apps.js +0 -34
  50. package/commands/suspend/user.js +0 -80
  51. package/commands/suspensions.js +0 -24
  52. package/commands/unsuspend/apps.js +0 -33
  53. package/commands/unsuspend/user.js +0 -33
  54. package/commands/userpass/add.js +0 -21
  55. package/commands/userpass/remove.js +0 -21
  56. package/index.js +0 -23
  57. package/lib/command.js +0 -12
  58. package/lib/heroku.js +0 -30
  59. package/lib/notifyOption.js +0 -24
  60. package/lib/skynet.js +0 -218
  61. package/lib/sudo.js +0 -5
  62. package/lib/utils.js +0 -35
@@ -0,0 +1,25 @@
1
+ import SkynetAPI from '../lib/skynet.js';
2
+ import { Command } from '@heroku-cli/command';
3
+ import { Flags, ux } from '@oclif/core';
4
+ export default class Suspensions extends Command {
5
+ static description = '(requires sudo) suspension history of the given user account';
6
+ static examples = [
7
+ '$ heroku skynet:suspensions -a [user account]'
8
+ ];
9
+ static flags = {
10
+ account: Flags.string({
11
+ name: 'account',
12
+ char: 'a',
13
+ description: 'user account email',
14
+ hasValue: true,
15
+ required: true
16
+ })
17
+ };
18
+ async run() {
19
+ const { flags } = await this.parse(Suspensions);
20
+ const skynet = new SkynetAPI(this.heroku.auth);
21
+ let response = await skynet.suspensions(flags.account);
22
+ response = JSON.parse(response);
23
+ ux.log(response);
24
+ }
25
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class UnsuspendApp extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ app: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ category: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ notes: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,48 @@
1
+ import SkynetAPI from '../../lib/skynet.js';
2
+ import { Command } from '@heroku-cli/command';
3
+ import { color } from '@heroku-cli/color';
4
+ import { Flags, ux } from '@oclif/core';
5
+ import { processUnsuspendResult } from '../../lib/utils.js';
6
+ export default class UnsuspendApp extends Command {
7
+ static description = '(requires sudo) unsuspends an app';
8
+ static examples = [
9
+ '$ heroku skynet:unsuspend:app -a test-app -n "helpful unsuspend message" -c "unsuspend-apology"'
10
+ ];
11
+ static flags = {
12
+ app: Flags.string({
13
+ name: 'app',
14
+ char: 'a',
15
+ description: 'app to unsuspend',
16
+ hasValue: true,
17
+ required: true
18
+ }),
19
+ category: Flags.string({
20
+ name: 'category',
21
+ char: 'c',
22
+ description: 'unsuspension category',
23
+ hasValue: true,
24
+ required: true
25
+ }),
26
+ notes: Flags.string({
27
+ name: 'notes',
28
+ char: 'n',
29
+ description: 'unsuspend notes',
30
+ hasValue: true,
31
+ required: true
32
+ })
33
+ };
34
+ async run() {
35
+ const { flags } = await this.parse(UnsuspendApp);
36
+ const skynet = new SkynetAPI(this.heroku.auth);
37
+ const app = flags.app;
38
+ const category = flags.category;
39
+ const notes = flags.notes;
40
+ if (!app) {
41
+ ux.error('Required flag: --app APP');
42
+ }
43
+ ux.action.start(`Unsuspending app ${color.cyan(app)}`);
44
+ let response = await skynet.unsuspendApp(app, category, notes);
45
+ response = JSON.parse(response);
46
+ processUnsuspendResult(app, response);
47
+ }
48
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class UnsuspendUser extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ user: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ category: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ notes: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,49 @@
1
+ import SkynetAPI from '../../lib/skynet.js';
2
+ import { requireSudo } from '../../lib/sudo.js';
3
+ import { Command } from '@heroku-cli/command';
4
+ import { color } from '@heroku-cli/color';
5
+ import { Flags, ux } from '@oclif/core';
6
+ import { processUnsuspendResult } from '../../lib/utils.js';
7
+ export default class UnsuspendUser extends Command {
8
+ static description = '(requires sudo) unsuspends a user';
9
+ static examples = [
10
+ '$ heroku skynet:unsuspend:user -u foo@bar.com -n "helpful unsuspend message" -c "unsuspend-account-recovery"'
11
+ ];
12
+ static flags = {
13
+ user: Flags.string({
14
+ name: 'user',
15
+ char: 'u',
16
+ description: 'user to unsuspend',
17
+ hasValue: true
18
+ }),
19
+ category: Flags.string({
20
+ name: 'category',
21
+ char: 'c',
22
+ description: 'unsuspension category',
23
+ hasValue: true,
24
+ required: true
25
+ }),
26
+ notes: Flags.string({
27
+ name: 'notes',
28
+ char: 'n',
29
+ description: 'unsuspend notes',
30
+ hasValue: true,
31
+ required: true
32
+ })
33
+ };
34
+ async run() {
35
+ requireSudo();
36
+ const { flags } = await this.parse(UnsuspendUser);
37
+ const skynet = new SkynetAPI(this.heroku.auth);
38
+ const user = flags.user || process.env.HEROKU_USER;
39
+ const category = flags.category;
40
+ const notes = flags.notes;
41
+ if (!user) {
42
+ ux.error('Required flag: --user USER');
43
+ }
44
+ ux.action.start(`Unsuspending ${color.cyan(user)}`);
45
+ let response = await skynet.unsuspendUser(user, category, notes);
46
+ response = JSON.parse(response);
47
+ processUnsuspendResult(user, response);
48
+ }
49
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class AddUserpass extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ user: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ flag: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,33 @@
1
+ import SkynetAPI from '../../lib/skynet.js';
2
+ import { Command } from '@heroku-cli/command';
3
+ import { color } from '@heroku-cli/color';
4
+ import { Flags, ux } from '@oclif/core';
5
+ export default class AddUserpass extends Command {
6
+ static description = 'adds a userpass flag to a given user';
7
+ static examples = [
8
+ '$ heroku skynet:userpass:add -u foo@bar.com -f cant-install-abused-addons'
9
+ ];
10
+ static flags = {
11
+ user: Flags.string({
12
+ name: 'user',
13
+ char: 'u',
14
+ description: 'user to apply userpass flag to',
15
+ hasValue: true,
16
+ required: true
17
+ }),
18
+ flag: Flags.string({
19
+ name: 'flag',
20
+ char: 'f',
21
+ description: 'flag to add to the given user',
22
+ hasValue: true,
23
+ required: true
24
+ })
25
+ };
26
+ async run() {
27
+ const { flags } = await this.parse(AddUserpass);
28
+ const skynet = new SkynetAPI(this.heroku.auth);
29
+ ux.action.start(`adding ${color.cyan(flags.flag)} to ${color.cyan(flags.user)}`);
30
+ await skynet.addUserpass(flags.user, flags.flag);
31
+ ux.action.stop();
32
+ }
33
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class RemoveUserpass extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ user: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ flag: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,33 @@
1
+ import SkynetAPI from '../../lib/skynet.js';
2
+ import { Command } from '@heroku-cli/command';
3
+ import { color } from '@heroku-cli/color';
4
+ import { Flags, ux } from '@oclif/core';
5
+ export default class RemoveUserpass extends Command {
6
+ static description = 'removes given flag from a given user';
7
+ static examples = [
8
+ '$ heroku skynet:userpass:remove -u foo@bar.com -f cant-install-abused-addons'
9
+ ];
10
+ static flags = {
11
+ user: Flags.string({
12
+ name: 'user',
13
+ char: 'u',
14
+ description: 'user to remove user_pass from',
15
+ hasValue: true,
16
+ required: true
17
+ }),
18
+ flag: Flags.string({
19
+ name: 'flag',
20
+ char: 'f',
21
+ description: 'flag to remove from given user',
22
+ hasValue: true,
23
+ required: true
24
+ })
25
+ };
26
+ async run() {
27
+ const { flags } = await this.parse(RemoveUserpass);
28
+ const skynet = new SkynetAPI(this.heroku.auth);
29
+ ux.action.start(`removing ${color.cyan(flags.flag)} from ${color.cyan(flags.user)}`);
30
+ await skynet.removeUserpass(flags.user, flags.flag);
31
+ ux.action.stop();
32
+ }
33
+ }
@@ -0,0 +1,13 @@
1
+ import { Method } from 'got';
2
+ interface RequestOptions {
3
+ method?: Method;
4
+ headers?: Record<string, string>;
5
+ body?: string;
6
+ json?: Record<string, any>;
7
+ }
8
+ export default class HerokuAPI {
9
+ private token;
10
+ constructor(token: string);
11
+ request(url: string, options?: RequestOptions): Promise<string>;
12
+ }
13
+ export {};
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+ import got from 'got';
3
+ const apiHost = 'https://api.heroku.com';
4
+ export default class HerokuAPI {
5
+ token;
6
+ constructor(token) {
7
+ this.token = token;
8
+ }
9
+ async request(url, options = {}) {
10
+ const gotOptions = {
11
+ ...options,
12
+ headers: Object.assign({
13
+ Authorization: `Bearer ${this.token}`,
14
+ Accept: 'application/json',
15
+ 'Content-type': 'application/x-www-form-urlencoded',
16
+ 'X-Heroku-Sudo': 'true'
17
+ }, options.headers)
18
+ };
19
+ switch (options.method) {
20
+ case 'delete':
21
+ try {
22
+ await got.delete(apiHost + url, gotOptions);
23
+ return 'done';
24
+ }
25
+ catch {
26
+ return 'failed';
27
+ }
28
+ default:
29
+ return '';
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,32 @@
1
+ import FormData from 'form-data';
2
+ interface RequestOptions {
3
+ method?: 'GET' | 'POST' | 'DELETE';
4
+ headers?: Record<string, string>;
5
+ body?: FormData | any;
6
+ json?: any;
7
+ form?: any;
8
+ }
9
+ export default class SkynetAPI {
10
+ private version;
11
+ private token;
12
+ constructor(token: string);
13
+ request(url: string, options?: RequestOptions): Promise<any>;
14
+ categories(): Promise<any>;
15
+ addCategory(name: string, description: string): Promise<any>;
16
+ removeCategory(name: string): Promise<any>;
17
+ allowlists(): Promise<any>;
18
+ addAllowlist(appOrUserEmail: string, notes: string): Promise<any>;
19
+ removeAllowlist(appOrUserEmail: string): Promise<any>;
20
+ removeUserpass(user: string, flag: string): Promise<any>;
21
+ addUserpass(user: string, flag: string): Promise<any>;
22
+ suspendAppOwner(app: string, notes: string, category: string, force?: boolean, deprovision?: boolean, async?: boolean): Promise<any>;
23
+ suspendApp(app: string, notes: string, category: string, force?: boolean, async?: boolean): Promise<any>;
24
+ unsuspendApp(app: string, category: string, notes: string): Promise<any>;
25
+ suspendUser(user: string, notes: string, category: string, notify: boolean, force?: boolean, deprovision?: boolean, async?: boolean): Promise<any>;
26
+ unsuspendUser(user: string, category: string, notes: string): Promise<any>;
27
+ bulkSuspendUsers(file: string, notes: string, category: string, notify: boolean, force?: boolean, deprovision?: boolean): Promise<any>;
28
+ bulkSuspendAppOwner(apps: string, notes: string, category: string, deprovision?: boolean): Promise<any>;
29
+ deprovision(user: string, notes: string, category: string, notify?: boolean, force?: boolean): Promise<any>;
30
+ suspensions(account: string): Promise<any>;
31
+ }
32
+ export {};
@@ -0,0 +1,215 @@
1
+ import got from 'got';
2
+ import fs from 'fs';
3
+ import FormData from 'form-data';
4
+ import { readFileSync } from 'fs';
5
+ import { join, dirname } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ let skynetHost = 'https://skynet.risk.herokai.com';
8
+ // If test against local skynet environment, change skynet host to localhost:5000
9
+ // let skynetHost = 'http://localhost:5000'
10
+ if (process.env.SKYNET_HOST) {
11
+ skynetHost = process.env.SKYNET_HOST;
12
+ }
13
+ const SKYNET_BASE_URL = `${skynetHost}/api-h`;
14
+ export default class SkynetAPI {
15
+ version;
16
+ token;
17
+ constructor(token) {
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+ const packageJSON = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
21
+ this.version = `skynet-${packageJSON.version}`;
22
+ this.token = token;
23
+ }
24
+ request(url, options = {}) {
25
+ if (options.body && options.body instanceof FormData) {
26
+ options.headers = Object.assign({
27
+ Authorization: `Bearer ${this.token}`,
28
+ 'User-Agent': this.version
29
+ }, options.body.getHeaders(), options.headers);
30
+ }
31
+ else {
32
+ options.headers = Object.assign({
33
+ Authorization: `Bearer ${this.token}`,
34
+ 'User-Agent': this.version
35
+ }, options.headers);
36
+ }
37
+ switch (options.method) {
38
+ case 'DELETE':
39
+ return got.delete(SKYNET_BASE_URL + url, options).then(res => res.body);
40
+ case 'GET':
41
+ return got.get(SKYNET_BASE_URL + url, options).then(res => res.body);
42
+ case 'POST':
43
+ return got.post(SKYNET_BASE_URL + url, options).then(res => res.body);
44
+ default:
45
+ return Promise.resolve(null);
46
+ }
47
+ }
48
+ categories() {
49
+ return this.request('/categories', {
50
+ method: 'GET'
51
+ });
52
+ }
53
+ addCategory(name, description) {
54
+ return this.request('/categories', {
55
+ method: 'POST',
56
+ json: {
57
+ category: name,
58
+ description
59
+ }
60
+ });
61
+ }
62
+ removeCategory(name) {
63
+ return this.request(`/categories/${name}`, {
64
+ method: 'DELETE'
65
+ });
66
+ }
67
+ allowlists() {
68
+ return this.request('/whitelist', {
69
+ method: 'GET'
70
+ });
71
+ }
72
+ addAllowlist(appOrUserEmail, notes) {
73
+ const body = {
74
+ value: appOrUserEmail,
75
+ notes
76
+ };
77
+ return this.request('/whitelist', {
78
+ method: 'POST',
79
+ form: body
80
+ });
81
+ }
82
+ removeAllowlist(appOrUserEmail) {
83
+ return this.request(`/whitelist/${appOrUserEmail}`, {
84
+ method: 'DELETE',
85
+ json: {}
86
+ });
87
+ }
88
+ removeUserpass(user, flag) {
89
+ const body = {
90
+ user,
91
+ flag
92
+ };
93
+ return this.request('/userpass/remove', {
94
+ method: 'POST',
95
+ form: body
96
+ });
97
+ }
98
+ addUserpass(user, flag) {
99
+ const body = {
100
+ user,
101
+ flag
102
+ };
103
+ return this.request('/userpass/add', {
104
+ method: 'POST',
105
+ form: body
106
+ });
107
+ }
108
+ suspendAppOwner(app, notes, category, force = false, deprovision = false, async = false) {
109
+ const body = {
110
+ value: app,
111
+ reason: notes,
112
+ method: 'skynet-cli',
113
+ category,
114
+ force,
115
+ deprovision,
116
+ sync: !async,
117
+ };
118
+ return this.request('/suspend/app-owner', {
119
+ method: 'POST',
120
+ form: body
121
+ });
122
+ }
123
+ suspendApp(app, notes, category, force = false, async = false) {
124
+ const body = {
125
+ value: app,
126
+ reason: notes,
127
+ category,
128
+ force,
129
+ method: 'skynet-cli',
130
+ sync: !async,
131
+ };
132
+ return this.request('/suspend/app', {
133
+ method: 'POST',
134
+ form: body
135
+ });
136
+ }
137
+ unsuspendApp(app, category, notes) {
138
+ return this.request(`/suspensions/app/${app}?category=${category}&reason=${notes}`, {
139
+ method: 'DELETE',
140
+ json: {}
141
+ });
142
+ }
143
+ suspendUser(user, notes, category, notify, force = false, deprovision = false, async = false) {
144
+ const body = {
145
+ value: user,
146
+ reason: notes,
147
+ method: 'skynet-cli',
148
+ category,
149
+ force,
150
+ notify,
151
+ deprovision,
152
+ sync: !async,
153
+ };
154
+ return this.request('/suspend/user', {
155
+ method: 'POST',
156
+ form: body
157
+ });
158
+ }
159
+ unsuspendUser(user, category, notes) {
160
+ return this.request(`/suspensions/user/${user}?category=${category}&reason=${notes}`, {
161
+ method: 'DELETE',
162
+ json: {}
163
+ });
164
+ }
165
+ bulkSuspendUsers(file, notes, category, notify, force = false, deprovision = false) {
166
+ const fileStream = fs.createReadStream(file);
167
+ const form = new FormData();
168
+ form.append('file', fileStream);
169
+ form.append('reason', notes);
170
+ form.append('method', 'skynet-cli');
171
+ form.append('category', category);
172
+ form.append('bulk', 'true');
173
+ form.append('force', String(force));
174
+ form.append('notify', String(notify));
175
+ form.append('deprovision', String(deprovision));
176
+ return this.request('/bulk-suspend/user', {
177
+ method: 'POST',
178
+ body: form
179
+ });
180
+ }
181
+ bulkSuspendAppOwner(apps, notes, category, deprovision = false) {
182
+ const body = {
183
+ value: apps,
184
+ reason: notes,
185
+ method: 'skynet-cli',
186
+ category,
187
+ bulk: 'true',
188
+ deprovision
189
+ };
190
+ return this.request('/suspend/app-owner', {
191
+ method: 'POST',
192
+ form: body
193
+ });
194
+ }
195
+ deprovision(user, notes, category, notify = true, force = false) {
196
+ const body = {
197
+ value: user,
198
+ reason: notes,
199
+ method: 'skynet-cli',
200
+ category,
201
+ force,
202
+ notify
203
+ };
204
+ return this.request('/deprovision', {
205
+ method: 'POST',
206
+ form: body
207
+ });
208
+ }
209
+ suspensions(account) {
210
+ return this.request(`/v2/suspensions/${account}`, {
211
+ method: 'GET'
212
+ });
213
+ }
214
+ }
215
+ ;
@@ -0,0 +1 @@
1
+ export declare function requireSudo(): void;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+ import { ux } from '@oclif/core';
3
+ import { color } from '@heroku-cli/color';
4
+ export function requireSudo() {
5
+ if (process.env.HEROKU_SUDO !== '1')
6
+ ux.error(color.bgRed('sudo is required for this command'));
7
+ }
@@ -0,0 +1,5 @@
1
+ export declare function readlines(file: string): Promise<string[]>;
2
+ export declare function arrayChunks<T>(array: T[], chunkSize: number): T[][];
3
+ export declare function processSuspensionResult(suspendObject: any, response: any): void;
4
+ export declare function processUnsuspendResult(unsuspendObject: any, response: any): void;
5
+ export declare function logError(response: any): void;
@@ -0,0 +1,57 @@
1
+ import split from 'split';
2
+ import fs from 'fs';
3
+ import { ux } from '@oclif/core';
4
+ import { color } from '@heroku-cli/color';
5
+ export function readlines(file) {
6
+ return new Promise(function (resolve, reject) {
7
+ const entries = [];
8
+ fs.createReadStream(file).pipe(split())
9
+ .on('data', function (line) {
10
+ line = line.trim();
11
+ if (line) {
12
+ entries.push(line);
13
+ }
14
+ })
15
+ .on('end', function () {
16
+ resolve(entries);
17
+ })
18
+ .on('error', function (err) {
19
+ reject(err);
20
+ });
21
+ });
22
+ }
23
+ export function arrayChunks(array, chunkSize) {
24
+ const chunks = [];
25
+ if (array.length <= chunkSize) {
26
+ chunks.push(array);
27
+ }
28
+ else {
29
+ for (let i = 0; i < array.length; i += chunkSize) {
30
+ chunks.push(array.slice(i, i + chunkSize));
31
+ }
32
+ }
33
+ return chunks;
34
+ }
35
+ export function processSuspensionResult(suspendObject, response) {
36
+ if (response.statusCode === 200) {
37
+ ux.action.stop(color.green(`Suspended ${suspendObject}`));
38
+ }
39
+ else {
40
+ logError(response);
41
+ ux.action.stop(color.bgRed(`Failed to suspend ${suspendObject}`));
42
+ }
43
+ }
44
+ export function processUnsuspendResult(unsuspendObject, response) {
45
+ if (response.statusCode === 200) {
46
+ ux.action.stop(color.green(`Unsuspended ${unsuspendObject}`));
47
+ }
48
+ else {
49
+ logError(response);
50
+ ux.action.stop(color.bgRed(`Failed to unsuspend ${unsuspendObject}`));
51
+ }
52
+ }
53
+ export function logError(response) {
54
+ ux.log(`${color.red(response.status)} \'${response.statusCode}\'.`);
55
+ ux.log(color.red(response.message));
56
+ ux.log(color.red(`Error: ${response.error}`));
57
+ }