teamclaws 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/dist/auth.js ADDED
@@ -0,0 +1,330 @@
1
+ import { ACCESS_TOKEN_MAX_LIFETIME_SECONDS, API_BASE, API_RESOURCE, OAUTH_CLIENT_ID, OAUTH_DEVICE_AUTHORIZATION_URL, OAUTH_LOGIN_TIMEOUT_MS, OAUTH_REVOKE_URL, OAUTH_TOKEN_URL, TEAMCLAWS_ORIGIN, } from "./constants.js";
2
+ import { TeamClawsError } from "./errors.js";
3
+ import { errorFromResponse, requestJson } from "./http.js";
4
+ import { assertExactKeys, isObject, parseSafeUserResponse, requireHttpsUrl, requireInteger, requireString, } from "./validation.js";
5
+ import { openExternalBrowser } from "./browser.js";
6
+ const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
7
+ export class AuthService {
8
+ fetcher;
9
+ store;
10
+ output;
11
+ openBrowser;
12
+ now;
13
+ wait;
14
+ loginTimeoutMs;
15
+ constructor(options) {
16
+ this.fetcher = options.fetcher ?? fetch;
17
+ this.store = options.store;
18
+ this.output = options.output;
19
+ this.openBrowser = options.openBrowser ?? openExternalBrowser;
20
+ this.now = options.now ?? Date.now;
21
+ this.wait = options.wait ?? waitFor;
22
+ this.loginTimeoutMs = options.loginTimeoutMs ?? OAUTH_LOGIN_TIMEOUT_MS;
23
+ }
24
+ async login(email, signal) {
25
+ const boundEmail = email === undefined ? undefined : parseLoginEmail(email);
26
+ const pending = await this.startDevice(boundEmail, signal);
27
+ this.output.loginBrowser(pending.verification_uri_complete);
28
+ await this.openBrowser(pending.verification_uri_complete).catch(() => false);
29
+ const credential = await this.poll(pending, signal);
30
+ const user = await this.fetchIdentity(credential.access_token, signal);
31
+ await this.store.writeLogin(credential);
32
+ this.output.loginComplete(user);
33
+ return user;
34
+ }
35
+ async status(signal) {
36
+ const credential = await this.store.readLogin();
37
+ if (!credential) {
38
+ this.output.authStatus("signed_out");
39
+ return undefined;
40
+ }
41
+ try {
42
+ const active = await this.ensureActive(credential, signal);
43
+ const user = await this.fetchIdentity(active.access_token, signal);
44
+ this.output.authStatus("signed_in", user, active.expires_at);
45
+ return user;
46
+ }
47
+ catch (error) {
48
+ if (error instanceof TeamClawsError &&
49
+ error.code === "invalid_authentication") {
50
+ await this.store.removeLogin();
51
+ this.output.authStatus("signed_out");
52
+ return undefined;
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ async logout(signal) {
58
+ const credential = await this.store.readLogin();
59
+ let remoteConfirmed = true;
60
+ if (credential) {
61
+ try {
62
+ await this.revoke(credential.refresh_token, signal);
63
+ }
64
+ catch {
65
+ remoteConfirmed = false;
66
+ }
67
+ }
68
+ await this.store.removeLogin();
69
+ this.output.logoutComplete(remoteConfirmed);
70
+ return remoteConfirmed;
71
+ }
72
+ async accessToken(signal) {
73
+ const credential = await this.store.readLogin();
74
+ if (!credential)
75
+ return undefined;
76
+ const active = await this.ensureActive(credential, signal);
77
+ return active.access_token;
78
+ }
79
+ async ensureActive(credential, signal) {
80
+ const expiresAt = Date.parse(credential.expires_at);
81
+ if (expiresAt - this.now() > 30_000)
82
+ return credential;
83
+ const refreshed = await this.refresh(credential.refresh_token, signal);
84
+ await this.store.writeLogin(refreshed);
85
+ return refreshed;
86
+ }
87
+ async startDevice(email, signal) {
88
+ const form = new URLSearchParams({
89
+ client_id: OAUTH_CLIENT_ID,
90
+ resource: API_RESOURCE,
91
+ });
92
+ if (email)
93
+ form.set("email", email);
94
+ const response = await requestJson(this.fetcher, OAUTH_DEVICE_AUTHORIZATION_URL, {
95
+ method: "POST",
96
+ form,
97
+ ...(signal ? { signal } : {}),
98
+ });
99
+ if (response.status < 200 || response.status >= 300) {
100
+ throw oauthError(response.status, response.body);
101
+ }
102
+ return parseDeviceAuthorization(response.body);
103
+ }
104
+ async poll(pending, signal) {
105
+ const startedAt = this.now();
106
+ const deadline = Math.min(startedAt + pending.expires_in * 1_000, startedAt + this.loginTimeoutMs);
107
+ let intervalSeconds = pending.interval;
108
+ while (this.now() < deadline) {
109
+ await this.wait(intervalSeconds * 1_000, signal);
110
+ if (this.now() >= deadline)
111
+ break;
112
+ const response = await requestJson(this.fetcher, OAUTH_TOKEN_URL, {
113
+ method: "POST",
114
+ form: new URLSearchParams({
115
+ grant_type: DEVICE_CODE_GRANT_TYPE,
116
+ device_code: pending.device_code,
117
+ client_id: OAUTH_CLIENT_ID,
118
+ resource: API_RESOURCE,
119
+ }),
120
+ ...(signal ? { signal } : {}),
121
+ });
122
+ if (response.status >= 200 && response.status < 300) {
123
+ return parseTokenResponse(response.body, this.now());
124
+ }
125
+ const code = oauthErrorCode(response.body);
126
+ if (code === "authorization_pending") {
127
+ continue;
128
+ }
129
+ if (code === "slow_down") {
130
+ intervalSeconds = Math.min(intervalSeconds + 5, 60);
131
+ continue;
132
+ }
133
+ if (code === "access_denied") {
134
+ throw new TeamClawsError("login_denied", "TeamClaws denied the CLI sign-in.", { exitCode: 3 });
135
+ }
136
+ if (code === "expired_token") {
137
+ throw new TeamClawsError("login_timeout", "CLI sign-in timed out after 10 minutes.", { exitCode: 3 });
138
+ }
139
+ throw oauthError(response.status, response.body);
140
+ }
141
+ throw new TeamClawsError("login_timeout", "CLI sign-in timed out after 10 minutes.", { exitCode: 3 });
142
+ }
143
+ async refresh(refreshToken, signal) {
144
+ try {
145
+ const response = await requestJson(this.fetcher, OAUTH_TOKEN_URL, {
146
+ method: "POST",
147
+ form: new URLSearchParams({
148
+ grant_type: "refresh_token",
149
+ refresh_token: refreshToken,
150
+ client_id: OAUTH_CLIENT_ID,
151
+ resource: API_RESOURCE,
152
+ }),
153
+ ...(signal ? { signal } : {}),
154
+ });
155
+ if (response.status < 200 || response.status >= 300) {
156
+ throw oauthError(response.status, response.body);
157
+ }
158
+ return parseTokenResponse(response.body, this.now());
159
+ }
160
+ catch (error) {
161
+ if (error instanceof TeamClawsError &&
162
+ error.code === "invalid_authentication") {
163
+ await this.store.removeLogin();
164
+ }
165
+ throw error;
166
+ }
167
+ }
168
+ async fetchIdentity(accessToken, signal) {
169
+ const response = await requestJson(this.fetcher, `${API_BASE}me/`, {
170
+ headers: { Authorization: `Bearer ${accessToken}` },
171
+ ...(signal ? { signal } : {}),
172
+ });
173
+ if (response.status === 401) {
174
+ throw new TeamClawsError("invalid_authentication", "The TeamClaws login is no longer valid.", {
175
+ exitCode: 3,
176
+ });
177
+ }
178
+ if (response.status < 200 || response.status >= 300) {
179
+ throw errorFromResponse(response, "identity_unavailable");
180
+ }
181
+ return parseSafeUserResponse(response.body);
182
+ }
183
+ async revoke(refreshToken, signal) {
184
+ const timeout = AbortSignal.timeout(10_000);
185
+ const combined = signal ? AbortSignal.any([timeout, signal]) : timeout;
186
+ const response = await this.fetcher(OAUTH_REVOKE_URL, {
187
+ method: "POST",
188
+ headers: {
189
+ Accept: "application/json",
190
+ "Content-Type": "application/x-www-form-urlencoded",
191
+ },
192
+ body: new URLSearchParams({
193
+ token: refreshToken,
194
+ client_id: OAUTH_CLIENT_ID,
195
+ }),
196
+ redirect: "error",
197
+ signal: combined,
198
+ });
199
+ if (response.status < 200 || response.status >= 300) {
200
+ throw new TeamClawsError("remote_logout_unconfirmed", "Remote logout was not confirmed.");
201
+ }
202
+ }
203
+ }
204
+ function parseDeviceAuthorization(body) {
205
+ if (!isObject(body))
206
+ throw invalidTokenResponse();
207
+ assertExactKeys(body, [
208
+ "device_code",
209
+ "user_code",
210
+ "verification_uri",
211
+ "verification_uri_complete",
212
+ "expires_in",
213
+ "interval",
214
+ ], [], "device authorization response");
215
+ const deviceCode = requireToken(body.device_code);
216
+ const userCode = requireString(body.user_code, "user code", 32);
217
+ const verificationUri = trustedTeamClawsUrl(body.verification_uri, "verification address");
218
+ const verificationUriComplete = trustedTeamClawsUrl(body.verification_uri_complete, "complete verification address");
219
+ if (verificationUriComplete.origin !== verificationUri.origin ||
220
+ verificationUriComplete.pathname !== verificationUri.pathname ||
221
+ verificationUriComplete.searchParams.get("user_code") !== userCode ||
222
+ ownerUrlLeaksSecret(verificationUriComplete, deviceCode)) {
223
+ throw invalidTokenResponse();
224
+ }
225
+ return {
226
+ device_code: deviceCode,
227
+ user_code: userCode,
228
+ verification_uri: verificationUri.toString(),
229
+ verification_uri_complete: verificationUriComplete.toString(),
230
+ expires_in: requireInteger(body.expires_in, "expires_in", 1, 86_400),
231
+ interval: requireInteger(body.interval, "interval", 1, 60),
232
+ };
233
+ }
234
+ function parseTokenResponse(body, now) {
235
+ if (!isObject(body))
236
+ throw invalidTokenResponse();
237
+ const accessToken = requireToken(body.access_token);
238
+ const refreshToken = requireToken(body.refresh_token);
239
+ if (body.token_type !== "Bearer")
240
+ throw invalidTokenResponse();
241
+ const expiresIn = Math.min(requireInteger(body.expires_in, "access-token lifetime", 1, 86_400), ACCESS_TOKEN_MAX_LIFETIME_SECONDS);
242
+ return {
243
+ version: 1,
244
+ token_type: "Bearer",
245
+ access_token: accessToken,
246
+ refresh_token: refreshToken,
247
+ expires_at: new Date(now + expiresIn * 1_000).toISOString(),
248
+ };
249
+ }
250
+ function parseLoginEmail(value) {
251
+ const email = value.trim();
252
+ if (email.length < 3 ||
253
+ email.length > 254 ||
254
+ !email.includes("@") ||
255
+ email.includes(" ")) {
256
+ throw new TeamClawsError("invalid_command", "Provide a valid email address to bind this TeamClaws CLI login.", { exitCode: 2 });
257
+ }
258
+ return email;
259
+ }
260
+ function requireToken(value) {
261
+ if (typeof value !== "string" || value.length < 8 || value.length > 8_192) {
262
+ throw invalidTokenResponse();
263
+ }
264
+ return value;
265
+ }
266
+ function trustedTeamClawsUrl(value, label) {
267
+ const url = requireHttpsUrl(value, label);
268
+ if (url.origin !== TEAMCLAWS_ORIGIN)
269
+ throw invalidTokenResponse();
270
+ return url;
271
+ }
272
+ function ownerUrlLeaksSecret(url, deviceCode) {
273
+ let decoded = url.toString();
274
+ try {
275
+ decoded = decodeURIComponent(decoded);
276
+ }
277
+ catch {
278
+ return true;
279
+ }
280
+ return (decoded.includes(deviceCode) ||
281
+ /(?:access_token|refresh_token|device_code)=/iu.test(decoded));
282
+ }
283
+ function invalidTokenResponse() {
284
+ return new TeamClawsError("invalid_response", "TeamClaws returned an invalid login response.", {
285
+ exitCode: 9,
286
+ });
287
+ }
288
+ function oauthErrorCode(body) {
289
+ if (isObject(body) &&
290
+ typeof body.error === "string" &&
291
+ body.error.length <= 80) {
292
+ return body.error;
293
+ }
294
+ return "";
295
+ }
296
+ function oauthError(status, body) {
297
+ let code = "login_failed";
298
+ const error = oauthErrorCode(body);
299
+ if (error) {
300
+ code = error === "invalid_grant" ? "invalid_authentication" : error;
301
+ }
302
+ return new TeamClawsError(code, "TeamClaws rejected the login request.", {
303
+ retryable: status >= 500,
304
+ exitCode: 3,
305
+ });
306
+ }
307
+ async function waitFor(milliseconds, signal) {
308
+ await new Promise((resolve, reject) => {
309
+ if (signal?.aborted) {
310
+ reject(new TeamClawsError("cancelled", "Login was cancelled.", {
311
+ exitCode: 8,
312
+ }));
313
+ return;
314
+ }
315
+ const finish = () => {
316
+ signal?.removeEventListener("abort", onAbort);
317
+ resolve();
318
+ };
319
+ const timer = setTimeout(finish, milliseconds);
320
+ const onAbort = () => {
321
+ clearTimeout(timer);
322
+ signal?.removeEventListener("abort", onAbort);
323
+ reject(new TeamClawsError("cancelled", "Login was cancelled.", {
324
+ exitCode: 8,
325
+ }));
326
+ };
327
+ signal?.addEventListener("abort", onAbort, { once: true });
328
+ });
329
+ }
330
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/broker.js ADDED
@@ -0,0 +1,79 @@
1
+ import { hostname } from "node:os";
2
+ import { randomUUID } from "node:crypto";
3
+ import { API_BASE, CLIENT_NAME, CONTRACT_VERSION, MAX_CLIENT_LABEL_LENGTH, MAX_DEVICE_NAME_LENGTH, PACKAGE_VERSION, } from "./constants.js";
4
+ import { TeamClawsError } from "./errors.js";
5
+ import { errorFromResponse, requestJson } from "./http.js";
6
+ import { parsePendingPairing, parseServersResponse } from "./validation.js";
7
+ export class BrokerClient {
8
+ fetcher;
9
+ deviceName;
10
+ constructor(options = {}) {
11
+ this.fetcher = options.fetcher ?? fetch;
12
+ this.deviceName = options.deviceName ?? hostname;
13
+ }
14
+ currentDeviceName() {
15
+ return normalizedDeviceName(this.deviceName());
16
+ }
17
+ async servers(accessToken, signal) {
18
+ const response = await requestJson(this.fetcher, `${API_BASE}servers/`, {
19
+ headers: requestHeaders(accessToken),
20
+ ...(signal ? { signal } : {}),
21
+ });
22
+ if (response.status === 401) {
23
+ throw new TeamClawsError("invalid_authentication", "The TeamClaws login is no longer valid.", {
24
+ exitCode: 3,
25
+ });
26
+ }
27
+ if (response.status < 200 || response.status >= 300) {
28
+ throw errorFromResponse(response, "server_discovery_failed");
29
+ }
30
+ return parseServersResponse(response.body);
31
+ }
32
+ async startPairing(target, accessToken, signal) {
33
+ const request = pairingStartRequest(target, this.currentDeviceName());
34
+ const response = await requestJson(this.fetcher, `${API_BASE}pairing/start/`, {
35
+ method: "POST",
36
+ headers: requestHeaders(accessToken),
37
+ body: request,
38
+ ...(signal ? { signal } : {}),
39
+ });
40
+ if (response.status < 200 || response.status >= 300) {
41
+ throw errorFromResponse(response, "pairing_start_failed");
42
+ }
43
+ const pending = parsePendingPairing(response.body);
44
+ if ("server_id" in target && pending.server_id !== target.server_id) {
45
+ throw new TeamClawsError("target_mismatch", "TeamClaws resolved a different workspace than the one requested.", { exitCode: 9 });
46
+ }
47
+ if ("workspace_url" in target &&
48
+ pending.target.origin !== new URL(target.workspace_url).origin) {
49
+ throw new TeamClawsError("target_mismatch", "TeamClaws resolved a different workspace than the one requested.", { exitCode: 9 });
50
+ }
51
+ return pending;
52
+ }
53
+ }
54
+ export function pairingStartRequest(target, deviceName) {
55
+ return {
56
+ contract_version: CONTRACT_VERSION,
57
+ target,
58
+ request_id: randomUUID(),
59
+ device_name: deviceName,
60
+ client_name: CLIENT_NAME,
61
+ client_version: PACKAGE_VERSION,
62
+ };
63
+ }
64
+ export function normalizedDeviceName(value) {
65
+ const normalized = value
66
+ .replace(/\s+/gu, " ")
67
+ .trim()
68
+ .slice(0, MAX_DEVICE_NAME_LENGTH);
69
+ return normalized || "Unnamed computer";
70
+ }
71
+ function requestHeaders(accessToken) {
72
+ const headers = {
73
+ "User-Agent": `${CLIENT_NAME}/${PACKAGE_VERSION}`.slice(0, MAX_CLIENT_LABEL_LENGTH),
74
+ };
75
+ if (accessToken)
76
+ headers.Authorization = `Bearer ${accessToken}`;
77
+ return headers;
78
+ }
79
+ //# sourceMappingURL=broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../src/broker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function openExternalBrowser(url) {
3
+ const command = browserCommand(url);
4
+ if (!command)
5
+ return false;
6
+ return await new Promise((resolve) => {
7
+ const child = spawn(command.executable, command.arguments, {
8
+ detached: true,
9
+ stdio: "ignore",
10
+ windowsHide: true,
11
+ shell: false,
12
+ });
13
+ child.once("error", () => resolve(false));
14
+ child.once("spawn", () => {
15
+ child.unref();
16
+ resolve(true);
17
+ });
18
+ });
19
+ }
20
+ export function browserCommand(url, platform = process.platform) {
21
+ if (platform === "darwin")
22
+ return { executable: "open", arguments: [url] };
23
+ if (platform === "win32") {
24
+ return {
25
+ executable: "rundll32.exe",
26
+ arguments: ["url.dll,FileProtocolHandler", url],
27
+ };
28
+ }
29
+ if (platform === "linux")
30
+ return { executable: "xdg-open", arguments: [url] };
31
+ return undefined;
32
+ }
33
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAW;IACnD,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,EAAE;YACzD,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,QAAQ;YACf,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,WAA4B,OAAO,CAAC,QAAQ;IAE5C,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3E,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO;YACL,UAAU,EAAE,cAAc;YAC1B,SAAS,EAAE,CAAC,6BAA6B,EAAE,GAAG,CAAC;SAChD,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9E,OAAO,SAAS,CAAC;AACnB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { run } from "./app.js";
3
+ const controller = new AbortController();
4
+ const interrupt = () => controller.abort();
5
+ process.once("SIGINT", interrupt);
6
+ process.once("SIGTERM", interrupt);
7
+ try {
8
+ process.exitCode = await run(process.argv.slice(2), {}, controller.signal);
9
+ }
10
+ finally {
11
+ process.removeListener("SIGINT", interrupt);
12
+ process.removeListener("SIGTERM", interrupt);
13
+ }
14
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;AACzC,MAAM,SAAS,GAAG,GAAS,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;AACjD,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAClC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAEnC,IAAI,CAAC;IACH,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;AAC7E,CAAC;QAAS,CAAC;IACT,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC5C,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,21 @@
1
+ export const PACKAGE_NAME = "teamclaws";
2
+ export const PACKAGE_VERSION = "1.0.0";
3
+ export const CLIENT_NAME = "teamclaws-cli";
4
+ export const CONTRACT_VERSION = 1;
5
+ export const OUTPUT_SCHEMA_VERSION = 1;
6
+ export const TEAMCLAWS_ORIGIN = "https://www.teamclaws.com";
7
+ export const API_RESOURCE = `${TEAMCLAWS_ORIGIN}/api/cli/v1`;
8
+ export const API_BASE = `${API_RESOURCE}/`;
9
+ export const OAUTH_CLIENT_ID = "teamclaws-cli";
10
+ export const OAUTH_DEVICE_AUTHORIZATION_URL = `${TEAMCLAWS_ORIGIN}/o/device-authorization/`;
11
+ export const OAUTH_TOKEN_URL = `${TEAMCLAWS_ORIGIN}/o/token/`;
12
+ export const OAUTH_REVOKE_URL = `${TEAMCLAWS_ORIGIN}/o/revoke_token/`;
13
+ export const OAUTH_LOGIN_TIMEOUT_MS = 10 * 60 * 1_000;
14
+ export const ACCESS_TOKEN_MAX_LIFETIME_SECONDS = 600;
15
+ export const DEFAULT_CONNECT_TIMEOUT_MS = 10_000;
16
+ export const PAIRING_STATUS_TIMEOUT_MS = 5_000;
17
+ export const DEFAULT_RESPONSE_LIMIT_BYTES = 1_048_576;
18
+ export const MAX_DEVICE_NAME_LENGTH = 120;
19
+ export const MAX_CLIENT_LABEL_LENGTH = 120;
20
+ export const MAX_ERROR_MESSAGE_LENGTH = 300;
21
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AACxC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC;AAC3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,2BAA2B,CAAC;AAC5D,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,gBAAgB,aAAa,CAAC;AAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,YAAY,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,eAAe,GAAG,eAAe,CAAC;AAC/C,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,gBAAgB,0BAA0B,CAAC;AAC5F,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,gBAAgB,WAAW,CAAC;AAC9D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,gBAAgB,kBAAkB,CAAC;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;AACtD,MAAM,CAAC,MAAM,iCAAiC,GAAG,GAAG,CAAC;AAErD,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AACjD,MAAM,CAAC,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAC/C,MAAM,CAAC,MAAM,4BAA4B,GAAG,SAAS,CAAC;AACtD,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAC1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAC3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,20 @@
1
+ export class TeamClawsError extends Error {
2
+ code;
3
+ retryable;
4
+ retryAfterSeconds;
5
+ exitCode;
6
+ constructor(code, message, details = {}) {
7
+ super(message);
8
+ this.name = "TeamClawsError";
9
+ this.code = code;
10
+ this.retryable = details.retryable ?? false;
11
+ this.retryAfterSeconds = details.retryAfterSeconds;
12
+ this.exitCode = details.exitCode ?? 1;
13
+ }
14
+ }
15
+ export function safeError(error) {
16
+ if (error instanceof TeamClawsError)
17
+ return error;
18
+ return new TeamClawsError("unexpected_error", "TeamClaws could not complete the command. Try again.", { exitCode: 1 });
19
+ }
20
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAMA,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,IAAI,CAAS;IACb,SAAS,CAAU;IACnB,iBAAiB,CAAqB;IACtC,QAAQ,CAAS;IAE1B,YAAY,IAAY,EAAE,OAAe,EAAE,UAAwB,EAAE;QACnE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC;IACxC,CAAC;CACF;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,IAAI,KAAK,YAAY,cAAc;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,IAAI,cAAc,CACvB,kBAAkB,EAClB,sDAAsD,EACtD,EAAE,QAAQ,EAAE,CAAC,EAAE,CAChB,CAAC;AACJ,CAAC"}