guesty-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/dist/auth.d.ts +2 -0
- package/dist/auth.js +156 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +46 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +109 -0
- package/dist/commands/accounting.d.ts +2 -0
- package/dist/commands/accounting.js +102 -0
- package/dist/commands/calendar.d.ts +2 -0
- package/dist/commands/calendar.js +60 -0
- package/dist/commands/conversations.d.ts +2 -0
- package/dist/commands/conversations.js +40 -0
- package/dist/commands/financials.d.ts +2 -0
- package/dist/commands/financials.js +56 -0
- package/dist/commands/guests.d.ts +2 -0
- package/dist/commands/guests.js +57 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +109 -0
- package/dist/commands/integrations.d.ts +2 -0
- package/dist/commands/integrations.js +62 -0
- package/dist/commands/listings.d.ts +2 -0
- package/dist/commands/listings.js +72 -0
- package/dist/commands/owners.d.ts +2 -0
- package/dist/commands/owners.js +76 -0
- package/dist/commands/properties.d.ts +2 -0
- package/dist/commands/properties.js +104 -0
- package/dist/commands/quotes.d.ts +2 -0
- package/dist/commands/quotes.js +31 -0
- package/dist/commands/raw.d.ts +2 -0
- package/dist/commands/raw.js +19 -0
- package/dist/commands/reservations.d.ts +2 -0
- package/dist/commands/reservations.js +126 -0
- package/dist/commands/reviews.d.ts +2 -0
- package/dist/commands/reviews.js +39 -0
- package/dist/commands/tasks.d.ts +2 -0
- package/dist/commands/tasks.js +60 -0
- package/dist/commands/users.d.ts +2 -0
- package/dist/commands/users.js +59 -0
- package/dist/commands/webhooks.d.ts +2 -0
- package/dist/commands/webhooks.js +52 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +44 -0
- package/dist/output.d.ts +2 -0
- package/dist/output.js +22 -0
- package/dist/stdin.d.ts +1 -0
- package/dist/stdin.js +12 -0
- package/package.json +41 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { createInterface } from "node:readline";
|
|
3
|
+
import { writeFileSync, mkdirSync, existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
const CONFIG_DIR = join(homedir(), ".guesty-cli");
|
|
7
|
+
const ENV_FILE = join(CONFIG_DIR, ".env");
|
|
8
|
+
function prompt(question, mask = false) {
|
|
9
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
if (mask && process.stdin.isTTY) {
|
|
12
|
+
process.stdout.write(question);
|
|
13
|
+
let value = "";
|
|
14
|
+
process.stdin.setRawMode(true);
|
|
15
|
+
process.stdin.resume();
|
|
16
|
+
process.stdin.setEncoding("utf8");
|
|
17
|
+
const onData = (ch) => {
|
|
18
|
+
if (ch === "\r" || ch === "\n") {
|
|
19
|
+
process.stdin.setRawMode(false);
|
|
20
|
+
process.stdin.pause();
|
|
21
|
+
process.stdin.removeListener("data", onData);
|
|
22
|
+
rl.close();
|
|
23
|
+
process.stdout.write("\n");
|
|
24
|
+
resolve(value);
|
|
25
|
+
}
|
|
26
|
+
else if (ch === "\u0003") {
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
else if (ch === "\u007F" || ch === "\b") {
|
|
30
|
+
if (value.length > 0) {
|
|
31
|
+
value = value.slice(0, -1);
|
|
32
|
+
process.stdout.write("\b \b");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
value += ch;
|
|
37
|
+
process.stdout.write("*");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
process.stdin.on("data", onData);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
rl.question(question, (answer) => {
|
|
44
|
+
rl.close();
|
|
45
|
+
resolve(answer.trim());
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function testCredentials(clientId, clientSecret) {
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch("https://open-api.guesty.com/oauth2/token", {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
55
|
+
body: new URLSearchParams({
|
|
56
|
+
grant_type: "client_credentials",
|
|
57
|
+
scope: "open-api",
|
|
58
|
+
client_id: clientId,
|
|
59
|
+
client_secret: clientSecret,
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
return res.ok;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export const init = new Command("init")
|
|
69
|
+
.description("Set up Guesty CLI with your API credentials")
|
|
70
|
+
.option("--force", "Overwrite existing configuration")
|
|
71
|
+
.action(async (opts) => {
|
|
72
|
+
process.stdout.write("\n Guesty CLI Setup\n");
|
|
73
|
+
process.stdout.write(" ================\n\n");
|
|
74
|
+
if (existsSync(ENV_FILE) && !opts.force) {
|
|
75
|
+
const existing = readFileSync(ENV_FILE, "utf8");
|
|
76
|
+
if (existing.includes("GUESTY_CLIENT_ID")) {
|
|
77
|
+
process.stdout.write(" Already configured. Run 'guesty init --force' to reconfigure.\n\n");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
process.stdout.write(" You'll need your Guesty Open API credentials.\n");
|
|
82
|
+
process.stdout.write(" Get them from: Guesty Dashboard > Marketplace > Open API\n\n");
|
|
83
|
+
const clientId = await prompt(" Client ID: ");
|
|
84
|
+
if (!clientId) {
|
|
85
|
+
process.stderr.write("\n Error: Client ID is required.\n\n");
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
const clientSecret = await prompt(" Client Secret: ", true);
|
|
89
|
+
if (!clientSecret) {
|
|
90
|
+
process.stderr.write("\n Error: Client Secret is required.\n\n");
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
process.stdout.write("\n Verifying credentials...");
|
|
94
|
+
const valid = await testCredentials(clientId, clientSecret);
|
|
95
|
+
if (!valid) {
|
|
96
|
+
process.stdout.write(" failed.\n\n");
|
|
97
|
+
process.stderr.write(" Error: Invalid credentials. Check your Client ID and Secret.\n");
|
|
98
|
+
process.stderr.write(" Note: This uses 1 of your 5 daily token requests for verification.\n\n");
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
process.stdout.write(" verified.\n");
|
|
102
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
103
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
104
|
+
}
|
|
105
|
+
const envContent = `GUESTY_CLIENT_ID=${clientId}\nGUESTY_CLIENT_SECRET=${clientSecret}\n`;
|
|
106
|
+
writeFileSync(ENV_FILE, envContent);
|
|
107
|
+
process.stdout.write(`\n Configuration saved to ${ENV_FILE}\n`);
|
|
108
|
+
process.stdout.write(" You're all set! Try: guesty res list --limit 1\n\n");
|
|
109
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
export const integrations = new Command("integrations")
|
|
5
|
+
.alias("int")
|
|
6
|
+
.description("Manage integrations and channels");
|
|
7
|
+
integrations
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List all integrations")
|
|
10
|
+
.action(async () => {
|
|
11
|
+
const data = await guestyFetch("/v1/integrations");
|
|
12
|
+
print(data);
|
|
13
|
+
});
|
|
14
|
+
integrations
|
|
15
|
+
.command("get <id>")
|
|
16
|
+
.description("Get an integration by ID")
|
|
17
|
+
.action(async (id) => {
|
|
18
|
+
const data = await guestyFetch(`/v1/integrations/${id}`);
|
|
19
|
+
print(data);
|
|
20
|
+
});
|
|
21
|
+
integrations
|
|
22
|
+
.command("channels")
|
|
23
|
+
.description("List supported marketing channels")
|
|
24
|
+
.action(async () => {
|
|
25
|
+
const data = await guestyFetch("/v1/marketing/channels");
|
|
26
|
+
print(data);
|
|
27
|
+
});
|
|
28
|
+
integrations
|
|
29
|
+
.command("promotions")
|
|
30
|
+
.description("List all promotions")
|
|
31
|
+
.action(async () => {
|
|
32
|
+
const data = await guestyFetch("/v1/rm-promotions/promotions");
|
|
33
|
+
print(data);
|
|
34
|
+
});
|
|
35
|
+
integrations
|
|
36
|
+
.command("rate-plans")
|
|
37
|
+
.description("List all rate plans")
|
|
38
|
+
.action(async () => {
|
|
39
|
+
const data = await guestyFetch("/v1/rm-rate-plans-ext/rate-plans");
|
|
40
|
+
print(data);
|
|
41
|
+
});
|
|
42
|
+
integrations
|
|
43
|
+
.command("rate-plan <id>")
|
|
44
|
+
.description("Get a rate plan by ID")
|
|
45
|
+
.action(async (id) => {
|
|
46
|
+
const data = await guestyFetch(`/v1/rm-rate-plans-ext/rate-plans/${id}`);
|
|
47
|
+
print(data);
|
|
48
|
+
});
|
|
49
|
+
integrations
|
|
50
|
+
.command("views")
|
|
51
|
+
.description("List all views")
|
|
52
|
+
.action(async () => {
|
|
53
|
+
const data = await guestyFetch("/v1/views");
|
|
54
|
+
print(data);
|
|
55
|
+
});
|
|
56
|
+
integrations
|
|
57
|
+
.command("view <id>")
|
|
58
|
+
.description("Get a view by ID")
|
|
59
|
+
.action(async (id) => {
|
|
60
|
+
const data = await guestyFetch(`/v1/views/${id}`);
|
|
61
|
+
print(data);
|
|
62
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch, paginateAll } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
import { readStdin } from "../stdin.js";
|
|
5
|
+
export const listings = new Command("listings")
|
|
6
|
+
.alias("ls")
|
|
7
|
+
.description("Manage listings");
|
|
8
|
+
listings
|
|
9
|
+
.command("list")
|
|
10
|
+
.description("List all listings")
|
|
11
|
+
.option("--fields <fields>", "Comma-separated fields to return")
|
|
12
|
+
.option("--limit <n>", "Max results", "100")
|
|
13
|
+
.option("--skip <n>", "Offset", "0")
|
|
14
|
+
.option("--all", "Fetch all pages")
|
|
15
|
+
.option("--active", "Only active listings")
|
|
16
|
+
.action(async (opts) => {
|
|
17
|
+
const params = {
|
|
18
|
+
limit: parseInt(opts.limit),
|
|
19
|
+
skip: parseInt(opts.skip),
|
|
20
|
+
};
|
|
21
|
+
if (opts.fields)
|
|
22
|
+
params.fields = opts.fields;
|
|
23
|
+
if (opts.active)
|
|
24
|
+
params.active = true;
|
|
25
|
+
if (opts.all) {
|
|
26
|
+
const results = await paginateAll("/v1/listings", params, "results");
|
|
27
|
+
print(results);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const data = await guestyFetch("/v1/listings", { params });
|
|
31
|
+
print(data);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
listings
|
|
35
|
+
.command("get <id>")
|
|
36
|
+
.description("Get a single listing by ID")
|
|
37
|
+
.option("--fields <fields>", "Comma-separated fields to return")
|
|
38
|
+
.action(async (id, opts) => {
|
|
39
|
+
const params = {};
|
|
40
|
+
if (opts.fields)
|
|
41
|
+
params.fields = opts.fields;
|
|
42
|
+
const data = await guestyFetch(`/v1/listings/${id}`, { params });
|
|
43
|
+
print(data);
|
|
44
|
+
});
|
|
45
|
+
listings
|
|
46
|
+
.command("update <id>")
|
|
47
|
+
.description("Update a listing (--data or stdin)")
|
|
48
|
+
.option("--data <json>", "JSON body")
|
|
49
|
+
.action(async (id, opts) => {
|
|
50
|
+
const body = opts.data
|
|
51
|
+
? JSON.parse(opts.data)
|
|
52
|
+
: JSON.parse(await readStdin());
|
|
53
|
+
const data = await guestyFetch(`/v1/listings/${id}`, {
|
|
54
|
+
method: "PUT",
|
|
55
|
+
body,
|
|
56
|
+
});
|
|
57
|
+
print(data);
|
|
58
|
+
});
|
|
59
|
+
listings
|
|
60
|
+
.command("custom-fields <id>")
|
|
61
|
+
.description("Get custom fields for a listing")
|
|
62
|
+
.action(async (id) => {
|
|
63
|
+
const data = await guestyFetch(`/v1/listings/${id}/custom-fields`);
|
|
64
|
+
print(data);
|
|
65
|
+
});
|
|
66
|
+
listings
|
|
67
|
+
.command("financials <id>")
|
|
68
|
+
.description("Get financial settings for a listing")
|
|
69
|
+
.action(async (id) => {
|
|
70
|
+
const data = await guestyFetch(`/v1/financials/${id}`);
|
|
71
|
+
print(data);
|
|
72
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
import { readStdin } from "../stdin.js";
|
|
5
|
+
export const owners = new Command("owners")
|
|
6
|
+
.description("Manage owners and ownerships");
|
|
7
|
+
owners
|
|
8
|
+
.command("list")
|
|
9
|
+
.description("List all owners")
|
|
10
|
+
.option("--limit <n>", "Max results", "25")
|
|
11
|
+
.option("--skip <n>", "Offset", "0")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
const data = await guestyFetch("/v1/owners", {
|
|
14
|
+
params: { limit: parseInt(opts.limit), skip: parseInt(opts.skip) },
|
|
15
|
+
});
|
|
16
|
+
print(data);
|
|
17
|
+
});
|
|
18
|
+
owners
|
|
19
|
+
.command("get <ownerId>")
|
|
20
|
+
.description("Get a single owner")
|
|
21
|
+
.action(async (ownerId) => {
|
|
22
|
+
const data = await guestyFetch(`/v1/owners/${ownerId}`);
|
|
23
|
+
print(data);
|
|
24
|
+
});
|
|
25
|
+
owners
|
|
26
|
+
.command("create")
|
|
27
|
+
.description("Create an owner (--data or stdin)")
|
|
28
|
+
.option("--data <json>", "JSON body")
|
|
29
|
+
.action(async (opts) => {
|
|
30
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
31
|
+
const data = await guestyFetch("/v1/owners", { method: "POST", body });
|
|
32
|
+
print(data);
|
|
33
|
+
});
|
|
34
|
+
owners
|
|
35
|
+
.command("update <ownerId>")
|
|
36
|
+
.description("Update an owner (--data or stdin)")
|
|
37
|
+
.option("--data <json>", "JSON body")
|
|
38
|
+
.action(async (ownerId, opts) => {
|
|
39
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
40
|
+
const data = await guestyFetch(`/v1/owners/${ownerId}`, { method: "PUT", body });
|
|
41
|
+
print(data);
|
|
42
|
+
});
|
|
43
|
+
owners
|
|
44
|
+
.command("delete <ownerId>")
|
|
45
|
+
.description("Delete an owner")
|
|
46
|
+
.action(async (ownerId) => {
|
|
47
|
+
const data = await guestyFetch(`/v1/owners/${ownerId}`, { method: "DELETE" });
|
|
48
|
+
print(data);
|
|
49
|
+
});
|
|
50
|
+
owners
|
|
51
|
+
.command("ownerships <listingId>")
|
|
52
|
+
.description("Get ownerships for a listing")
|
|
53
|
+
.action(async (listingId) => {
|
|
54
|
+
const data = await guestyFetch(`/v1/owners/listings/${listingId}/ownerships`);
|
|
55
|
+
print(data);
|
|
56
|
+
});
|
|
57
|
+
owners
|
|
58
|
+
.command("set-ownerships <listingId>")
|
|
59
|
+
.description("Set ownerships for a listing (--data or stdin)")
|
|
60
|
+
.option("--data <json>", "JSON body")
|
|
61
|
+
.action(async (listingId, opts) => {
|
|
62
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
63
|
+
const data = await guestyFetch(`/v1/owners/listings/${listingId}/ownerships`, { method: "PUT", body });
|
|
64
|
+
print(data);
|
|
65
|
+
});
|
|
66
|
+
owners
|
|
67
|
+
.command("reservations")
|
|
68
|
+
.description("List owner reservations")
|
|
69
|
+
.option("--limit <n>", "Max results", "25")
|
|
70
|
+
.option("--skip <n>", "Offset", "0")
|
|
71
|
+
.action(async (opts) => {
|
|
72
|
+
const data = await guestyFetch("/v1/owners-reservations", {
|
|
73
|
+
params: { limit: parseInt(opts.limit), skip: parseInt(opts.skip) },
|
|
74
|
+
});
|
|
75
|
+
print(data);
|
|
76
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
import { readStdin } from "../stdin.js";
|
|
5
|
+
export const properties = new Command("properties")
|
|
6
|
+
.alias("prop")
|
|
7
|
+
.description("Property settings: amenities, photos, spaces, house rules, complexes");
|
|
8
|
+
properties
|
|
9
|
+
.command("amenities <propertyId>")
|
|
10
|
+
.description("Get amenities for a property")
|
|
11
|
+
.action(async (id) => {
|
|
12
|
+
const data = await guestyFetch(`/v1/properties-api/amenities/${id}`);
|
|
13
|
+
print(data);
|
|
14
|
+
});
|
|
15
|
+
properties
|
|
16
|
+
.command("set-amenities <propertyId>")
|
|
17
|
+
.description("Set amenities for a property (--data or stdin)")
|
|
18
|
+
.option("--data <json>", "JSON body")
|
|
19
|
+
.action(async (id, opts) => {
|
|
20
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
21
|
+
const data = await guestyFetch(`/v1/properties-api/amenities/${id}`, { method: "PUT", body });
|
|
22
|
+
print(data);
|
|
23
|
+
});
|
|
24
|
+
properties
|
|
25
|
+
.command("supported-amenities")
|
|
26
|
+
.description("List all supported amenities")
|
|
27
|
+
.action(async () => {
|
|
28
|
+
const data = await guestyFetch("/v1/properties-api/amenities/supported");
|
|
29
|
+
print(data);
|
|
30
|
+
});
|
|
31
|
+
properties
|
|
32
|
+
.command("photos <propertyId>")
|
|
33
|
+
.description("Get all photos for a property")
|
|
34
|
+
.action(async (id) => {
|
|
35
|
+
const data = await guestyFetch(`/v1/properties-api/property-photos/property-photos/${id}`);
|
|
36
|
+
print(data);
|
|
37
|
+
});
|
|
38
|
+
properties
|
|
39
|
+
.command("add-photos <propertyId>")
|
|
40
|
+
.description("Add photos to a property (--data or stdin)")
|
|
41
|
+
.option("--data <json>", "JSON body")
|
|
42
|
+
.action(async (id, opts) => {
|
|
43
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
44
|
+
const data = await guestyFetch(`/v1/properties-api/property-photos/property-photos/${id}`, { method: "POST", body });
|
|
45
|
+
print(data);
|
|
46
|
+
});
|
|
47
|
+
properties
|
|
48
|
+
.command("spaces <unitTypeId>")
|
|
49
|
+
.description("Get spaces for a unit type")
|
|
50
|
+
.action(async (id) => {
|
|
51
|
+
const data = await guestyFetch(`/v1/properties/spaces/unit-type/${id}`);
|
|
52
|
+
print(data);
|
|
53
|
+
});
|
|
54
|
+
properties
|
|
55
|
+
.command("house-rules <unitTypeId>")
|
|
56
|
+
.description("Get house rules for a unit type")
|
|
57
|
+
.action(async (id) => {
|
|
58
|
+
const data = await guestyFetch(`/v1/properties/house-rules/unit-type/${id}`);
|
|
59
|
+
print(data);
|
|
60
|
+
});
|
|
61
|
+
properties
|
|
62
|
+
.command("set-house-rules <unitTypeId>")
|
|
63
|
+
.description("Update house rules (--data or stdin)")
|
|
64
|
+
.option("--data <json>", "JSON body")
|
|
65
|
+
.action(async (id, opts) => {
|
|
66
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
67
|
+
const data = await guestyFetch(`/v1/properties/house-rules/unit-type/${id}`, { method: "PUT", body });
|
|
68
|
+
print(data);
|
|
69
|
+
});
|
|
70
|
+
properties
|
|
71
|
+
.command("address <propertyId>")
|
|
72
|
+
.description("Get property address")
|
|
73
|
+
.action(async (id) => {
|
|
74
|
+
const data = await guestyFetch(`/v1/address/${id}`);
|
|
75
|
+
print(data);
|
|
76
|
+
});
|
|
77
|
+
properties
|
|
78
|
+
.command("complexes")
|
|
79
|
+
.description("List all complexes")
|
|
80
|
+
.action(async () => {
|
|
81
|
+
const data = await guestyFetch("/v1/properties-api/complexes");
|
|
82
|
+
print(data);
|
|
83
|
+
});
|
|
84
|
+
properties
|
|
85
|
+
.command("complex <id>")
|
|
86
|
+
.description("Get a complex by ID")
|
|
87
|
+
.action(async (id) => {
|
|
88
|
+
const data = await guestyFetch(`/v1/properties-api/complexes/${id}`);
|
|
89
|
+
print(data);
|
|
90
|
+
});
|
|
91
|
+
properties
|
|
92
|
+
.command("logs <propertyId>")
|
|
93
|
+
.description("Get property logs")
|
|
94
|
+
.action(async (id) => {
|
|
95
|
+
const data = await guestyFetch(`/v1/property-logs/${id}`);
|
|
96
|
+
print(data);
|
|
97
|
+
});
|
|
98
|
+
properties
|
|
99
|
+
.command("custom-fields <propertyId>")
|
|
100
|
+
.description("Get custom fields for a property")
|
|
101
|
+
.action(async (id) => {
|
|
102
|
+
const data = await guestyFetch(`/v1/properties-api/custom-fields/${id}`);
|
|
103
|
+
print(data);
|
|
104
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
import { readStdin } from "../stdin.js";
|
|
5
|
+
export const quotes = new Command("quotes")
|
|
6
|
+
.description("Manage quotes");
|
|
7
|
+
quotes
|
|
8
|
+
.command("get <quoteId>")
|
|
9
|
+
.description("Get a quote by ID")
|
|
10
|
+
.action(async (id) => {
|
|
11
|
+
const data = await guestyFetch(`/v1/quotes/${id}`);
|
|
12
|
+
print(data);
|
|
13
|
+
});
|
|
14
|
+
quotes
|
|
15
|
+
.command("create")
|
|
16
|
+
.description("Create a quote (--data or stdin)")
|
|
17
|
+
.option("--data <json>", "JSON body")
|
|
18
|
+
.action(async (opts) => {
|
|
19
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
20
|
+
const data = await guestyFetch("/v1/quotes", { method: "POST", body });
|
|
21
|
+
print(data);
|
|
22
|
+
});
|
|
23
|
+
quotes
|
|
24
|
+
.command("create-multiple")
|
|
25
|
+
.description("Create multiple quotes (--data or stdin)")
|
|
26
|
+
.option("--data <json>", "JSON body")
|
|
27
|
+
.action(async (opts) => {
|
|
28
|
+
const body = opts.data ? JSON.parse(opts.data) : JSON.parse(await readStdin());
|
|
29
|
+
const data = await guestyFetch("/v1/quotes/multiple", { method: "POST", body });
|
|
30
|
+
print(data);
|
|
31
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
export const raw = new Command("raw")
|
|
5
|
+
.description("Make a raw API call to any Guesty endpoint")
|
|
6
|
+
.argument("<method>", "HTTP method (GET, POST, PUT, DELETE, PATCH)")
|
|
7
|
+
.argument("<path>", "API path (e.g. /v1/listings)")
|
|
8
|
+
.option("--data <json>", "JSON body")
|
|
9
|
+
.option("--params <json>", "Query params as JSON")
|
|
10
|
+
.action(async (method, path, opts) => {
|
|
11
|
+
const body = opts.data ? JSON.parse(opts.data) : undefined;
|
|
12
|
+
const params = opts.params ? JSON.parse(opts.params) : undefined;
|
|
13
|
+
const data = await guestyFetch(path, {
|
|
14
|
+
method: method.toUpperCase(),
|
|
15
|
+
body,
|
|
16
|
+
params,
|
|
17
|
+
});
|
|
18
|
+
print(data);
|
|
19
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch, paginateAll } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
import { readStdin } from "../stdin.js";
|
|
5
|
+
export const reservations = new Command("reservations")
|
|
6
|
+
.alias("res")
|
|
7
|
+
.description("Manage reservations");
|
|
8
|
+
reservations
|
|
9
|
+
.command("list")
|
|
10
|
+
.description("List reservations with optional filters")
|
|
11
|
+
.option("--from <date>", "Check-in from date (YYYY-MM-DD)")
|
|
12
|
+
.option("--to <date>", "Check-in to date (YYYY-MM-DD)")
|
|
13
|
+
.option("--status <status>", "Filter by status (confirmed, canceled, inquiry, etc.)")
|
|
14
|
+
.option("--listing <id>", "Filter by listing ID")
|
|
15
|
+
.option("--guest <name>", "Filter by guest name")
|
|
16
|
+
.option("--source <source>", "Filter by source (Airbnb, Booking.com, etc.)")
|
|
17
|
+
.option("--limit <n>", "Max results", "25")
|
|
18
|
+
.option("--skip <n>", "Offset", "0")
|
|
19
|
+
.option("--sort <field>", "Sort field", "checkIn")
|
|
20
|
+
.option("--fields <fields>", "Comma-separated fields to return")
|
|
21
|
+
.option("--all", "Fetch all pages (up to 10k)")
|
|
22
|
+
.action(async (opts) => {
|
|
23
|
+
const params = {
|
|
24
|
+
limit: parseInt(opts.limit),
|
|
25
|
+
skip: parseInt(opts.skip),
|
|
26
|
+
sort: opts.sort,
|
|
27
|
+
};
|
|
28
|
+
if (opts.fields)
|
|
29
|
+
params.fields = opts.fields;
|
|
30
|
+
if (opts.status)
|
|
31
|
+
params.status = opts.status;
|
|
32
|
+
if (opts.listing)
|
|
33
|
+
params.listingId = opts.listing;
|
|
34
|
+
if (opts.source)
|
|
35
|
+
params.source = opts.source;
|
|
36
|
+
const filters = [];
|
|
37
|
+
if (opts.from)
|
|
38
|
+
filters.push(`checkIn>=${opts.from}`);
|
|
39
|
+
if (opts.to)
|
|
40
|
+
filters.push(`checkIn<=${opts.to}`);
|
|
41
|
+
if (opts.guest)
|
|
42
|
+
filters.push(`guestName=${opts.guest}`);
|
|
43
|
+
if (filters.length > 0)
|
|
44
|
+
params.filters = filters.join(",");
|
|
45
|
+
if (opts.all) {
|
|
46
|
+
const results = await paginateAll("/v1/reservations", params, "results");
|
|
47
|
+
print(results);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const data = await guestyFetch("/v1/reservations", { params });
|
|
51
|
+
print(data);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
reservations
|
|
55
|
+
.command("get <id>")
|
|
56
|
+
.description("Get a single reservation by ID")
|
|
57
|
+
.option("--fields <fields>", "Comma-separated fields to return")
|
|
58
|
+
.action(async (id, opts) => {
|
|
59
|
+
const params = {};
|
|
60
|
+
if (opts.fields)
|
|
61
|
+
params.fields = opts.fields;
|
|
62
|
+
const data = await guestyFetch(`/v1/reservations/${id}`, { params });
|
|
63
|
+
print(data);
|
|
64
|
+
});
|
|
65
|
+
reservations
|
|
66
|
+
.command("search <query>")
|
|
67
|
+
.description("Search reservations by guest name or confirmation code")
|
|
68
|
+
.option("--limit <n>", "Max results", "25")
|
|
69
|
+
.action(async (query, opts) => {
|
|
70
|
+
const data = await guestyFetch("/v1/reservations", {
|
|
71
|
+
params: {
|
|
72
|
+
q: query,
|
|
73
|
+
limit: parseInt(opts.limit),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
print(data);
|
|
77
|
+
});
|
|
78
|
+
reservations
|
|
79
|
+
.command("update <id>")
|
|
80
|
+
.description("Update a reservation (pass JSON body via stdin or --data)")
|
|
81
|
+
.option("--data <json>", "JSON body")
|
|
82
|
+
.action(async (id, opts) => {
|
|
83
|
+
const body = opts.data
|
|
84
|
+
? JSON.parse(opts.data)
|
|
85
|
+
: JSON.parse(await readStdin());
|
|
86
|
+
const data = await guestyFetch(`/v1/reservations/${id}`, {
|
|
87
|
+
method: "PUT",
|
|
88
|
+
body,
|
|
89
|
+
});
|
|
90
|
+
print(data);
|
|
91
|
+
});
|
|
92
|
+
reservations
|
|
93
|
+
.command("create")
|
|
94
|
+
.description("Create a reservation (pass JSON body via stdin or --data)")
|
|
95
|
+
.option("--data <json>", "JSON body")
|
|
96
|
+
.action(async (opts) => {
|
|
97
|
+
const body = opts.data
|
|
98
|
+
? JSON.parse(opts.data)
|
|
99
|
+
: JSON.parse(await readStdin());
|
|
100
|
+
const data = await guestyFetch("/v1/reservations", {
|
|
101
|
+
method: "POST",
|
|
102
|
+
body,
|
|
103
|
+
});
|
|
104
|
+
print(data);
|
|
105
|
+
});
|
|
106
|
+
reservations
|
|
107
|
+
.command("balance <id>")
|
|
108
|
+
.description("Get the folio/balance for a reservation")
|
|
109
|
+
.action(async (id) => {
|
|
110
|
+
const data = await guestyFetch(`/v1/accounting-api/reservations/${id}/balance`);
|
|
111
|
+
print(data);
|
|
112
|
+
});
|
|
113
|
+
reservations
|
|
114
|
+
.command("add-payment <id>")
|
|
115
|
+
.description("Add a payment to a reservation (--data or stdin)")
|
|
116
|
+
.option("--data <json>", "JSON body")
|
|
117
|
+
.action(async (id, opts) => {
|
|
118
|
+
const body = opts.data
|
|
119
|
+
? JSON.parse(opts.data)
|
|
120
|
+
: JSON.parse(await readStdin());
|
|
121
|
+
const data = await guestyFetch(`/v1/reservations/${id}/payments`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
body,
|
|
124
|
+
});
|
|
125
|
+
print(data);
|
|
126
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { guestyFetch } from "../client.js";
|
|
3
|
+
import { print } from "../output.js";
|
|
4
|
+
export const reviews = new Command("reviews")
|
|
5
|
+
.description("Manage reviews");
|
|
6
|
+
reviews
|
|
7
|
+
.command("list")
|
|
8
|
+
.description("List reviews")
|
|
9
|
+
.option("--listing <id>", "Filter by listing ID")
|
|
10
|
+
.option("--limit <n>", "Max results", "25")
|
|
11
|
+
.option("--skip <n>", "Offset", "0")
|
|
12
|
+
.action(async (opts) => {
|
|
13
|
+
const params = {
|
|
14
|
+
limit: parseInt(opts.limit),
|
|
15
|
+
skip: parseInt(opts.skip),
|
|
16
|
+
};
|
|
17
|
+
if (opts.listing)
|
|
18
|
+
params.listingId = opts.listing;
|
|
19
|
+
const data = await guestyFetch("/v1/reviews", { params });
|
|
20
|
+
print(data);
|
|
21
|
+
});
|
|
22
|
+
reviews
|
|
23
|
+
.command("get <id>")
|
|
24
|
+
.description("Get a single review")
|
|
25
|
+
.action(async (id) => {
|
|
26
|
+
const data = await guestyFetch(`/v1/reviews/${id}`);
|
|
27
|
+
print(data);
|
|
28
|
+
});
|
|
29
|
+
reviews
|
|
30
|
+
.command("reply <id>")
|
|
31
|
+
.description("Reply to a review")
|
|
32
|
+
.requiredOption("--body <text>", "Reply text")
|
|
33
|
+
.action(async (id, opts) => {
|
|
34
|
+
const data = await guestyFetch(`/v1/reviews/${id}/reply`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
body: { body: opts.body },
|
|
37
|
+
});
|
|
38
|
+
print(data);
|
|
39
|
+
});
|