@sendly/cli 1.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.
- package/README.md +323 -0
- package/bin/run.js +5 -0
- package/dist/commands/config/get.d.ts +13 -0
- package/dist/commands/config/get.js +38 -0
- package/dist/commands/config/list.d.ts +10 -0
- package/dist/commands/config/list.js +45 -0
- package/dist/commands/config/set.d.ts +14 -0
- package/dist/commands/config/set.js +67 -0
- package/dist/commands/credits/balance.d.ts +10 -0
- package/dist/commands/credits/balance.js +38 -0
- package/dist/commands/credits/history.d.ts +11 -0
- package/dist/commands/credits/history.js +88 -0
- package/dist/commands/doctor.d.ts +23 -0
- package/dist/commands/doctor.js +336 -0
- package/dist/commands/keys/create.d.ts +12 -0
- package/dist/commands/keys/create.js +47 -0
- package/dist/commands/keys/list.d.ts +10 -0
- package/dist/commands/keys/list.js +65 -0
- package/dist/commands/keys/revoke.d.ts +15 -0
- package/dist/commands/keys/revoke.js +68 -0
- package/dist/commands/login.d.ts +12 -0
- package/dist/commands/login.js +114 -0
- package/dist/commands/logout.d.ts +10 -0
- package/dist/commands/logout.js +20 -0
- package/dist/commands/logs/tail.d.ts +17 -0
- package/dist/commands/logs/tail.js +183 -0
- package/dist/commands/sms/batch.d.ts +16 -0
- package/dist/commands/sms/batch.js +163 -0
- package/dist/commands/sms/cancel.d.ts +13 -0
- package/dist/commands/sms/cancel.js +46 -0
- package/dist/commands/sms/get.d.ts +13 -0
- package/dist/commands/sms/get.js +51 -0
- package/dist/commands/sms/list.d.ts +12 -0
- package/dist/commands/sms/list.js +79 -0
- package/dist/commands/sms/schedule.d.ts +14 -0
- package/dist/commands/sms/schedule.js +91 -0
- package/dist/commands/sms/scheduled.d.ts +12 -0
- package/dist/commands/sms/scheduled.js +82 -0
- package/dist/commands/sms/send.d.ts +13 -0
- package/dist/commands/sms/send.js +70 -0
- package/dist/commands/webhooks/list.d.ts +10 -0
- package/dist/commands/webhooks/list.js +80 -0
- package/dist/commands/webhooks/listen.d.ts +20 -0
- package/dist/commands/webhooks/listen.js +202 -0
- package/dist/commands/whoami.d.ts +10 -0
- package/dist/commands/whoami.js +51 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +27 -0
- package/dist/lib/api-client.d.ts +52 -0
- package/dist/lib/api-client.js +129 -0
- package/dist/lib/auth.d.ts +52 -0
- package/dist/lib/auth.js +171 -0
- package/dist/lib/base-command.d.ts +17 -0
- package/dist/lib/base-command.js +60 -0
- package/dist/lib/config.d.ts +54 -0
- package/dist/lib/config.js +182 -0
- package/dist/lib/output.d.ts +43 -0
- package/dist/lib/output.js +222 -0
- package/oclif.manifest.json +1147 -0
- package/package.json +98 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sendly CLI
|
|
3
|
+
*
|
|
4
|
+
* The official command-line interface for Sendly SMS API.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```bash
|
|
8
|
+
* # Install
|
|
9
|
+
* npm install -g @sendly/cli
|
|
10
|
+
*
|
|
11
|
+
* # Login
|
|
12
|
+
* sendly login
|
|
13
|
+
*
|
|
14
|
+
* # Send an SMS
|
|
15
|
+
* sendly sms send --to +15551234567 --text "Hello from Sendly!"
|
|
16
|
+
*
|
|
17
|
+
* # List messages
|
|
18
|
+
* sendly sms list
|
|
19
|
+
*
|
|
20
|
+
* # Listen for webhooks locally
|
|
21
|
+
* sendly webhooks listen --forward http://localhost:3000/webhook
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @packageDocumentation
|
|
25
|
+
*/
|
|
26
|
+
export { run } from "@oclif/core";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sendly CLI
|
|
3
|
+
*
|
|
4
|
+
* The official command-line interface for Sendly SMS API.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```bash
|
|
8
|
+
* # Install
|
|
9
|
+
* npm install -g @sendly/cli
|
|
10
|
+
*
|
|
11
|
+
* # Login
|
|
12
|
+
* sendly login
|
|
13
|
+
*
|
|
14
|
+
* # Send an SMS
|
|
15
|
+
* sendly sms send --to +15551234567 --text "Hello from Sendly!"
|
|
16
|
+
*
|
|
17
|
+
* # List messages
|
|
18
|
+
* sendly sms list
|
|
19
|
+
*
|
|
20
|
+
* # Listen for webhooks locally
|
|
21
|
+
* sendly webhooks listen --forward http://localhost:3000/webhook
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @packageDocumentation
|
|
25
|
+
*/
|
|
26
|
+
export { run } from "@oclif/core";
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXdCRztBQUVILE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxhQUFhLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlbmRseSBDTElcbiAqXG4gKiBUaGUgb2ZmaWNpYWwgY29tbWFuZC1saW5lIGludGVyZmFjZSBmb3IgU2VuZGx5IFNNUyBBUEkuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYGJhc2hcbiAqICMgSW5zdGFsbFxuICogbnBtIGluc3RhbGwgLWcgQHNlbmRseS9jbGlcbiAqXG4gKiAjIExvZ2luXG4gKiBzZW5kbHkgbG9naW5cbiAqXG4gKiAjIFNlbmQgYW4gU01TXG4gKiBzZW5kbHkgc21zIHNlbmQgLS10byArMTU1NTEyMzQ1NjcgLS10ZXh0IFwiSGVsbG8gZnJvbSBTZW5kbHkhXCJcbiAqXG4gKiAjIExpc3QgbWVzc2FnZXNcbiAqIHNlbmRseSBzbXMgbGlzdFxuICpcbiAqICMgTGlzdGVuIGZvciB3ZWJob29rcyBsb2NhbGx5XG4gKiBzZW5kbHkgd2ViaG9va3MgbGlzdGVuIC0tZm9yd2FyZCBodHRwOi8vbG9jYWxob3N0OjMwMDAvd2ViaG9va1xuICogYGBgXG4gKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKi9cblxuZXhwb3J0IHsgcnVuIH0gZnJvbSBcIkBvY2xpZi9jb3JlXCI7XG4iXX0=
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for Sendly CLI
|
|
3
|
+
* Handles all HTTP requests to the Sendly API
|
|
4
|
+
*/
|
|
5
|
+
export interface ApiResponse<T> {
|
|
6
|
+
data?: T;
|
|
7
|
+
error?: {
|
|
8
|
+
code: string;
|
|
9
|
+
message: string;
|
|
10
|
+
details?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface RateLimitInfo {
|
|
14
|
+
limit: number;
|
|
15
|
+
remaining: number;
|
|
16
|
+
reset: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class ApiError extends Error {
|
|
19
|
+
code: string;
|
|
20
|
+
statusCode: number;
|
|
21
|
+
details?: Record<string, unknown> | undefined;
|
|
22
|
+
constructor(code: string, message: string, statusCode: number, details?: Record<string, unknown> | undefined);
|
|
23
|
+
}
|
|
24
|
+
export declare class AuthenticationError extends ApiError {
|
|
25
|
+
constructor(message?: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class RateLimitError extends ApiError {
|
|
28
|
+
retryAfter: number;
|
|
29
|
+
constructor(retryAfter: number, message?: string);
|
|
30
|
+
}
|
|
31
|
+
export declare class InsufficientCreditsError extends ApiError {
|
|
32
|
+
constructor(message?: string);
|
|
33
|
+
}
|
|
34
|
+
declare class ApiClient {
|
|
35
|
+
private rateLimitInfo?;
|
|
36
|
+
private getBaseUrl;
|
|
37
|
+
private getHeaders;
|
|
38
|
+
request<T>(method: string, path: string, options?: {
|
|
39
|
+
body?: Record<string, unknown>;
|
|
40
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
41
|
+
requireAuth?: boolean;
|
|
42
|
+
}): Promise<T>;
|
|
43
|
+
private updateRateLimitInfo;
|
|
44
|
+
private handleError;
|
|
45
|
+
getRateLimitInfo(): RateLimitInfo | undefined;
|
|
46
|
+
get<T>(path: string, query?: Record<string, string | number | boolean | undefined>, requireAuth?: boolean): Promise<T>;
|
|
47
|
+
post<T>(path: string, body?: Record<string, unknown>, requireAuth?: boolean): Promise<T>;
|
|
48
|
+
patch<T>(path: string, body?: Record<string, unknown>, requireAuth?: boolean): Promise<T>;
|
|
49
|
+
delete<T>(path: string, requireAuth?: boolean): Promise<T>;
|
|
50
|
+
}
|
|
51
|
+
export declare const apiClient: ApiClient;
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Client for Sendly CLI
|
|
3
|
+
* Handles all HTTP requests to the Sendly API
|
|
4
|
+
*/
|
|
5
|
+
import { getAuthToken, getConfigValue } from "./config.js";
|
|
6
|
+
export class ApiError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
statusCode;
|
|
9
|
+
details;
|
|
10
|
+
constructor(code, message, statusCode, details) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.statusCode = statusCode;
|
|
14
|
+
this.details = details;
|
|
15
|
+
this.name = "ApiError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class AuthenticationError extends ApiError {
|
|
19
|
+
constructor(message = "Not authenticated. Run 'sendly login' first.") {
|
|
20
|
+
super("authentication_error", message, 401);
|
|
21
|
+
this.name = "AuthenticationError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class RateLimitError extends ApiError {
|
|
25
|
+
retryAfter;
|
|
26
|
+
constructor(retryAfter, message = "Rate limit exceeded") {
|
|
27
|
+
super("rate_limit_exceeded", message, 429);
|
|
28
|
+
this.retryAfter = retryAfter;
|
|
29
|
+
this.name = "RateLimitError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class InsufficientCreditsError extends ApiError {
|
|
33
|
+
constructor(message = "Insufficient credits") {
|
|
34
|
+
super("insufficient_credits", message, 402);
|
|
35
|
+
this.name = "InsufficientCreditsError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
class ApiClient {
|
|
39
|
+
rateLimitInfo;
|
|
40
|
+
getBaseUrl() {
|
|
41
|
+
return getConfigValue("baseUrl") || "https://sendly.live";
|
|
42
|
+
}
|
|
43
|
+
getHeaders(requireAuth = true) {
|
|
44
|
+
const headers = {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
Accept: "application/json",
|
|
47
|
+
"User-Agent": "@sendly/cli/1.0.0",
|
|
48
|
+
};
|
|
49
|
+
if (requireAuth) {
|
|
50
|
+
const token = getAuthToken();
|
|
51
|
+
if (!token) {
|
|
52
|
+
throw new AuthenticationError();
|
|
53
|
+
}
|
|
54
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
55
|
+
}
|
|
56
|
+
return headers;
|
|
57
|
+
}
|
|
58
|
+
async request(method, path, options = {}) {
|
|
59
|
+
const { body, query, requireAuth = true } = options;
|
|
60
|
+
const url = new URL(`${this.getBaseUrl()}${path}`);
|
|
61
|
+
if (query) {
|
|
62
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
63
|
+
if (value !== undefined) {
|
|
64
|
+
url.searchParams.append(key, String(value));
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const response = await fetch(url.toString(), {
|
|
69
|
+
method,
|
|
70
|
+
headers: this.getHeaders(requireAuth),
|
|
71
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
72
|
+
});
|
|
73
|
+
// Update rate limit info
|
|
74
|
+
this.updateRateLimitInfo(response.headers);
|
|
75
|
+
// Parse response
|
|
76
|
+
const data = await response.json().catch(() => ({}));
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
this.handleError(response.status, data);
|
|
79
|
+
}
|
|
80
|
+
return data;
|
|
81
|
+
}
|
|
82
|
+
updateRateLimitInfo(headers) {
|
|
83
|
+
const limit = headers.get("X-RateLimit-Limit");
|
|
84
|
+
const remaining = headers.get("X-RateLimit-Remaining");
|
|
85
|
+
const reset = headers.get("X-RateLimit-Reset");
|
|
86
|
+
if (limit && remaining && reset) {
|
|
87
|
+
this.rateLimitInfo = {
|
|
88
|
+
limit: parseInt(limit, 10),
|
|
89
|
+
remaining: parseInt(remaining, 10),
|
|
90
|
+
reset: parseInt(reset, 10),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
handleError(statusCode, data) {
|
|
95
|
+
const error = data?.error || "unknown_error";
|
|
96
|
+
const message = data?.message || `HTTP ${statusCode}`;
|
|
97
|
+
const details = data?.details;
|
|
98
|
+
switch (statusCode) {
|
|
99
|
+
case 401:
|
|
100
|
+
case 403:
|
|
101
|
+
throw new AuthenticationError(message);
|
|
102
|
+
case 402:
|
|
103
|
+
throw new InsufficientCreditsError(message);
|
|
104
|
+
case 429:
|
|
105
|
+
const retryAfter = data?.retryAfter || 60;
|
|
106
|
+
throw new RateLimitError(retryAfter, message);
|
|
107
|
+
default:
|
|
108
|
+
throw new ApiError(error, message, statusCode, details);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getRateLimitInfo() {
|
|
112
|
+
return this.rateLimitInfo;
|
|
113
|
+
}
|
|
114
|
+
// Convenience methods
|
|
115
|
+
async get(path, query, requireAuth = true) {
|
|
116
|
+
return this.request("GET", path, { query, requireAuth });
|
|
117
|
+
}
|
|
118
|
+
async post(path, body, requireAuth = true) {
|
|
119
|
+
return this.request("POST", path, { body, requireAuth });
|
|
120
|
+
}
|
|
121
|
+
async patch(path, body, requireAuth = true) {
|
|
122
|
+
return this.request("PATCH", path, { body, requireAuth });
|
|
123
|
+
}
|
|
124
|
+
async delete(path, requireAuth = true) {
|
|
125
|
+
return this.request("DELETE", path, { requireAuth });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
export const apiClient = new ApiClient();
|
|
129
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvYXBpLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQUUsWUFBWSxFQUFFLGNBQWMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQWlCM0QsTUFBTSxPQUFPLFFBQVMsU0FBUSxLQUFLO0lBRXhCO0lBRUE7SUFDQTtJQUpULFlBQ1MsSUFBWSxFQUNuQixPQUFlLEVBQ1IsVUFBa0IsRUFDbEIsT0FBaUM7UUFFeEMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBTFIsU0FBSSxHQUFKLElBQUksQ0FBUTtRQUVaLGVBQVUsR0FBVixVQUFVLENBQVE7UUFDbEIsWUFBTyxHQUFQLE9BQU8sQ0FBMEI7UUFHeEMsSUFBSSxDQUFDLElBQUksR0FBRyxVQUFVLENBQUM7SUFDekIsQ0FBQztDQUNGO0FBRUQsTUFBTSxPQUFPLG1CQUFvQixTQUFRLFFBQVE7SUFDL0MsWUFBWSxVQUFrQiw4Q0FBOEM7UUFDMUUsS0FBSyxDQUFDLHNCQUFzQixFQUFFLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM1QyxJQUFJLENBQUMsSUFBSSxHQUFHLHFCQUFxQixDQUFDO0lBQ3BDLENBQUM7Q0FDRjtBQUVELE1BQU0sT0FBTyxjQUFlLFNBQVEsUUFBUTtJQUVqQztJQURULFlBQ1MsVUFBa0IsRUFDekIsVUFBa0IscUJBQXFCO1FBRXZDLEtBQUssQ0FBQyxxQkFBcUIsRUFBRSxPQUFPLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFIcEMsZUFBVSxHQUFWLFVBQVUsQ0FBUTtRQUl6QixJQUFJLENBQUMsSUFBSSxHQUFHLGdCQUFnQixDQUFDO0lBQy9CLENBQUM7Q0FDRjtBQUVELE1BQU0sT0FBTyx3QkFBeUIsU0FBUSxRQUFRO0lBQ3BELFlBQVksVUFBa0Isc0JBQXNCO1FBQ2xELEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxPQUFPLEVBQUUsR0FB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QU8sQ0FBSSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJLENBQ1IsSUFBWSxFQUNaLElBQThCLEVBQzlCLGNBQXVCLElBQUk7UUFFM0IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFJLE1BQU0sRUFBRSxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUM5RCxDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUssQ0FDVCxJQUFZLEVBQ1osSUFBOEIsRUFDOUIsY0FBdUIsSUFBSTtRQUUzQixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUksT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFRCxLQUFLLENBQUMsTUFBTSxDQUFJLElBQVksRUFBRSxjQUF1QixJQUFJO1FBQ3ZELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBSSxRQUFRLEVBQUUsSUFBSSxFQUFFLEVBQUUsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUMxRCxDQUFDO0NBQ0Y7QUFFRCxNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQVBJIENsaWVudCBmb3IgU2VuZGx5IENMSVxuICogSGFuZGxlcyBhbGwgSFRUUCByZXF1ZXN0cyB0byB0aGUgU2VuZGx5IEFQSVxuICovXG5cbmltcG9ydCB7IGdldEF1dGhUb2tlbiwgZ2V0Q29uZmlnVmFsdWUgfSBmcm9tIFwiLi9jb25maWcuanNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBBcGlSZXNwb25zZTxUPiB7XG4gIGRhdGE/OiBUO1xuICBlcnJvcj86IHtcbiAgICBjb2RlOiBzdHJpbmc7XG4gICAgbWVzc2FnZTogc3RyaW5nO1xuICAgIGRldGFpbHM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgfTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSYXRlTGltaXRJbmZvIHtcbiAgbGltaXQ6IG51bWJlcjtcbiAgcmVtYWluaW5nOiBudW1iZXI7XG4gIHJlc2V0OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBBcGlFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGNvZGU6IHN0cmluZyxcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgcHVibGljIHN0YXR1c0NvZGU6IG51bWJlcixcbiAgICBwdWJsaWMgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+XG4gICkge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9IFwiQXBpRXJyb3JcIjtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgQXV0aGVudGljYXRpb25FcnJvciBleHRlbmRzIEFwaUVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nID0gXCJOb3QgYXV0aGVudGljYXRlZC4gUnVuICdzZW5kbHkgbG9naW4nIGZpcnN0LlwiKSB7XG4gICAgc3VwZXIoXCJhdXRoZW50aWNhdGlvbl9lcnJvclwiLCBtZXNzYWdlLCA0MDEpO1xuICAgIHRoaXMubmFtZSA9IFwiQXV0aGVudGljYXRpb25FcnJvclwiO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBSYXRlTGltaXRFcnJvciBleHRlbmRzIEFwaUVycm9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIHJldHJ5QWZ0ZXI6IG51bWJlcixcbiAgICBtZXNzYWdlOiBzdHJpbmcgPSBcIlJhdGUgbGltaXQgZXhjZWVkZWRcIlxuICApIHtcbiAgICBzdXBlcihcInJhdGVfbGltaXRfZXhjZWVkZWRcIiwgbWVzc2FnZSwgNDI5KTtcbiAgICB0aGlzLm5hbWUgPSBcIlJhdGVMaW1pdEVycm9yXCI7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEluc3VmZmljaWVudENyZWRpdHNFcnJvciBleHRlbmRzIEFwaUVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZTogc3RyaW5nID0gXCJJbnN1ZmZpY2llbnQgY3JlZGl0c1wiKSB7XG4gICAgc3VwZXIoXCJpbnN1ZmZpY2llbnRfY3JlZGl0c1wiLCBtZXNzYWdlLCA0MDIpO1xuICAgIHRoaXMubmFtZSA9IFwiSW5zdWZmaWNpZW50Q3JlZGl0c0Vycm9yXCI7XG4gIH1cbn1cblxuY2xhc3MgQXBpQ2xpZW50IHtcbiAgcHJpdmF0ZSByYXRlTGltaXRJbmZvPzogUmF0ZUxpbWl0SW5mbztcblxuICBwcml2YXRlIGdldEJhc2VVcmwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gZ2V0Q29uZmlnVmFsdWUoXCJiYXNlVXJsXCIpIHx8IFwiaHR0cHM6Ly9zZW5kbHkubGl2ZVwiO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRIZWFkZXJzKHJlcXVpcmVBdXRoOiBib29sZWFuID0gdHJ1ZSk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICAgIGNvbnN0IGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgIEFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICBcIlVzZXItQWdlbnRcIjogXCJAc2VuZGx5L2NsaS8xLjAuMFwiLFxuICAgIH07XG5cbiAgICBpZiAocmVxdWlyZUF1dGgpIHtcbiAgICAgIGNvbnN0IHRva2VuID0gZ2V0QXV0aFRva2VuKCk7XG4gICAgICBpZiAoIXRva2VuKSB7XG4gICAgICAgIHRocm93IG5ldyBBdXRoZW50aWNhdGlvbkVycm9yKCk7XG4gICAgICB9XG4gICAgICBoZWFkZXJzW1wiQXV0aG9yaXphdGlvblwiXSA9IGBCZWFyZXIgJHt0b2tlbn1gO1xuICAgIH1cblxuICAgIHJldHVybiBoZWFkZXJzO1xuICB9XG5cbiAgYXN5bmMgcmVxdWVzdDxUPihcbiAgICBtZXRob2Q6IHN0cmluZyxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczoge1xuICAgICAgYm9keT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgcXVlcnk/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHwgdW5kZWZpbmVkPjtcbiAgICAgIHJlcXVpcmVBdXRoPzogYm9vbGVhbjtcbiAgICB9ID0ge31cbiAgKTogUHJvbWlzZTxUPiB7XG4gICAgY29uc3QgeyBib2R5LCBxdWVyeSwgcmVxdWlyZUF1dGggPSB0cnVlIH0gPSBvcHRpb25zO1xuXG4gICAgY29uc3QgdXJsID0gbmV3IFVSTChgJHt0aGlzLmdldEJhc2VVcmwoKX0ke3BhdGh9YCk7XG4gICAgaWYgKHF1ZXJ5KSB7XG4gICAgICBPYmplY3QuZW50cmllcyhxdWVyeSkuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgdXJsLnNlYXJjaFBhcmFtcy5hcHBlbmQoa2V5LCBTdHJpbmcodmFsdWUpKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwudG9TdHJpbmcoKSwge1xuICAgICAgbWV0aG9kLFxuICAgICAgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKHJlcXVpcmVBdXRoKSxcbiAgICAgIGJvZHk6IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZCxcbiAgICB9KTtcblxuICAgIC8vIFVwZGF0ZSByYXRlIGxpbWl0IGluZm9cbiAgICB0aGlzLnVwZGF0ZVJhdGVMaW1pdEluZm8ocmVzcG9uc2UuaGVhZGVycyk7XG5cbiAgICAvLyBQYXJzZSByZXNwb25zZVxuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCkuY2F0Y2goKCkgPT4gKHt9KSk7XG5cbiAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICB0aGlzLmhhbmRsZUVycm9yKHJlc3BvbnNlLnN0YXR1cywgZGF0YSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRhdGEgYXMgVDtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlUmF0ZUxpbWl0SW5mbyhoZWFkZXJzOiBIZWFkZXJzKTogdm9pZCB7XG4gICAgY29uc3QgbGltaXQgPSBoZWFkZXJzLmdldChcIlgtUmF0ZUxpbWl0LUxpbWl0XCIpO1xuICAgIGNvbnN0IHJlbWFpbmluZyA9IGhlYWRlcnMuZ2V0KFwiWC1SYXRlTGltaXQtUmVtYWluaW5nXCIpO1xuICAgIGNvbnN0IHJlc2V0ID0gaGVhZGVycy5nZXQoXCJYLVJhdGVMaW1pdC1SZXNldFwiKTtcblxuICAgIGlmIChsaW1pdCAmJiByZW1haW5pbmcgJiYgcmVzZXQpIHtcbiAgICAgIHRoaXMucmF0ZUxpbWl0SW5mbyA9IHtcbiAgICAgICAgbGltaXQ6IHBhcnNlSW50KGxpbWl0LCAxMCksXG4gICAgICAgIHJlbWFpbmluZzogcGFyc2VJbnQocmVtYWluaW5nLCAxMCksXG4gICAgICAgIHJlc2V0OiBwYXJzZUludChyZXNldCwgMTApLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVycm9yKHN0YXR1c0NvZGU6IG51bWJlciwgZGF0YTogYW55KTogbmV2ZXIge1xuICAgIGNvbnN0IGVycm9yID0gZGF0YT8uZXJyb3IgfHwgXCJ1bmtub3duX2Vycm9yXCI7XG4gICAgY29uc3QgbWVzc2FnZSA9IGRhdGE/Lm1lc3NhZ2UgfHwgYEhUVFAgJHtzdGF0dXNDb2RlfWA7XG4gICAgY29uc3QgZGV0YWlscyA9IGRhdGE/LmRldGFpbHM7XG5cbiAgICBzd2l0Y2ggKHN0YXR1c0NvZGUpIHtcbiAgICAgIGNhc2UgNDAxOlxuICAgICAgY2FzZSA0MDM6XG4gICAgICAgIHRocm93IG5ldyBBdXRoZW50aWNhdGlvbkVycm9yKG1lc3NhZ2UpO1xuICAgICAgY2FzZSA0MDI6XG4gICAgICAgIHRocm93IG5ldyBJbnN1ZmZpY2llbnRDcmVkaXRzRXJyb3IobWVzc2FnZSk7XG4gICAgICBjYXNlIDQyOTpcbiAgICAgICAgY29uc3QgcmV0cnlBZnRlciA9IGRhdGE/LnJldHJ5QWZ0ZXIgfHwgNjA7XG4gICAgICAgIHRocm93IG5ldyBSYXRlTGltaXRFcnJvcihyZXRyeUFmdGVyLCBtZXNzYWdlKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBBcGlFcnJvcihlcnJvciwgbWVzc2FnZSwgc3RhdHVzQ29kZSwgZGV0YWlscyk7XG4gICAgfVxuICB9XG5cbiAgZ2V0UmF0ZUxpbWl0SW5mbygpOiBSYXRlTGltaXRJbmZvIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5yYXRlTGltaXRJbmZvO1xuICB9XG5cbiAgLy8gQ29udmVuaWVuY2UgbWV0aG9kc1xuICBhc3luYyBnZXQ8VD4oXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIHF1ZXJ5PzogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IHVuZGVmaW5lZD4sXG4gICAgcmVxdWlyZUF1dGg6IGJvb2xlYW4gPSB0cnVlXG4gICk6IFByb21pc2U8VD4ge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3Q8VD4oXCJHRVRcIiwgcGF0aCwgeyBxdWVyeSwgcmVxdWlyZUF1dGggfSk7XG4gIH1cblxuICBhc3luYyBwb3N0PFQ+KFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBib2R5PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICAgcmVxdWlyZUF1dGg6IGJvb2xlYW4gPSB0cnVlXG4gICk6IFByb21pc2U8VD4ge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3Q8VD4oXCJQT1NUXCIsIHBhdGgsIHsgYm9keSwgcmVxdWlyZUF1dGggfSk7XG4gIH1cblxuICBhc3luYyBwYXRjaDxUPihcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgYm9keT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIHJlcXVpcmVBdXRoOiBib29sZWFuID0gdHJ1ZVxuICApOiBQcm9taXNlPFQ+IHtcbiAgICByZXR1cm4gdGhpcy5yZXF1ZXN0PFQ+KFwiUEFUQ0hcIiwgcGF0aCwgeyBib2R5LCByZXF1aXJlQXV0aCB9KTtcbiAgfVxuXG4gIGFzeW5jIGRlbGV0ZTxUPihwYXRoOiBzdHJpbmcsIHJlcXVpcmVBdXRoOiBib29sZWFuID0gdHJ1ZSk6IFByb21pc2U8VD4ge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3Q8VD4oXCJERUxFVEVcIiwgcGF0aCwgeyByZXF1aXJlQXV0aCB9KTtcbiAgfVxufVxuXG5leHBvcnQgY29uc3QgYXBpQ2xpZW50ID0gbmV3IEFwaUNsaWVudCgpO1xuIl19
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication utilities for CLI
|
|
3
|
+
* Handles browser-based login flow and API key authentication
|
|
4
|
+
*/
|
|
5
|
+
export interface DeviceCodeResponse {
|
|
6
|
+
deviceCode: string;
|
|
7
|
+
userCode: string;
|
|
8
|
+
verificationUrl: string;
|
|
9
|
+
expiresIn: number;
|
|
10
|
+
interval: number;
|
|
11
|
+
}
|
|
12
|
+
export interface TokenResponse {
|
|
13
|
+
accessToken: string;
|
|
14
|
+
refreshToken: string;
|
|
15
|
+
expiresIn: number;
|
|
16
|
+
userId: string;
|
|
17
|
+
email: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a device code for browser-based authentication
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateDeviceCode(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Generate a secure device code for the auth flow
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateSecureCode(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Start the browser-based login flow
|
|
29
|
+
*/
|
|
30
|
+
export declare function browserLogin(): Promise<TokenResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Login with an API key directly
|
|
33
|
+
*/
|
|
34
|
+
export declare function apiKeyLogin(apiKey: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Logout - clear all stored credentials
|
|
37
|
+
*/
|
|
38
|
+
export declare function logout(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Check if currently authenticated
|
|
41
|
+
*/
|
|
42
|
+
export declare function checkAuth(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get current auth info for display
|
|
45
|
+
*/
|
|
46
|
+
export declare function getAuthInfo(): Promise<{
|
|
47
|
+
authenticated: boolean;
|
|
48
|
+
email?: string;
|
|
49
|
+
userId?: string;
|
|
50
|
+
environment: string;
|
|
51
|
+
keyType?: string;
|
|
52
|
+
}>;
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication utilities for CLI
|
|
3
|
+
* Handles browser-based login flow and API key authentication
|
|
4
|
+
*/
|
|
5
|
+
import open from "open";
|
|
6
|
+
import * as crypto from "node:crypto";
|
|
7
|
+
import { setAuthTokens, setApiKey, clearAuth, getConfigValue, isAuthenticated, getAuthToken, } from "./config.js";
|
|
8
|
+
import { colors, spinner } from "./output.js";
|
|
9
|
+
const DEVICE_CODE_LENGTH = 8;
|
|
10
|
+
const POLL_INTERVAL = 2000; // 2 seconds
|
|
11
|
+
const MAX_POLL_ATTEMPTS = 150; // 5 minutes max
|
|
12
|
+
/**
|
|
13
|
+
* Generate a device code for browser-based authentication
|
|
14
|
+
*/
|
|
15
|
+
export function generateDeviceCode() {
|
|
16
|
+
return crypto.randomBytes(4).toString("hex").toUpperCase();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generate a secure device code for the auth flow
|
|
20
|
+
*/
|
|
21
|
+
export function generateSecureCode() {
|
|
22
|
+
const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // Exclude confusing chars
|
|
23
|
+
let code = "";
|
|
24
|
+
const bytes = crypto.randomBytes(DEVICE_CODE_LENGTH);
|
|
25
|
+
for (let i = 0; i < DEVICE_CODE_LENGTH; i++) {
|
|
26
|
+
code += chars[bytes[i] % chars.length];
|
|
27
|
+
}
|
|
28
|
+
return code;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Start the browser-based login flow
|
|
32
|
+
*/
|
|
33
|
+
export async function browserLogin() {
|
|
34
|
+
const baseUrl = getConfigValue("baseUrl") || "https://sendly.live";
|
|
35
|
+
const deviceCode = generateSecureCode();
|
|
36
|
+
const userCode = `${deviceCode.slice(0, 4)}-${deviceCode.slice(4)}`;
|
|
37
|
+
// Request device code from server
|
|
38
|
+
const response = await fetch(`${baseUrl}/api/cli/auth/device-code`, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: { "Content-Type": "application/json" },
|
|
41
|
+
body: JSON.stringify({ deviceCode }),
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const error = (await response.json().catch(() => ({})));
|
|
45
|
+
throw new Error(error.message || "Failed to initiate login");
|
|
46
|
+
}
|
|
47
|
+
const data = (await response.json());
|
|
48
|
+
// Display instructions to user
|
|
49
|
+
console.log();
|
|
50
|
+
console.log(colors.bold("Login to Sendly"));
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(`Open this URL in your browser:`);
|
|
53
|
+
console.log(colors.primary(` ${data.verificationUrl}`));
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(`And enter this code:`);
|
|
56
|
+
console.log(colors.bold(colors.primary(` ${userCode}`)));
|
|
57
|
+
console.log();
|
|
58
|
+
// Try to open browser automatically
|
|
59
|
+
try {
|
|
60
|
+
await open(data.verificationUrl);
|
|
61
|
+
console.log(colors.dim("Browser opened automatically"));
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
console.log(colors.dim("Please open the URL manually"));
|
|
65
|
+
}
|
|
66
|
+
console.log();
|
|
67
|
+
// Poll for token
|
|
68
|
+
const spin = spinner("Waiting for authorization...");
|
|
69
|
+
spin.start();
|
|
70
|
+
let attempts = 0;
|
|
71
|
+
while (attempts < MAX_POLL_ATTEMPTS) {
|
|
72
|
+
await sleep(data.interval * 1000 || POLL_INTERVAL);
|
|
73
|
+
attempts++;
|
|
74
|
+
try {
|
|
75
|
+
const tokenResponse = await fetch(`${baseUrl}/api/cli/auth/token`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: { "Content-Type": "application/json" },
|
|
78
|
+
body: JSON.stringify({ deviceCode }),
|
|
79
|
+
});
|
|
80
|
+
if (tokenResponse.ok) {
|
|
81
|
+
const tokens = (await tokenResponse.json());
|
|
82
|
+
spin.succeed("Logged in successfully!");
|
|
83
|
+
// Store tokens
|
|
84
|
+
setAuthTokens(tokens.accessToken, tokens.refreshToken, tokens.expiresIn, tokens.userId, tokens.email);
|
|
85
|
+
return tokens;
|
|
86
|
+
}
|
|
87
|
+
const errorData = (await tokenResponse.json().catch(() => ({})));
|
|
88
|
+
if (errorData.error === "authorization_pending") {
|
|
89
|
+
// Still waiting, continue polling
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (errorData.error === "expired_token") {
|
|
93
|
+
spin.fail("Login request expired. Please try again.");
|
|
94
|
+
throw new Error("Login request expired");
|
|
95
|
+
}
|
|
96
|
+
if (errorData.error === "access_denied") {
|
|
97
|
+
spin.fail("Login was denied");
|
|
98
|
+
throw new Error("Login was denied");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (error.message.includes("expired") ||
|
|
103
|
+
error.message.includes("denied")) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
// Network error, continue polling
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
spin.fail("Login timed out. Please try again.");
|
|
110
|
+
throw new Error("Login timed out");
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Login with an API key directly
|
|
114
|
+
*/
|
|
115
|
+
export async function apiKeyLogin(apiKey) {
|
|
116
|
+
const baseUrl = getConfigValue("baseUrl") || "https://sendly.live";
|
|
117
|
+
// Validate the API key with the server
|
|
118
|
+
const response = await fetch(`${baseUrl}/api/cli/auth/verify-key`, {
|
|
119
|
+
method: "POST",
|
|
120
|
+
headers: {
|
|
121
|
+
"Content-Type": "application/json",
|
|
122
|
+
Authorization: `Bearer ${apiKey}`,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
const error = (await response.json().catch(() => ({})));
|
|
127
|
+
throw new Error(error.message || "Invalid API key");
|
|
128
|
+
}
|
|
129
|
+
// Store the API key
|
|
130
|
+
setApiKey(apiKey);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Logout - clear all stored credentials
|
|
134
|
+
*/
|
|
135
|
+
export function logout() {
|
|
136
|
+
clearAuth();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check if currently authenticated
|
|
140
|
+
*/
|
|
141
|
+
export function checkAuth() {
|
|
142
|
+
return isAuthenticated();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get current auth info for display
|
|
146
|
+
*/
|
|
147
|
+
export async function getAuthInfo() {
|
|
148
|
+
const token = getAuthToken();
|
|
149
|
+
const email = getConfigValue("email");
|
|
150
|
+
const userId = getConfigValue("userId");
|
|
151
|
+
const apiKey = getConfigValue("apiKey");
|
|
152
|
+
const environment = getConfigValue("environment");
|
|
153
|
+
if (!token && !apiKey) {
|
|
154
|
+
return { authenticated: false, environment };
|
|
155
|
+
}
|
|
156
|
+
let keyType;
|
|
157
|
+
if (apiKey) {
|
|
158
|
+
keyType = apiKey.startsWith("sk_test_") ? "test" : "live";
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
authenticated: true,
|
|
162
|
+
email,
|
|
163
|
+
userId,
|
|
164
|
+
environment,
|
|
165
|
+
keyType,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function sleep(ms) {
|
|
169
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvYXV0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFFeEIsT0FBTyxLQUFLLE1BQU0sTUFBTSxhQUFhLENBQUM7QUFDdEMsT0FBTyxFQUNMLGFBQWEsRUFDYixTQUFTLEVBQ1QsU0FBUyxFQUNULGNBQWMsRUFDZCxlQUFlLEVBQ2YsWUFBWSxHQUNiLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTlDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxDQUFDO0FBQzdCLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxDQUFDLFlBQVk7QUFDeEMsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUMsQ0FBQyxnQkFBZ0I7QUFrQi9DOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQjtJQUNoQyxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQzdELENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxrQkFBa0I7SUFDaEMsTUFBTSxLQUFLLEdBQUcsa0NBQWtDLENBQUMsQ0FBQywwQkFBMEI7SUFDNUUsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ2QsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ3JELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxrQkFBa0IsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzVDLElBQUksSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6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O0FBQzNELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEF1dGhlbnRpY2F0aW9uIHV0aWxpdGllcyBmb3IgQ0xJXG4gKiBIYW5kbGVzIGJyb3dzZXItYmFzZWQgbG9naW4gZmxvdyBhbmQgQVBJIGtleSBhdXRoZW50aWNhdGlvblxuICovXG5cbmltcG9ydCBvcGVuIGZyb20gXCJvcGVuXCI7XG5pbXBvcnQgKiBhcyBodHRwIGZyb20gXCJub2RlOmh0dHBcIjtcbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB7XG4gIHNldEF1dGhUb2tlbnMsXG4gIHNldEFwaUtleSxcbiAgY2xlYXJBdXRoLFxuICBnZXRDb25maWdWYWx1ZSxcbiAgaXNBdXRoZW50aWNhdGVkLFxuICBnZXRBdXRoVG9rZW4sXG59IGZyb20gXCIuL2NvbmZpZy5qc1wiO1xuaW1wb3J0IHsgY29sb3JzLCBzcGlubmVyIH0gZnJvbSBcIi4vb3V0cHV0LmpzXCI7XG5cbmNvbnN0IERFVklDRV9DT0RFX0xFTkdUSCA9IDg7XG5jb25zdCBQT0xMX0lOVEVSVkFMID0gMjAwMDsgLy8gMiBzZWNvbmRzXG5jb25zdCBNQVhfUE9MTF9BVFRFTVBUUyA9IDE1MDsgLy8gNSBtaW51dGVzIG1heFxuXG5leHBvcnQgaW50ZXJmYWNlIERldmljZUNvZGVSZXNwb25zZSB7XG4gIGRldmljZUNvZGU6IHN0cmluZztcbiAgdXNlckNvZGU6IHN0cmluZztcbiAgdmVyaWZpY2F0aW9uVXJsOiBzdHJpbmc7XG4gIGV4cGlyZXNJbjogbnVtYmVyO1xuICBpbnRlcnZhbDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRva2VuUmVzcG9uc2Uge1xuICBhY2Nlc3NUb2tlbjogc3RyaW5nO1xuICByZWZyZXNoVG9rZW46IHN0cmluZztcbiAgZXhwaXJlc0luOiBudW1iZXI7XG4gIHVzZXJJZDogc3RyaW5nO1xuICBlbWFpbDogc3RyaW5nO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgZGV2aWNlIGNvZGUgZm9yIGJyb3dzZXItYmFzZWQgYXV0aGVudGljYXRpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlRGV2aWNlQ29kZSgpOiBzdHJpbmcge1xuICByZXR1cm4gY3J5cHRvLnJhbmRvbUJ5dGVzKDQpLnRvU3RyaW5nKFwiaGV4XCIpLnRvVXBwZXJDYXNlKCk7XG59XG5cbi8qKlxuICogR2VuZXJhdGUgYSBzZWN1cmUgZGV2aWNlIGNvZGUgZm9yIHRoZSBhdXRoIGZsb3dcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlU2VjdXJlQ29kZSgpOiBzdHJpbmcge1xuICBjb25zdCBjaGFycyA9IFwiQUJDREVGR0hKS0xNTlBRUlNUVVZXWFlaMjM0NTY3ODlcIjsgLy8gRXhjbHVkZSBjb25mdXNpbmcgY2hhcnNcbiAgbGV0IGNvZGUgPSBcIlwiO1xuICBjb25zdCBieXRlcyA9IGNyeXB0by5yYW5kb21CeXRlcyhERVZJQ0VfQ09ERV9MRU5HVEgpO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IERFVklDRV9DT0RFX0xFTkdUSDsgaSsrKSB7XG4gICAgY29kZSArPSBjaGFyc1tieXRlc1tpXSAlIGNoYXJzLmxlbmd0aF07XG4gIH1cbiAgcmV0dXJuIGNvZGU7XG59XG5cbi8qKlxuICogU3RhcnQgdGhlIGJyb3dzZXItYmFzZWQgbG9naW4gZmxvd1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYnJvd3NlckxvZ2luKCk6IFByb21pc2U8VG9rZW5SZXNwb25zZT4ge1xuICBjb25zdCBiYXNlVXJsID0gZ2V0Q29uZmlnVmFsdWUoXCJiYXNlVXJsXCIpIHx8IFwiaHR0cHM6Ly9zZW5kbHkubGl2ZVwiO1xuICBjb25zdCBkZXZpY2VDb2RlID0gZ2VuZXJhdGVTZWN1cmVDb2RlKCk7XG4gIGNvbnN0IHVzZXJDb2RlID0gYCR7ZGV2aWNlQ29kZS5zbGljZSgwLCA0KX0tJHtkZXZpY2VDb2RlLnNsaWNlKDQpfWA7XG5cbiAgLy8gUmVxdWVzdCBkZXZpY2UgY29kZSBmcm9tIHNlcnZlclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke2Jhc2VVcmx9L2FwaS9jbGkvYXV0aC9kZXZpY2UtY29kZWAsIHtcbiAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgIGhlYWRlcnM6IHsgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfSxcbiAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7IGRldmljZUNvZGUgfSksXG4gIH0pO1xuXG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICBjb25zdCBlcnJvciA9IChhd2FpdCByZXNwb25zZS5qc29uKCkuY2F0Y2goKCkgPT4gKHt9KSkpIGFzIHtcbiAgICAgIG1lc3NhZ2U/OiBzdHJpbmc7XG4gICAgfTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3IubWVzc2FnZSB8fCBcIkZhaWxlZCB0byBpbml0aWF0ZSBsb2dpblwiKTtcbiAgfVxuXG4gIGNvbnN0IGRhdGEgPSAoYXdhaXQgcmVzcG9uc2UuanNvbigpKSBhcyBEZXZpY2VDb2RlUmVzcG9uc2U7XG5cbiAgLy8gRGlzcGxheSBpbnN0cnVjdGlvbnMgdG8gdXNlclxuICBjb25zb2xlLmxvZygpO1xuICBjb25zb2xlLmxvZyhjb2xvcnMuYm9sZChcIkxvZ2luIHRvIFNlbmRseVwiKSk7XG4gIGNvbnNvbGUubG9nKCk7XG4gIGNvbnNvbGUubG9nKGBPcGVuIHRoaXMgVVJMIGluIHlvdXIgYnJvd3NlcjpgKTtcbiAgY29uc29sZS5sb2coY29sb3JzLnByaW1hcnkoYCAgJHtkYXRhLnZlcmlmaWNhdGlvblVybH1gKSk7XG4gIGNvbnNvbGUubG9nKCk7XG4gIGNvbnNvbGUubG9nKGBBbmQgZW50ZXIgdGhpcyBjb2RlOmApO1xuICBjb25zb2xlLmxvZyhjb2xvcnMuYm9sZChjb2xvcnMucHJpbWFyeShgICAke3VzZXJDb2RlfWApKSk7XG4gIGNvbnNvbGUubG9nKCk7XG5cbiAgLy8gVHJ5IHRvIG9wZW4gYnJvd3NlciBhdXRvbWF0aWNhbGx5XG4gIHRyeSB7XG4gICAgYXdhaXQgb3BlbihkYXRhLnZlcmlmaWNhdGlvblVybCk7XG4gICAgY29uc29sZS5sb2coY29sb3JzLmRpbShcIkJyb3dzZXIgb3BlbmVkIGF1dG9tYXRpY2FsbHlcIikpO1xuICB9IGNhdGNoIHtcbiAgICBjb25zb2xlLmxvZyhjb2xvcnMuZGltKFwiUGxlYXNlIG9wZW4gdGhlIFVSTCBtYW51YWxseVwiKSk7XG4gIH1cblxuICBjb25zb2xlLmxvZygpO1xuXG4gIC8vIFBvbGwgZm9yIHRva2VuXG4gIGNvbnN0IHNwaW4gPSBzcGlubmVyKFwiV2FpdGluZyBmb3IgYXV0aG9yaXphdGlvbi4uLlwiKTtcbiAgc3Bpbi5zdGFydCgpO1xuXG4gIGxldCBhdHRlbXB0cyA9IDA7XG4gIHdoaWxlIChhdHRlbXB0cyA8IE1BWF9QT0xMX0FUVEVNUFRTKSB7XG4gICAgYXdhaXQgc2xlZXAoZGF0YS5pbnRlcnZhbCAqIDEwMDAgfHwgUE9MTF9JTlRFUlZBTCk7XG4gICAgYXR0ZW1wdHMrKztcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB0b2tlblJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7YmFzZVVybH0vYXBpL2NsaS9hdXRoL3Rva2VuYCwge1xuICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICBoZWFkZXJzOiB7IFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiIH0sXG4gICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgZGV2aWNlQ29kZSB9KSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodG9rZW5SZXNwb25zZS5vaykge1xuICAgICAgICBjb25zdCB0b2tlbnMgPSAoYXdhaXQgdG9rZW5SZXNwb25zZS5qc29uKCkpIGFzIFRva2VuUmVzcG9uc2U7XG4gICAgICAgIHNwaW4uc3VjY2VlZChcIkxvZ2dlZCBpbiBzdWNjZXNzZnVsbHkhXCIpO1xuXG4gICAgICAgIC8vIFN0b3JlIHRva2Vuc1xuICAgICAgICBzZXRBdXRoVG9rZW5zKFxuICAgICAgICAgIHRva2Vucy5hY2Nlc3NUb2tlbixcbiAgICAgICAgICB0b2tlbnMucmVmcmVzaFRva2VuLFxuICAgICAgICAgIHRva2Vucy5leHBpcmVzSW4sXG4gICAgICAgICAgdG9rZW5zLnVzZXJJZCxcbiAgICAgICAgICB0b2tlbnMuZW1haWwsXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIHRva2VucztcbiAgICAgIH1cblxuICAgICAgY29uc3QgZXJyb3JEYXRhID0gKGF3YWl0IHRva2VuUmVzcG9uc2UuanNvbigpLmNhdGNoKCgpID0+ICh7fSkpKSBhcyB7XG4gICAgICAgIGVycm9yPzogc3RyaW5nO1xuICAgICAgfTtcblxuICAgICAgaWYgKGVycm9yRGF0YS5lcnJvciA9PT0gXCJhdXRob3JpemF0aW9uX3BlbmRpbmdcIikge1xuICAgICAgICAvLyBTdGlsbCB3YWl0aW5nLCBjb250aW51ZSBwb2xsaW5nXG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXJyb3JEYXRhLmVycm9yID09PSBcImV4cGlyZWRfdG9rZW5cIikge1xuICAgICAgICBzcGluLmZhaWwoXCJMb2dpbiByZXF1ZXN0IGV4cGlyZWQuIFBsZWFzZSB0cnkgYWdhaW4uXCIpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJMb2dpbiByZXF1ZXN0IGV4cGlyZWRcIik7XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvckRhdGEuZXJyb3IgPT09IFwiYWNjZXNzX2RlbmllZFwiKSB7XG4gICAgICAgIHNwaW4uZmFpbChcIkxvZ2luIHdhcyBkZW5pZWRcIik7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkxvZ2luIHdhcyBkZW5pZWRcIik7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChcbiAgICAgICAgKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlLmluY2x1ZGVzKFwiZXhwaXJlZFwiKSB8fFxuICAgICAgICAoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2UuaW5jbHVkZXMoXCJkZW5pZWRcIilcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICAgIC8vIE5ldHdvcmsgZXJyb3IsIGNvbnRpbnVlIHBvbGxpbmdcbiAgICB9XG4gIH1cblxuICBzcGluLmZhaWwoXCJMb2dpbiB0aW1lZCBvdXQuIFBsZWFzZSB0cnkgYWdhaW4uXCIpO1xuICB0aHJvdyBuZXcgRXJyb3IoXCJMb2dpbiB0aW1lZCBvdXRcIik7XG59XG5cbi8qKlxuICogTG9naW4gd2l0aCBhbiBBUEkga2V5IGRpcmVjdGx5XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhcGlLZXlMb2dpbihhcGlLZXk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBiYXNlVXJsID0gZ2V0Q29uZmlnVmFsdWUoXCJiYXNlVXJsXCIpIHx8IFwiaHR0cHM6Ly9zZW5kbHkubGl2ZVwiO1xuXG4gIC8vIFZhbGlkYXRlIHRoZSBBUEkga2V5IHdpdGggdGhlIHNlcnZlclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke2Jhc2VVcmx9L2FwaS9jbGkvYXV0aC92ZXJpZnkta2V5YCwge1xuICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgaGVhZGVyczoge1xuICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7YXBpS2V5fWAsXG4gICAgfSxcbiAgfSk7XG5cbiAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgIGNvbnN0IGVycm9yID0gKGF3YWl0IHJlc3BvbnNlLmpzb24oKS5jYXRjaCgoKSA9PiAoe30pKSkgYXMge1xuICAgICAgbWVzc2FnZT86IHN0cmluZztcbiAgICB9O1xuICAgIHRocm93IG5ldyBFcnJvcihlcnJvci5tZXNzYWdlIHx8IFwiSW52YWxpZCBBUEkga2V5XCIpO1xuICB9XG5cbiAgLy8gU3RvcmUgdGhlIEFQSSBrZXlcbiAgc2V0QXBpS2V5KGFwaUtleSk7XG59XG5cbi8qKlxuICogTG9nb3V0IC0gY2xlYXIgYWxsIHN0b3JlZCBjcmVkZW50aWFsc1xuICovXG5leHBvcnQgZnVuY3Rpb24gbG9nb3V0KCk6IHZvaWQge1xuICBjbGVhckF1dGgoKTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBjdXJyZW50bHkgYXV0aGVudGljYXRlZFxuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tBdXRoKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gaXNBdXRoZW50aWNhdGVkKCk7XG59XG5cbi8qKlxuICogR2V0IGN1cnJlbnQgYXV0aCBpbmZvIGZvciBkaXNwbGF5XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRBdXRoSW5mbygpOiBQcm9taXNlPHtcbiAgYXV0aGVudGljYXRlZDogYm9vbGVhbjtcbiAgZW1haWw/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbiAgZW52aXJvbm1lbnQ6IHN0cmluZztcbiAga2V5VHlwZT86IHN0cmluZztcbn0+IHtcbiAgY29uc3QgdG9rZW4gPSBnZXRBdXRoVG9rZW4oKTtcbiAgY29uc3QgZW1haWwgPSBnZXRDb25maWdWYWx1ZShcImVtYWlsXCIpO1xuICBjb25zdCB1c2VySWQgPSBnZXRDb25maWdWYWx1ZShcInVzZXJJZFwiKTtcbiAgY29uc3QgYXBpS2V5ID0gZ2V0Q29uZmlnVmFsdWUoXCJhcGlLZXlcIik7XG4gIGNvbnN0IGVudmlyb25tZW50ID0gZ2V0Q29uZmlnVmFsdWUoXCJlbnZpcm9ubWVudFwiKTtcblxuICBpZiAoIXRva2VuICYmICFhcGlLZXkpIHtcbiAgICByZXR1cm4geyBhdXRoZW50aWNhdGVkOiBmYWxzZSwgZW52aXJvbm1lbnQgfTtcbiAgfVxuXG4gIGxldCBrZXlUeXBlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGlmIChhcGlLZXkpIHtcbiAgICBrZXlUeXBlID0gYXBpS2V5LnN0YXJ0c1dpdGgoXCJza190ZXN0X1wiKSA/IFwidGVzdFwiIDogXCJsaXZlXCI7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGF1dGhlbnRpY2F0ZWQ6IHRydWUsXG4gICAgZW1haWwsXG4gICAgdXNlcklkLFxuICAgIGVudmlyb25tZW50LFxuICAgIGtleVR5cGUsXG4gIH07XG59XG5cbmZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG59XG4iXX0=
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Command class for all Sendly CLI commands
|
|
3
|
+
* Provides common functionality and flags
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from "@oclif/core";
|
|
6
|
+
export declare abstract class BaseCommand extends Command {
|
|
7
|
+
static baseFlags: {
|
|
8
|
+
json: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
9
|
+
quiet: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
protected init(): Promise<void>;
|
|
12
|
+
protected catch(err: Error): Promise<void>;
|
|
13
|
+
protected requireAuth(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare abstract class AuthenticatedCommand extends BaseCommand {
|
|
16
|
+
protected init(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Command class for all Sendly CLI commands
|
|
3
|
+
* Provides common functionality and flags
|
|
4
|
+
*/
|
|
5
|
+
import { Command, Flags } from "@oclif/core";
|
|
6
|
+
import { setOutputFormat, setQuietMode, error } from "./output.js";
|
|
7
|
+
import { isAuthenticated } from "./config.js";
|
|
8
|
+
import { ApiError, AuthenticationError } from "./api-client.js";
|
|
9
|
+
export class BaseCommand extends Command {
|
|
10
|
+
static baseFlags = {
|
|
11
|
+
json: Flags.boolean({
|
|
12
|
+
description: "Output in JSON format",
|
|
13
|
+
default: false,
|
|
14
|
+
}),
|
|
15
|
+
quiet: Flags.boolean({
|
|
16
|
+
char: "q",
|
|
17
|
+
description: "Minimal output",
|
|
18
|
+
default: false,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
async init() {
|
|
22
|
+
await super.init();
|
|
23
|
+
const { flags } = await this.parse(this.constructor);
|
|
24
|
+
if (flags.json) {
|
|
25
|
+
setOutputFormat("json");
|
|
26
|
+
}
|
|
27
|
+
if (flags.quiet) {
|
|
28
|
+
setQuietMode(true);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async catch(err) {
|
|
32
|
+
if (err instanceof AuthenticationError) {
|
|
33
|
+
error("Not authenticated", {
|
|
34
|
+
hint: "Run 'sendly login' to authenticate",
|
|
35
|
+
});
|
|
36
|
+
this.exit(1);
|
|
37
|
+
}
|
|
38
|
+
if (err instanceof ApiError) {
|
|
39
|
+
error(err.message, {
|
|
40
|
+
code: err.code,
|
|
41
|
+
...(err.details || {}),
|
|
42
|
+
});
|
|
43
|
+
this.exit(1);
|
|
44
|
+
}
|
|
45
|
+
error(err.message);
|
|
46
|
+
this.exit(1);
|
|
47
|
+
}
|
|
48
|
+
requireAuth() {
|
|
49
|
+
if (!isAuthenticated()) {
|
|
50
|
+
throw new AuthenticationError();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export class AuthenticatedCommand extends BaseCommand {
|
|
55
|
+
async init() {
|
|
56
|
+
await super.init();
|
|
57
|
+
this.requireAuth();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1jb21tYW5kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpYi9iYXNlLWNvbW1hbmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ25FLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDOUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWhFLE1BQU0sT0FBZ0IsV0FBWSxTQUFRLE9BQU87SUFDL0MsTUFBTSxDQUFDLFNBQVMsR0FBRztRQUNqQixJQUFJLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQztZQUNsQixXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLE9BQU8sRUFBRSxLQUFLO1NBQ2YsQ0FBQztRQUNGLEtBQUssRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDO1lBQ25CLElBQUksRUFBRSxHQUFHO1lBQ1QsV0FBVyxFQUFFLGdCQUFnQjtZQUM3QixPQUFPLEVBQUUsS0FBSztTQUNmLENBQUM7S0FDSCxDQUFDO0lBRVEsS0FBSyxDQUFDLElBQUk7UUFDbEIsTUFBTSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbkIsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBaUMsQ0FBQyxDQUFDO1FBRTNFLElBQUksS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2YsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzFCLENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNoQixZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDckIsQ0FBQztJQUNILENBQUM7SUFFUyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQVU7UUFDOUIsSUFBSSxHQUFHLFlBQVksbUJBQW1CLEVBQUUsQ0FBQztZQUN2QyxLQUFLLENBQUMsbUJBQW1CLEVBQUU7Z0JBQ3pCLElBQUksRUFBRSxvQ0FBb0M7YUFDM0MsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNmLENBQUM7UUFFRCxJQUFJLEdBQUcsWUFBWSxRQUFRLEVBQUUsQ0FBQztZQUM1QixLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRTtnQkFDakIsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO2dCQUNkLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQzthQUN2QixDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2YsQ0FBQztRQUVELEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkIsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNmLENBQUM7SUFFUyxXQUFXO1FBQ25CLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1FBQ2xDLENBQUM7SUFDSCxDQUFDOztBQUdILE1BQU0sT0FBZ0Isb0JBQXFCLFNBQVEsV0FBVztJQUNsRCxLQUFLLENBQUMsSUFBSTtRQUNsQixNQUFNLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDckIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCYXNlIENvbW1hbmQgY2xhc3MgZm9yIGFsbCBTZW5kbHkgQ0xJIGNvbW1hbmRzXG4gKiBQcm92aWRlcyBjb21tb24gZnVuY3Rpb25hbGl0eSBhbmQgZmxhZ3NcbiAqL1xuXG5pbXBvcnQgeyBDb21tYW5kLCBGbGFncyB9IGZyb20gXCJAb2NsaWYvY29yZVwiO1xuaW1wb3J0IHsgc2V0T3V0cHV0Rm9ybWF0LCBzZXRRdWlldE1vZGUsIGVycm9yIH0gZnJvbSBcIi4vb3V0cHV0LmpzXCI7XG5pbXBvcnQgeyBpc0F1dGhlbnRpY2F0ZWQgfSBmcm9tIFwiLi9jb25maWcuanNcIjtcbmltcG9ydCB7IEFwaUVycm9yLCBBdXRoZW50aWNhdGlvbkVycm9yIH0gZnJvbSBcIi4vYXBpLWNsaWVudC5qc1wiO1xuXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQmFzZUNvbW1hbmQgZXh0ZW5kcyBDb21tYW5kIHtcbiAgc3RhdGljIGJhc2VGbGFncyA9IHtcbiAgICBqc29uOiBGbGFncy5ib29sZWFuKHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcIk91dHB1dCBpbiBKU09OIGZvcm1hdFwiLFxuICAgICAgZGVmYXVsdDogZmFsc2UsXG4gICAgfSksXG4gICAgcXVpZXQ6IEZsYWdzLmJvb2xlYW4oe1xuICAgICAgY2hhcjogXCJxXCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJNaW5pbWFsIG91dHB1dFwiLFxuICAgICAgZGVmYXVsdDogZmFsc2UsXG4gICAgfSksXG4gIH07XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGluaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc3VwZXIuaW5pdCgpO1xuICAgIGNvbnN0IHsgZmxhZ3MgfSA9IGF3YWl0IHRoaXMucGFyc2UodGhpcy5jb25zdHJ1Y3RvciBhcyB0eXBlb2YgQmFzZUNvbW1hbmQpO1xuXG4gICAgaWYgKGZsYWdzLmpzb24pIHtcbiAgICAgIHNldE91dHB1dEZvcm1hdChcImpzb25cIik7XG4gICAgfVxuICAgIGlmIChmbGFncy5xdWlldCkge1xuICAgICAgc2V0UXVpZXRNb2RlKHRydWUpO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBjYXRjaChlcnI6IEVycm9yKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKGVyciBpbnN0YW5jZW9mIEF1dGhlbnRpY2F0aW9uRXJyb3IpIHtcbiAgICAgIGVycm9yKFwiTm90IGF1dGhlbnRpY2F0ZWRcIiwge1xuICAgICAgICBoaW50OiBcIlJ1biAnc2VuZGx5IGxvZ2luJyB0byBhdXRoZW50aWNhdGVcIixcbiAgICAgIH0pO1xuICAgICAgdGhpcy5leGl0KDEpO1xuICAgIH1cblxuICAgIGlmIChlcnIgaW5zdGFuY2VvZiBBcGlFcnJvcikge1xuICAgICAgZXJyb3IoZXJyLm1lc3NhZ2UsIHtcbiAgICAgICAgY29kZTogZXJyLmNvZGUsXG4gICAgICAgIC4uLihlcnIuZGV0YWlscyB8fCB7fSksXG4gICAgICB9KTtcbiAgICAgIHRoaXMuZXhpdCgxKTtcbiAgICB9XG5cbiAgICBlcnJvcihlcnIubWVzc2FnZSk7XG4gICAgdGhpcy5leGl0KDEpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHJlcXVpcmVBdXRoKCk6IHZvaWQge1xuICAgIGlmICghaXNBdXRoZW50aWNhdGVkKCkpIHtcbiAgICAgIHRocm93IG5ldyBBdXRoZW50aWNhdGlvbkVycm9yKCk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBBdXRoZW50aWNhdGVkQ29tbWFuZCBleHRlbmRzIEJhc2VDb21tYW5kIHtcbiAgcHJvdGVjdGVkIGFzeW5jIGluaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc3VwZXIuaW5pdCgpO1xuICAgIHRoaXMucmVxdWlyZUF1dGgoKTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Configuration Management
|
|
3
|
+
* Stores user preferences and credentials in ~/.sendly/
|
|
4
|
+
*
|
|
5
|
+
* Environment Variables (take precedence over config file):
|
|
6
|
+
* - SENDLY_API_KEY: API key for authentication
|
|
7
|
+
* - SENDLY_BASE_URL: Custom API endpoint
|
|
8
|
+
* - SENDLY_OUTPUT_FORMAT: Default output format (human/json)
|
|
9
|
+
* - SENDLY_NO_COLOR: Disable colored output (any value)
|
|
10
|
+
* - SENDLY_TIMEOUT: Request timeout in ms (default: 30000)
|
|
11
|
+
* - SENDLY_MAX_RETRIES: Max retry attempts (default: 3)
|
|
12
|
+
* - CI: Auto-detect CI mode (disables interactive prompts)
|
|
13
|
+
*/
|
|
14
|
+
import Conf from "conf";
|
|
15
|
+
export interface SendlyConfig {
|
|
16
|
+
apiKey?: string;
|
|
17
|
+
accessToken?: string;
|
|
18
|
+
refreshToken?: string;
|
|
19
|
+
tokenExpiresAt?: number;
|
|
20
|
+
userId?: string;
|
|
21
|
+
email?: string;
|
|
22
|
+
environment: "test" | "live";
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
defaultFormat: "human" | "json";
|
|
25
|
+
colorEnabled: boolean;
|
|
26
|
+
timeout: number;
|
|
27
|
+
maxRetries: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if running in CI environment
|
|
31
|
+
*/
|
|
32
|
+
export declare function isCI(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Check if color output is disabled
|
|
35
|
+
*/
|
|
36
|
+
export declare function isColorDisabled(): boolean;
|
|
37
|
+
declare const config: Conf<SendlyConfig>;
|
|
38
|
+
/**
|
|
39
|
+
* Get effective config value with environment variable override
|
|
40
|
+
* Priority: env var > config file > default
|
|
41
|
+
*/
|
|
42
|
+
export declare function getEffectiveValue<K extends keyof SendlyConfig>(key: K): SendlyConfig[K];
|
|
43
|
+
export declare function getConfig(): SendlyConfig;
|
|
44
|
+
export declare function setConfig<K extends keyof SendlyConfig>(key: K, value: SendlyConfig[K]): void;
|
|
45
|
+
export declare function getConfigValue<K extends keyof SendlyConfig>(key: K): SendlyConfig[K];
|
|
46
|
+
export declare function clearConfig(): void;
|
|
47
|
+
export declare function clearAuth(): void;
|
|
48
|
+
export declare function isAuthenticated(): boolean;
|
|
49
|
+
export declare function getAuthToken(): string | undefined;
|
|
50
|
+
export declare function setApiKey(apiKey: string): void;
|
|
51
|
+
export declare function setAuthTokens(accessToken: string, refreshToken: string, expiresIn: number, userId: string, email: string): void;
|
|
52
|
+
export declare function getConfigPath(): string;
|
|
53
|
+
export declare function getConfigDir(): string;
|
|
54
|
+
export { config };
|