@getbrevo/cli 0.0.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +182 -0
  4. package/dist/api/client.d.ts +23 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +186 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/bin/index.d.ts +3 -0
  9. package/dist/bin/index.d.ts.map +1 -0
  10. package/dist/bin/index.js +179 -0
  11. package/dist/bin/index.js.map +1 -0
  12. package/dist/commands/app/create.d.ts +7 -0
  13. package/dist/commands/app/create.d.ts.map +1 -0
  14. package/dist/commands/app/create.js +261 -0
  15. package/dist/commands/app/create.js.map +1 -0
  16. package/dist/commands/app/credentials.d.ts +6 -0
  17. package/dist/commands/app/credentials.d.ts.map +1 -0
  18. package/dist/commands/app/credentials.js +106 -0
  19. package/dist/commands/app/credentials.js.map +1 -0
  20. package/dist/commands/app/delete.d.ts +6 -0
  21. package/dist/commands/app/delete.d.ts.map +1 -0
  22. package/dist/commands/app/delete.js +146 -0
  23. package/dist/commands/app/delete.js.map +1 -0
  24. package/dist/commands/app/list.d.ts +4 -0
  25. package/dist/commands/app/list.d.ts.map +1 -0
  26. package/dist/commands/app/list.js +46 -0
  27. package/dist/commands/app/list.js.map +1 -0
  28. package/dist/commands/app/scaffold.d.ts +5 -0
  29. package/dist/commands/app/scaffold.d.ts.map +1 -0
  30. package/dist/commands/app/scaffold.js +199 -0
  31. package/dist/commands/app/scaffold.js.map +1 -0
  32. package/dist/commands/app/start.d.ts +5 -0
  33. package/dist/commands/app/start.d.ts.map +1 -0
  34. package/dist/commands/app/start.js +138 -0
  35. package/dist/commands/app/start.js.map +1 -0
  36. package/dist/commands/app/test.d.ts +6 -0
  37. package/dist/commands/app/test.d.ts.map +1 -0
  38. package/dist/commands/app/test.js +495 -0
  39. package/dist/commands/app/test.js.map +1 -0
  40. package/dist/commands/app/update.d.ts +2 -0
  41. package/dist/commands/app/update.d.ts.map +1 -0
  42. package/dist/commands/app/update.js +324 -0
  43. package/dist/commands/app/update.js.map +1 -0
  44. package/dist/commands/definitions.d.ts +4 -0
  45. package/dist/commands/definitions.d.ts.map +1 -0
  46. package/dist/commands/definitions.js +197 -0
  47. package/dist/commands/definitions.js.map +1 -0
  48. package/dist/commands/init.d.ts +2 -0
  49. package/dist/commands/init.d.ts.map +1 -0
  50. package/dist/commands/init.js +90 -0
  51. package/dist/commands/init.js.map +1 -0
  52. package/dist/commands/login.d.ts +6 -0
  53. package/dist/commands/login.d.ts.map +1 -0
  54. package/dist/commands/login.js +219 -0
  55. package/dist/commands/login.js.map +1 -0
  56. package/dist/commands/logout.d.ts +5 -0
  57. package/dist/commands/logout.d.ts.map +1 -0
  58. package/dist/commands/logout.js +54 -0
  59. package/dist/commands/logout.js.map +1 -0
  60. package/dist/commands/whoami.d.ts +4 -0
  61. package/dist/commands/whoami.d.ts.map +1 -0
  62. package/dist/commands/whoami.js +74 -0
  63. package/dist/commands/whoami.js.map +1 -0
  64. package/dist/container.d.ts +7 -0
  65. package/dist/container.d.ts.map +1 -0
  66. package/dist/container.js +28 -0
  67. package/dist/container.js.map +1 -0
  68. package/dist/lang/en.d.ts +110 -0
  69. package/dist/lang/en.d.ts.map +1 -0
  70. package/dist/lang/en.js +133 -0
  71. package/dist/lang/en.js.map +1 -0
  72. package/dist/lib/abort.d.ts +3 -0
  73. package/dist/lib/abort.d.ts.map +1 -0
  74. package/dist/lib/abort.js +30 -0
  75. package/dist/lib/abort.js.map +1 -0
  76. package/dist/lib/auth-guard.d.ts +3 -0
  77. package/dist/lib/auth-guard.d.ts.map +1 -0
  78. package/dist/lib/auth-guard.js +25 -0
  79. package/dist/lib/auth-guard.js.map +1 -0
  80. package/dist/lib/browser.d.ts +2 -0
  81. package/dist/lib/browser.d.ts.map +1 -0
  82. package/dist/lib/browser.js +16 -0
  83. package/dist/lib/browser.js.map +1 -0
  84. package/dist/lib/command-handler.d.ts +10 -0
  85. package/dist/lib/command-handler.d.ts.map +1 -0
  86. package/dist/lib/command-handler.js +16 -0
  87. package/dist/lib/command-handler.js.map +1 -0
  88. package/dist/lib/command-registry.d.ts +28 -0
  89. package/dist/lib/command-registry.d.ts.map +1 -0
  90. package/dist/lib/command-registry.js +54 -0
  91. package/dist/lib/command-registry.js.map +1 -0
  92. package/dist/lib/config.d.ts +76 -0
  93. package/dist/lib/config.d.ts.map +1 -0
  94. package/dist/lib/config.js +314 -0
  95. package/dist/lib/config.js.map +1 -0
  96. package/dist/lib/constants.d.ts +35 -0
  97. package/dist/lib/constants.d.ts.map +1 -0
  98. package/dist/lib/constants.js +97 -0
  99. package/dist/lib/constants.js.map +1 -0
  100. package/dist/lib/errors.d.ts +30 -0
  101. package/dist/lib/errors.d.ts.map +1 -0
  102. package/dist/lib/errors.js +66 -0
  103. package/dist/lib/errors.js.map +1 -0
  104. package/dist/lib/exit-codes.d.ts +9 -0
  105. package/dist/lib/exit-codes.d.ts.map +1 -0
  106. package/dist/lib/exit-codes.js +12 -0
  107. package/dist/lib/exit-codes.js.map +1 -0
  108. package/dist/lib/hidden-input.d.ts +2 -0
  109. package/dist/lib/hidden-input.d.ts.map +1 -0
  110. package/dist/lib/hidden-input.js +78 -0
  111. package/dist/lib/hidden-input.js.map +1 -0
  112. package/dist/lib/json-output.d.ts +6 -0
  113. package/dist/lib/json-output.d.ts.map +1 -0
  114. package/dist/lib/json-output.js +11 -0
  115. package/dist/lib/json-output.js.map +1 -0
  116. package/dist/lib/logger.d.ts +11 -0
  117. package/dist/lib/logger.d.ts.map +1 -0
  118. package/dist/lib/logger.js +87 -0
  119. package/dist/lib/logger.js.map +1 -0
  120. package/dist/lib/port.d.ts +12 -0
  121. package/dist/lib/port.d.ts.map +1 -0
  122. package/dist/lib/port.js +79 -0
  123. package/dist/lib/port.js.map +1 -0
  124. package/dist/lib/ui.d.ts +14 -0
  125. package/dist/lib/ui.d.ts.map +1 -0
  126. package/dist/lib/ui.js +75 -0
  127. package/dist/lib/ui.js.map +1 -0
  128. package/dist/lib/validators.d.ts +32 -0
  129. package/dist/lib/validators.d.ts.map +1 -0
  130. package/dist/lib/validators.js +96 -0
  131. package/dist/lib/validators.js.map +1 -0
  132. package/dist/services/account.d.ts +8 -0
  133. package/dist/services/account.d.ts.map +1 -0
  134. package/dist/services/account.js +15 -0
  135. package/dist/services/account.js.map +1 -0
  136. package/dist/services/app.d.ts +35 -0
  137. package/dist/services/app.d.ts.map +1 -0
  138. package/dist/services/app.js +117 -0
  139. package/dist/services/app.js.map +1 -0
  140. package/dist/services/browser-auth.d.ts +15 -0
  141. package/dist/services/browser-auth.d.ts.map +1 -0
  142. package/dist/services/browser-auth.js +187 -0
  143. package/dist/services/browser-auth.js.map +1 -0
  144. package/dist/services/normalize-app-id.d.ts +12 -0
  145. package/dist/services/normalize-app-id.d.ts.map +1 -0
  146. package/dist/services/normalize-app-id.js +38 -0
  147. package/dist/services/normalize-app-id.js.map +1 -0
  148. package/dist/services/oauth-refresh.d.ts +14 -0
  149. package/dist/services/oauth-refresh.d.ts.map +1 -0
  150. package/dist/services/oauth-refresh.js +70 -0
  151. package/dist/services/oauth-refresh.js.map +1 -0
  152. package/dist/templates/files/AGENTS.md.tmpl +41 -0
  153. package/dist/templates/files/CLAUDE.md.tmpl +50 -0
  154. package/dist/templates/files/README.md.tmpl +77 -0
  155. package/dist/templates/files/app-config.json.tmpl +23 -0
  156. package/dist/templates/files/gitignore.tmpl +9 -0
  157. package/dist/templates/files/src/oauth/.env.example.tmpl +13 -0
  158. package/dist/templates/files/src/oauth/.env.local.tmpl +10 -0
  159. package/dist/templates/files/src/oauth/handler.js.tmpl +203 -0
  160. package/dist/templates/files/src/oauth/package.json.tmpl +15 -0
  161. package/dist/templates/files/src/oauth/server.js.tmpl +226 -0
  162. package/dist/templates/files/src/oauth/token-store.js.tmpl +39 -0
  163. package/dist/templates/index.d.ts +36 -0
  164. package/dist/templates/index.d.ts.map +1 -0
  165. package/dist/templates/index.js +105 -0
  166. package/dist/templates/index.js.map +1 -0
  167. package/dist/types.d.ts +30 -0
  168. package/dist/types.d.ts.map +1 -0
  169. package/dist/types.js +3 -0
  170. package/dist/types.js.map +1 -0
  171. package/package.json +81 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const loginCommand: (opts: {
2
+ browser?: boolean;
3
+ json?: boolean;
4
+ suppressNextSteps?: boolean;
5
+ }) => Promise<void>;
6
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,YAAY;cAEX,OAAO;WACV,OAAO;wBACM,OAAO;mBAoM9B,CAAC"}
@@ -0,0 +1,219 @@
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.loginCommand = void 0;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const config_1 = require("../lib/config");
9
+ const constants_1 = require("../lib/constants");
10
+ const browser_1 = require("../lib/browser");
11
+ const logger_1 = require("../lib/logger");
12
+ const en_1 = require("../lang/en");
13
+ const errors_1 = require("../lib/errors");
14
+ const command_handler_1 = require("../lib/command-handler");
15
+ const create_1 = require("./app/create");
16
+ const container_1 = require("../container");
17
+ const ui_1 = require("../lib/ui");
18
+ const json_output_1 = require("../lib/json-output");
19
+ const browser_auth_1 = require("../services/browser-auth");
20
+ async function promptApiKey() {
21
+ const { key } = await inquirer_1.default.prompt([
22
+ {
23
+ type: 'password',
24
+ name: 'key',
25
+ message: en_1.messages.AUTH_PROMPT_API_KEY,
26
+ mask: '*',
27
+ validate: (input) => input.trim().length > 0 || 'API key cannot be empty',
28
+ },
29
+ ]);
30
+ return key;
31
+ }
32
+ exports.loginCommand = (0, command_handler_1.withCommandHandler)(async (options) => {
33
+ // In --json mode, stdout must be a single JSON document. Suppress the
34
+ // welcome banner and every human-oriented log on stdout below; errors
35
+ // still go to stderr via logError, which is fine for JSON consumers.
36
+ const quiet = !!options.json;
37
+ if (!quiet) {
38
+ process.stdout.write(`\n ${en_1.messages.AUTH_WELCOME}\n`);
39
+ process.stdout.write(' ──────────────────────────────────────\n');
40
+ }
41
+ let apiKey = process.env.BREVO_API_KEY;
42
+ let method;
43
+ // Explicit `--browser` wins over BREVO_API_KEY so users can force the
44
+ // browser flow on machines that have a stale env var. Browser login still
45
+ // needs a TTY (the inquirer prompts after success), so reject early in
46
+ // non-interactive contexts instead of hanging until timeout.
47
+ if (options.browser) {
48
+ if (!process.stdin.isTTY) {
49
+ throw new errors_1.CliError(en_1.messages.AUTH_BROWSER_NON_INTERACTIVE);
50
+ }
51
+ method = 'browser';
52
+ }
53
+ else if (apiKey) {
54
+ method = 'api-key';
55
+ }
56
+ else if (!process.stdin.isTTY) {
57
+ throw new errors_1.CliError(en_1.messages.AUTH_BROWSER_NON_INTERACTIVE);
58
+ }
59
+ else {
60
+ const { chosen } = await inquirer_1.default.prompt([
61
+ {
62
+ type: 'list',
63
+ name: 'chosen',
64
+ message: en_1.messages.AUTH_PROMPT_METHOD,
65
+ choices: [
66
+ { name: 'Browser (sign in through your browser)', value: 'browser' },
67
+ { name: 'API key (paste from your Brevo dashboard)', value: 'api-key' },
68
+ ],
69
+ default: 'browser',
70
+ },
71
+ ]);
72
+ method = chosen;
73
+ }
74
+ let account;
75
+ if (method === 'api-key') {
76
+ if (!apiKey) {
77
+ (0, browser_1.openBrowser)(constants_1.BREVO_DASHBOARD_API_KEYS_URL);
78
+ if (!quiet) {
79
+ process.stdout.write(en_1.messages.AUTH_HINT(constants_1.BREVO_DASHBOARD_API_KEYS_URL, constants_1.BREVO_API_KEY_DOCS_URL));
80
+ }
81
+ apiKey = await promptApiKey();
82
+ }
83
+ if (!apiKey) {
84
+ throw new errors_1.CliError('No API key provided.');
85
+ }
86
+ const spinner = (0, ui_1.createSpinner)('Validating API key...', { silent: quiet });
87
+ try {
88
+ account = await container_1.accountService.validateApiKey(apiKey);
89
+ spinner.stop();
90
+ }
91
+ catch (err) {
92
+ spinner.stop();
93
+ if (err instanceof errors_1.ApiError && err.statusCode === 401) {
94
+ (0, logger_1.logError)(en_1.messages.AUTH_INVALID_KEY);
95
+ if (!quiet)
96
+ (0, logger_1.logInfo)(` ${en_1.messages.AUTH_GET_KEY_URL}`);
97
+ if (!process.stdin.isTTY) {
98
+ throw err;
99
+ }
100
+ const retryKey = await promptApiKey();
101
+ const retrySpinner = (0, ui_1.createSpinner)('Validating API key...', { silent: quiet });
102
+ try {
103
+ account = await container_1.accountService.validateApiKey(retryKey);
104
+ retrySpinner.stop();
105
+ apiKey = retryKey;
106
+ }
107
+ catch (retryErr) {
108
+ retrySpinner.stop();
109
+ throw retryErr;
110
+ }
111
+ }
112
+ else {
113
+ throw err;
114
+ }
115
+ }
116
+ if (!account) {
117
+ throw new errors_1.CliError('Authentication failed.');
118
+ }
119
+ (0, config_1.saveCredentials)(apiKey, {
120
+ email: account.email,
121
+ organizationId: account.organization_id,
122
+ userId: account.user_id,
123
+ });
124
+ }
125
+ else {
126
+ if (!quiet)
127
+ (0, logger_1.logInfo)(` ${en_1.messages.AUTH_BROWSER_OPENING}`);
128
+ const tokens = await (0, browser_auth_1.runBrowserLoginFlow)({
129
+ proxyUrl: constants_1.OAUTH_PROXY_URL,
130
+ openBrowser: browser_1.openBrowser,
131
+ onWaiting: (url) => {
132
+ if (quiet)
133
+ return;
134
+ (0, logger_1.logInfo)(` ${en_1.messages.AUTH_BROWSER_FALLBACK_URL(url)}`);
135
+ (0, logger_1.logInfo)(` ${en_1.messages.AUTH_BROWSER_WAITING}`);
136
+ },
137
+ });
138
+ // Persist tokens before validating /v3/account so transient API failures
139
+ // (5xx, 424, network) don't force the user to redo the OAuth dance. Only
140
+ // a 401 unambiguously means the token itself is bad — see catch below.
141
+ const tokensToStore = {
142
+ accessToken: tokens.accessToken,
143
+ refreshToken: tokens.refreshToken,
144
+ expiresIn: tokens.expiresIn,
145
+ tokenType: tokens.tokenType,
146
+ scope: tokens.scope,
147
+ };
148
+ (0, config_1.saveOauthCredentials)(tokensToStore);
149
+ if (!quiet)
150
+ (0, logger_1.logSuccess)(en_1.messages.AUTH_BROWSER_TOKENS_RECEIVED((0, config_1.getCredentialsPath)()));
151
+ const spinner = (0, ui_1.createSpinner)('Finishing login...', { silent: quiet });
152
+ try {
153
+ account = await container_1.client.getWithBearer(constants_1.ENDPOINTS.ACCOUNT, tokens.accessToken, tokens.tokenType);
154
+ }
155
+ catch (err) {
156
+ if (err instanceof errors_1.ApiError && err.statusCode === 401) {
157
+ (0, config_1.clearCredentials)();
158
+ }
159
+ throw err;
160
+ }
161
+ finally {
162
+ spinner.stop();
163
+ }
164
+ if (!account) {
165
+ throw new errors_1.CliError('Authentication failed.');
166
+ }
167
+ (0, config_1.saveOauthCredentials)(tokensToStore, {
168
+ email: account.email,
169
+ organizationId: account.organization_id,
170
+ userId: account.user_id,
171
+ });
172
+ }
173
+ if (options.json) {
174
+ (0, json_output_1.jsonOutput)({ authenticated: true, email: account.email, company: account.companyName });
175
+ return;
176
+ }
177
+ (0, logger_1.logSuccess)(en_1.messages.AUTH_SUCCESS(account.email));
178
+ (0, logger_1.logInfo)(en_1.messages.AUTH_SAVED((0, config_1.getCredentialsPath)()));
179
+ if (!options.suppressNextSteps) {
180
+ let apps = [];
181
+ const appsSpinner = (0, ui_1.createSpinner)('Checking your apps...');
182
+ try {
183
+ apps = await container_1.appService.fetchAppsList();
184
+ appsSpinner.stop();
185
+ }
186
+ catch {
187
+ appsSpinner.stop();
188
+ }
189
+ if (apps.length > 0) {
190
+ (0, ui_1.printBox)("What's next?", [
191
+ constants_1.CLI.APP_CREATE,
192
+ constants_1.CLI.APP_LIST,
193
+ constants_1.CLI.APP_SCAFFOLD(),
194
+ constants_1.CLI.APP_CREDENTIALS(),
195
+ ]);
196
+ }
197
+ else if (!process.stdin.isTTY) {
198
+ (0, logger_1.logInfo)(`\n ${en_1.messages.AUTH_NEXT}\n`);
199
+ }
200
+ else {
201
+ process.stdout.write('\n');
202
+ const { shouldCreate } = await inquirer_1.default.prompt([
203
+ {
204
+ type: 'confirm',
205
+ name: 'shouldCreate',
206
+ message: en_1.messages.AUTH_CREATE_APP_PROMPT,
207
+ default: true,
208
+ },
209
+ ]);
210
+ if (shouldCreate) {
211
+ process.stdout.write('\n');
212
+ await (0, create_1.createCommand)({});
213
+ return;
214
+ }
215
+ (0, logger_1.logInfo)(`\n ${en_1.messages.AUTH_NEXT}\n`);
216
+ }
217
+ }
218
+ });
219
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare const logoutCommand: (opts: {
2
+ force?: boolean;
3
+ json?: boolean;
4
+ }) => Promise<void>;
5
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,aAAa;YACE,OAAO;WAAS,OAAO;mBAyClD,CAAC"}
@@ -0,0 +1,54 @@
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.logoutCommand = void 0;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const config_1 = require("../lib/config");
9
+ const logger_1 = require("../lib/logger");
10
+ const errors_1 = require("../lib/errors");
11
+ const en_1 = require("../lang/en");
12
+ const command_handler_1 = require("../lib/command-handler");
13
+ const json_output_1 = require("../lib/json-output");
14
+ exports.logoutCommand = (0, command_handler_1.withCommandHandler)(async (options) => {
15
+ if (!(0, config_1.isAuthenticated)()) {
16
+ if (options.json) {
17
+ (0, json_output_1.jsonOutput)({ loggedOut: false, reason: 'not_authenticated' });
18
+ }
19
+ else {
20
+ (0, logger_1.logInfo)(`\n ${en_1.messages.AUTH_NOT_LOGGED_IN}\n`);
21
+ }
22
+ return;
23
+ }
24
+ if (!options.force && !options.json && (0, config_1.hasAppCredentials)()) {
25
+ if (!process.stdin.isTTY) {
26
+ throw new errors_1.CliError(en_1.messages.AUTH_LOGOUT_NON_INTERACTIVE);
27
+ }
28
+ (0, logger_1.logWarn)(en_1.messages.AUTH_LOGOUT_APP_WARNING);
29
+ const { confirmed } = await inquirer_1.default.prompt([
30
+ {
31
+ type: 'confirm',
32
+ name: 'confirmed',
33
+ message: en_1.messages.AUTH_LOGOUT_CONFIRM,
34
+ default: false,
35
+ },
36
+ ]);
37
+ if (!confirmed) {
38
+ (0, logger_1.logInfo)(`\n ${en_1.messages.ABORTED}\n`);
39
+ return;
40
+ }
41
+ }
42
+ const appCount = (0, config_1.countAppCredentials)();
43
+ (0, config_1.deleteCredentialsFile)();
44
+ if (options.json) {
45
+ (0, json_output_1.jsonOutput)({ loggedOut: true, appsCleared: appCount });
46
+ }
47
+ else if (appCount > 0) {
48
+ (0, logger_1.logSuccess)(en_1.messages.AUTH_LOGGED_OUT_WITH_APPS(appCount));
49
+ }
50
+ else {
51
+ (0, logger_1.logSuccess)(en_1.messages.AUTH_LOGGED_OUT);
52
+ }
53
+ });
54
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":";;;;;;AAAA,wDAAgC;AAChC,0CAKuB;AACvB,0CAA6D;AAC7D,0CAAyC;AACzC,mCAAsC;AACtC,4DAA4D;AAC5D,oDAAgD;AAEnC,QAAA,aAAa,GAAG,IAAA,oCAAkB,EAC7C,KAAK,EAAE,OAA4C,EAAiB,EAAE;IACpE,IAAI,CAAC,IAAA,wBAAe,GAAE,EAAE,CAAC;QACvB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,IAAA,wBAAU,EAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,IAAA,gBAAO,EAAC,OAAO,aAAQ,CAAC,kBAAkB,IAAI,CAAC,CAAC;QAClD,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAA,0BAAiB,GAAE,EAAE,CAAC;QAC3D,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,iBAAQ,CAAC,aAAQ,CAAC,2BAA2B,CAAC,CAAC;QAC3D,CAAC;QACD,IAAA,gBAAO,EAAC,aAAQ,CAAC,uBAAuB,CAAC,CAAC;QAC1C,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC;YAC1C;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,aAAQ,CAAC,mBAAmB;gBACrC,OAAO,EAAE,KAAK;aACf;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAA,gBAAO,EAAC,OAAO,aAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,IAAA,4BAAmB,GAAE,CAAC;IACvC,IAAA,8BAAqB,GAAE,CAAC;IAExB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,IAAA,wBAAU,EAAC,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;SAAM,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACxB,IAAA,mBAAU,EAAC,aAAQ,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACN,IAAA,mBAAU,EAAC,aAAQ,CAAC,eAAe,CAAC,CAAC;IACvC,CAAC;AACH,CAAC,CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const whoamiCommand: (opts: {
2
+ json?: boolean;
3
+ }) => Promise<void>;
4
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,aAAa;WACC,OAAO;mBAgEjC,CAAC"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.whoamiCommand = void 0;
4
+ const logger_1 = require("../lib/logger");
5
+ const en_1 = require("../lang/en");
6
+ const errors_1 = require("../lib/errors");
7
+ const config_1 = require("../lib/config");
8
+ const container_1 = require("../container");
9
+ const command_handler_1 = require("../lib/command-handler");
10
+ const json_output_1 = require("../lib/json-output");
11
+ const ui_1 = require("../lib/ui");
12
+ exports.whoamiCommand = (0, command_handler_1.withCommandHandler)(async (options) => {
13
+ // No stored key at all
14
+ if (!(0, config_1.isAuthenticated)()) {
15
+ if (options.json) {
16
+ (0, json_output_1.jsonOutput)({ authenticated: false, reason: 'no_key' });
17
+ }
18
+ throw new errors_1.CliError(en_1.messages.WHOAMI_NOT_AUTHENTICATED);
19
+ }
20
+ // Key exists — validate it against the API
21
+ const spinner = (0, ui_1.createSpinner)('Checking credentials...', { silent: options.json });
22
+ try {
23
+ const account = await container_1.accountService.getAccount();
24
+ spinner.stop();
25
+ // Check for mismatches between stored credentials and API response
26
+ const mismatched = [];
27
+ const storedEmail = (0, config_1.getEmail)();
28
+ const storedOrgId = (0, config_1.getOrganizationId)();
29
+ const storedUserId = (0, config_1.getUserId)();
30
+ if (storedEmail && storedEmail !== account.email)
31
+ mismatched.push('email');
32
+ if (storedOrgId && storedOrgId !== account.organization_id)
33
+ mismatched.push('organization');
34
+ if (storedUserId != null && storedUserId !== account.user_id)
35
+ mismatched.push('user id');
36
+ if (mismatched.length > 0) {
37
+ if (options.json) {
38
+ (0, json_output_1.jsonOutput)({
39
+ authenticated: false,
40
+ reason: 'credential_mismatch',
41
+ mismatchedFields: mismatched,
42
+ });
43
+ }
44
+ throw new errors_1.CliError(en_1.messages.WHOAMI_CREDENTIAL_MISMATCH(mismatched));
45
+ }
46
+ if (options.json) {
47
+ (0, json_output_1.jsonOutput)({
48
+ authenticated: true,
49
+ authKind: (0, config_1.getAuthCred)()?.kind,
50
+ email: account.email,
51
+ company: account.companyName || '',
52
+ organizationId: account.organization_id,
53
+ userId: account.user_id,
54
+ });
55
+ }
56
+ else {
57
+ const authKind = (0, config_1.getAuthCred)()?.kind;
58
+ const kindLabel = authKind === 'oauth' ? ' (browser login)' : authKind === 'api-key' ? ' (API key)' : '';
59
+ (0, logger_1.logInfo)(`\n ${en_1.messages.WHOAMI_AUTHENTICATED(account.email, account.companyName || 'N/A')}${kindLabel}\n` +
60
+ ` Organization: ${account.organization_id}\n` +
61
+ ` User ID: ${account.user_id}\n`);
62
+ }
63
+ }
64
+ catch (err) {
65
+ spinner.stop();
66
+ if (err instanceof errors_1.CliError)
67
+ throw err;
68
+ if (options.json) {
69
+ (0, json_output_1.jsonOutput)({ authenticated: false, reason: 'expired' });
70
+ }
71
+ throw new errors_1.CliError(en_1.messages.AUTH_EXPIRED);
72
+ }
73
+ });
74
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ApiClient } from './api/client';
2
+ import { AccountService } from './services/account';
3
+ import { AppService } from './services/app';
4
+ export declare const client: ApiClient;
5
+ export declare const accountService: AccountService;
6
+ export declare const appService: AppService;
7
+ //# sourceMappingURL=container.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAwB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAoB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAoB9D,eAAO,MAAM,MAAM,WAAuE,CAAC;AAE3F,eAAO,MAAM,cAAc,EAAE,cAA6C,CAAC;AAC3E,eAAO,MAAM,UAAU,EAAE,UAAqC,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appService = exports.accountService = exports.client = void 0;
4
+ const client_1 = require("./api/client");
5
+ const account_1 = require("./services/account");
6
+ const app_1 = require("./services/app");
7
+ const constants_1 = require("./lib/constants");
8
+ const config_1 = require("./lib/config");
9
+ /**
10
+ * Application container — creates and holds all shared instances.
11
+ * Initialized once by bin/index.ts. Commands import services from here.
12
+ *
13
+ * The auth-failure handler is wired in bin/index.ts so it can branch on
14
+ * stored auth kind (oauth: refresh+retry; api-key: prompt for new key)
15
+ * without pulling UI/prompt concerns into the container.
16
+ */
17
+ function buildAuthHeader() {
18
+ const auth = (0, config_1.getAuthCred)();
19
+ if (!auth)
20
+ return undefined;
21
+ if (auth.kind === 'api-key')
22
+ return { 'api-key': auth.apiKey };
23
+ return { Authorization: `${auth.tokenType} ${auth.accessToken}` };
24
+ }
25
+ exports.client = new client_1.ApiClient({ baseUrl: constants_1.API_BASE, getAuthHeader: buildAuthHeader });
26
+ exports.accountService = (0, account_1.createAccountService)(exports.client);
27
+ exports.appService = (0, app_1.createAppService)(exports.client);
28
+ //# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":";;;AAAA,yCAAyC;AACzC,gDAA0E;AAC1E,wCAA8D;AAC9D,+CAA2C;AAC3C,yCAA2C;AAE3C;;;;;;;GAOG;AAEH,SAAS,eAAe;IACtB,MAAM,IAAI,GAAG,IAAA,oBAAW,GAAE,CAAC;IAC3B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;IAC/D,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;AACpE,CAAC;AAEY,QAAA,MAAM,GAAG,IAAI,kBAAS,CAAC,EAAE,OAAO,EAAE,oBAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC,CAAC;AAE9E,QAAA,cAAc,GAAmB,IAAA,8BAAoB,EAAC,cAAM,CAAC,CAAC;AAC9D,QAAA,UAAU,GAAe,IAAA,sBAAgB,EAAC,cAAM,CAAC,CAAC"}
@@ -0,0 +1,110 @@
1
+ export declare const messages: {
2
+ readonly AUTH_WELCOME: "Welcome to Brevo CLI";
3
+ readonly AUTH_PROMPT_METHOD: "How would you like to authenticate?";
4
+ readonly AUTH_PROMPT_API_KEY: "Paste your API key:";
5
+ readonly AUTH_SUCCESS: (email: string) => string;
6
+ readonly AUTH_INVALID_KEY: "Invalid API key. Please check and try again.";
7
+ readonly AUTH_HINT: (keysUrl: string, docsUrl: string) => string;
8
+ readonly AUTH_SAVED: (path: string) => string;
9
+ readonly AUTH_NEXT: "Next: brevo app create";
10
+ readonly AUTH_CREATE_APP_PROMPT: "Would you like to create an app?";
11
+ readonly AUTH_NOT_LOGGED_IN: "Not currently authenticated.";
12
+ readonly AUTH_LOGGED_OUT: "Credentials cleared.";
13
+ readonly AUTH_LOGGED_OUT_WITH_APPS: (count: number) => string;
14
+ readonly AUTH_LOGOUT_APP_WARNING: "You have cached app credentials (clientId/clientSecret) that cannot be recovered after logout.\n Run `brevo app credentials --reveal-secret` to view them before proceeding.";
15
+ readonly AUTH_LOGOUT_CONFIRM: "Proceed with logout?";
16
+ readonly AUTH_EXPIRED: "Your API key is invalid or expired.";
17
+ readonly AUTH_EXPIRED_PROMPT: "Enter a new API key:";
18
+ readonly AUTH_GET_KEY_URL: "Create an API key at: https://app.brevo.com/settings/keys/api";
19
+ readonly AUTH_BROWSER_OPENING: "Opening your browser to log you in...";
20
+ readonly AUTH_BROWSER_FALLBACK_URL: (url: string) => string;
21
+ readonly AUTH_BROWSER_WAITING: "Waiting for login to complete (Ctrl+C to cancel)...";
22
+ readonly AUTH_BROWSER_TOKENS_RECEIVED: (path: string) => string;
23
+ readonly AUTH_BROWSER_TIMEOUT: "Login timed out before we received a response from the browser.\n If you were completing 2FA, close the browser tab and run `brevo login` again.\n For non-interactive use, set BREVO_API_KEY instead.";
24
+ readonly AUTH_BROWSER_CANCELLED: "Login cancelled.";
25
+ readonly AUTH_BROWSER_BAD_PAYLOAD: "Unexpected response from the login service. Please try again.";
26
+ readonly AUTH_BROWSER_NON_INTERACTIVE: "Browser login needs an interactive terminal. Set BREVO_API_KEY to authenticate non-interactively.";
27
+ readonly WHOAMI_AUTHENTICATED: (email: string, company: string) => string;
28
+ readonly WHOAMI_NOT_AUTHENTICATED: "Not authenticated. Run: brevo login";
29
+ readonly WHOAMI_CREDENTIAL_MISMATCH: (fields: string[]) => string;
30
+ readonly APP_CREATE_NAME_PROMPT: "App name:";
31
+ readonly APP_CREATE_TYPE_PROMPT: "Distribution type?";
32
+ readonly APP_CREATE_SUCCESS: "App created.";
33
+ readonly APP_CREATE_SCAFFOLD_PROMPT: "Generate starter code now?";
34
+ readonly APP_CREATE_NAME_TAKEN: "That name is already taken. Try a different name.";
35
+ readonly APP_CREATE_REDIRECT_PROMPT: "OAuth callback URL — where users are sent after authorizing your app:";
36
+ readonly APP_CREATE_REDIRECT_ANOTHER: "Add another redirect URL?";
37
+ readonly APP_CREATE_REDIRECT_EMPTY: "Redirect URL cannot be empty";
38
+ readonly APP_CREATE_REDIRECT_INVALID: "Invalid format. Must start with http:// or https://";
39
+ readonly APP_CREATE_PORT_IN_USE: (port: number, available: number) => string;
40
+ readonly APP_CREATE_PORT_SCAN_FAILED: (port: number) => string;
41
+ readonly APP_CREATE_LIMIT_REACHED: "You have reached the maximum number of OAuth apps allowed for your account. To make room, delete an existing app: brevo app delete";
42
+ readonly APP_CREATE_PUBLIC_UNAVAILABLE: "Public distribution is not yet available (coming soon). Use `--distribution private` for now.";
43
+ readonly APP_LIST_EMPTY: "No apps found. Create one with: brevo app create";
44
+ readonly APP_LIST_HEADER: "Your OAuth apps:";
45
+ readonly APP_CREDENTIALS_REVEAL_CONFIRM: "Are you sure you want to reveal the client secret?";
46
+ readonly APP_CREDENTIALS_SELECT: "Select an app:";
47
+ readonly APP_UPDATE_INVALID_JSON: "app-config.json contains invalid JSON. Please check the file and try again.";
48
+ readonly APP_UPDATE_MISSING_APP_ID: "app-config.json is missing \"appId\".";
49
+ readonly APP_UPDATE_NO_REDIRECT_URLS: "app-config.json has no redirect URLs configured.";
50
+ readonly APP_UPDATE_INVALID_APP_ID: "app-config.json has an invalid \"appId\". Expected a non-empty string.";
51
+ readonly APP_UPDATE_INVALID_REDIRECT_URL: (url: string) => string;
52
+ readonly APP_UPDATE_INVALID_REDIRECT_PROTOCOL: (url: string) => string;
53
+ readonly APP_UPDATE_SUMMARY: "Update summary:";
54
+ readonly APP_UPDATE_CONFIRM: "Proceed with update?";
55
+ readonly APP_UPDATE_CANCELLED: "Update cancelled.";
56
+ readonly APP_UPDATE_SUCCESS: "App updated.";
57
+ readonly APP_UPDATE_NOTHING_TO_UPDATE: "Nothing to update. Provide --app-id with --name or --redirect-url, or run from a scaffolded project directory.";
58
+ readonly APP_UPDATE_NO_APP_RESOLVED: "Cannot determine which app to update. Provide --app-id or run from a directory with app-config.json.";
59
+ readonly APP_UPDATE_APP_ID_MISMATCH: (flagId: string, configId: string) => string;
60
+ readonly APP_DELETE_CONFIRM: (name: string, id: string) => string;
61
+ readonly APP_DELETE_SUCCESS: (id: string) => string;
62
+ readonly APP_DELETE_CANCELLED: "Delete cancelled.";
63
+ readonly APP_DELETE_FOLDER_CONFIRM: (dir: string) => string;
64
+ readonly APP_DELETE_FOLDER_SUCCESS: (dir: string) => string;
65
+ readonly APP_DELETE_FOLDER_FAILED: (dir: string) => string;
66
+ readonly APP_SCAFFOLD_DIR_PROMPT: "Output directory:";
67
+ readonly APP_SCAFFOLD_DIR_EXISTS: "Directory already exists. What would you like to do?";
68
+ readonly APP_SCAFFOLD_ALREADY_IN_PROJECT: "Project already scaffolded in this directory (app-config.json found). Run from a different directory, or use `brevo app update` to push config changes.";
69
+ readonly APP_SCAFFOLD_SUCCESS: (count: number) => string;
70
+ readonly APP_SCAFFOLD_NEXT_STEPS_TITLE: "Next steps";
71
+ readonly APP_SCAFFOLD_NEXT_STEPS_LINES: (dir: string) => string[];
72
+ readonly APP_TEST_MISSING_CREDENTIALS: "Run `brevo app scaffold` to set up a project with credentials.";
73
+ readonly APP_TEST_CODE_RECEIVED: "Authorization code received. Exchanging for tokens...";
74
+ readonly APP_TEST_COMPLETE: "OAuth flow complete. Tokens are live above. Press Ctrl+C to stop.";
75
+ readonly APP_TEST_PORT_IN_USE: (port: number) => string;
76
+ readonly APP_TEST_STARTING: (port: number) => string;
77
+ readonly APP_TEST_REDIRECT_URI: (uri: string) => string;
78
+ readonly APP_TEST_BROWSER_OPEN: "Opening browser for authorization...";
79
+ readonly APP_TEST_WAITING: "Waiting for OAuth callback...";
80
+ readonly APP_TEST_ACCESS_TOKEN: (expiresIn: number) => string;
81
+ readonly APP_TEST_REFRESH_TOKEN_RECEIVED: "Refresh token received";
82
+ readonly APP_TEST_TOKENS_IN_BROWSER: (port: number) => string;
83
+ readonly APP_TEST_TOKEN_REFRESH_URL: (port: number) => string;
84
+ readonly APP_TEST_TOKEN_REFRESHED: (expiresIn: number) => string;
85
+ readonly APP_START_FEATURE_NOT_FOUND: (entryFile: string) => string;
86
+ readonly APP_START_NO_DEPS: (featureDir: string) => string;
87
+ readonly APP_START_STOPPED: "Process stopped.";
88
+ readonly APP_START_MISSING_FEATURE: (available: string) => string;
89
+ readonly APP_START_UNKNOWN_FEATURE: (feature: string, available: string) => string;
90
+ readonly APP_START_PORT_IN_USE: (port: number) => string;
91
+ readonly APP_START_CUSTOM_PORT_IN_USE: (port: number) => string;
92
+ readonly APP_START_EXITED: (feature: string, code: number) => string;
93
+ readonly APP_START_FAILED: (feature: string, error: string) => string;
94
+ readonly AUTH_LOGOUT_NON_INTERACTIVE: "Cannot prompt for confirmation in non-interactive mode. Use --force to skip.";
95
+ readonly ERR_NETWORK: "Cannot reach Brevo API.";
96
+ readonly ERR_RATE_LIMITED: (retryAfter: number) => string;
97
+ readonly ERR_REGISTRY: "Operation failed due to a registry error. Please try again.";
98
+ readonly ERR_AUTH_GATEWAY: "API is behind an authentication gateway (e.g. Cloudflare Access). Sign in via your browser first, or check your API base URL.";
99
+ readonly TLS_VERIFICATION_DISABLED: "TLS certificate verification is disabled (NODE_TLS_REJECT_UNAUTHORIZED=0). This is insecure — API keys and tokens can be intercepted on the network.";
100
+ readonly INIT_WELCOME: "Brevo CLI — Quick Setup";
101
+ readonly INIT_ALREADY_LOGGED_IN: "Already authenticated.";
102
+ readonly INIT_STEP_LOGIN: " Step 1: Authenticate with your Brevo account";
103
+ readonly INIT_STEP_CREATE: " Step 2: Create your first OAuth app";
104
+ readonly INIT_APPS_EXIST: (count: number) => string;
105
+ readonly INIT_APP_LINKED: (name: string) => string;
106
+ readonly INIT_APP_ACTION: "What would you like to do?";
107
+ readonly INIT_DONE: `All set! Run \`${string}\` to test your OAuth flow, or \`brevo --help\` to see all commands.`;
108
+ readonly ABORTED: "Aborted.";
109
+ };
110
+ //# sourceMappingURL=en.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/lang/en.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;;;;mCAKG,MAAM;;kCAEP,MAAM,WAAW,MAAM;gCAEzB,MAAM;;;;;gDAKU,MAAM;;;;;;;8CASR,MAAM;;kDAGF,MAAM;;;;;2CAUb,MAAM,WAAW,MAAM;;kDAGhB,MAAM,EAAE;;;;;;;;;;4CAcd,MAAM,aAAa,MAAM;iDAEpB,MAAM;;;;;;;;;;;oDAqBH,MAAM;yDAED,MAAM;;;;;;;kDAUb,MAAM,YAAY,MAAM;wCAIlC,MAAM,MAAM,MAAM;sCAEpB,MAAM;;8CAEE,MAAM;8CACN,MAAM;6CACP,MAAM;;;;2CAMR,MAAM;;kDAEC,MAAM;;;;0CAWd,MAAM;uCACT,MAAM;0CACH,MAAM;;;gDAGA,MAAM;;gDAEN,MAAM;gDAEN,MAAM;mDACH,MAAM;sDAIH,MAAM;6CAEf,MAAM;;oDAGC,MAAM;kDAER,MAAM,aAAa,MAAM;2CAEhC,MAAM;kDAEC,MAAM;yCAEf,MAAM,QAAQ,MAAM;yCACpB,MAAM,SAAS,MAAM;;;4CAOlB,MAAM;;;;;;;;sCAcZ,MAAM;qCACP,MAAM;;;;CAMtB,CAAC"}