guesty-cli 1.0.0 → 1.0.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.
package/dist/client.js CHANGED
@@ -42,8 +42,13 @@ export async function guestyFetch(path, options = {}) {
42
42
  if (body) {
43
43
  headers["Content-Type"] = "application/json";
44
44
  }
45
+ let tokenRefreshed = false;
45
46
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
46
47
  await enforceRateLimit();
48
+ // Re-fetch token if it was invalidated on a previous attempt
49
+ if (tokenRefreshed) {
50
+ headers.Authorization = `Bearer ${await getToken()}`;
51
+ }
47
52
  const res = await fetch(url, {
48
53
  method,
49
54
  headers,
@@ -52,9 +57,10 @@ export async function guestyFetch(path, options = {}) {
52
57
  if (res.status === 204) {
53
58
  return undefined;
54
59
  }
55
- if (res.status === 401 && attempt < MAX_RETRIES) {
60
+ if (res.status === 401 && !tokenRefreshed) {
56
61
  process.stderr.write(`Token expired (401). Refreshing...\n`);
57
62
  invalidateToken();
63
+ tokenRefreshed = true;
58
64
  continue;
59
65
  }
60
66
  if (res.status === 429 && attempt < MAX_RETRIES) {
@@ -3,6 +3,8 @@ import { createInterface } from "node:readline";
3
3
  import { writeFileSync, mkdirSync, existsSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { homedir } from "node:os";
6
+ const CONFIG_DIR_INIT = join(homedir(), ".guesty-cli");
7
+ const TOKEN_FILE_INIT = join(CONFIG_DIR_INIT, "token.json");
6
8
  const CONFIG_DIR = join(homedir(), ".guesty-cli");
7
9
  const ENV_FILE = join(CONFIG_DIR, ".env");
8
10
  function prompt(question, mask = false) {
@@ -59,10 +61,13 @@ async function testCredentials(clientId, clientSecret) {
59
61
  client_secret: clientSecret,
60
62
  }),
61
63
  });
62
- return res.ok;
64
+ if (!res.ok)
65
+ return { ok: false };
66
+ const data = await res.json();
67
+ return { ok: true, access_token: data.access_token, expires_in: data.expires_in };
63
68
  }
64
69
  catch {
65
- return false;
70
+ return { ok: false };
66
71
  }
67
72
  }
68
73
  export const init = new Command("init")
@@ -91,19 +96,31 @@ export const init = new Command("init")
91
96
  process.exit(1);
92
97
  }
93
98
  process.stdout.write("\n Verifying credentials...");
94
- const valid = await testCredentials(clientId, clientSecret);
95
- if (!valid) {
99
+ const result = await testCredentials(clientId, clientSecret);
100
+ if (!result.ok) {
96
101
  process.stdout.write(" failed.\n\n");
97
102
  process.stderr.write(" Error: Invalid credentials. Check your Client ID and Secret.\n");
98
103
  process.stderr.write(" Note: This uses 1 of your 5 daily token requests for verification.\n\n");
99
104
  process.exit(1);
100
105
  }
101
106
  process.stdout.write(" verified.\n");
102
- if (!existsSync(CONFIG_DIR)) {
103
- mkdirSync(CONFIG_DIR, { recursive: true });
107
+ if (!existsSync(CONFIG_DIR_INIT)) {
108
+ mkdirSync(CONFIG_DIR_INIT, { recursive: true });
104
109
  }
110
+ // Save credentials
105
111
  const envContent = `GUESTY_CLIENT_ID=${clientId}\nGUESTY_CLIENT_SECRET=${clientSecret}\n`;
106
112
  writeFileSync(ENV_FILE, envContent);
113
+ // Cache the token we already got so the first command doesn't burn another
114
+ if (result.access_token) {
115
+ const tokenFileData = {
116
+ token: {
117
+ access_token: result.access_token,
118
+ expires_at: Date.now() + (result.expires_in ?? 3600) * 1000,
119
+ },
120
+ issued_timestamps: [Date.now()],
121
+ };
122
+ writeFileSync(TOKEN_FILE_INIT, JSON.stringify(tokenFileData, null, 2));
123
+ }
107
124
  process.stdout.write(`\n Configuration saved to ${ENV_FILE}\n`);
108
125
  process.stdout.write(" You're all set! Try: guesty res list --limit 1\n\n");
109
126
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guesty-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI for the Guesty property management API with built-in OAuth token caching and rate limiting",
5
5
  "type": "module",
6
6
  "bin": {