bamboohr-cli 1.0.21 → 1.0.22-g6336787.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/index.js +108 -61
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -60,33 +60,77 @@ function readPackageVersion(importMetaUrl) {
|
|
|
60
60
|
|
|
61
61
|
// ../../cli-utils/dist/validators.js
|
|
62
62
|
import { InvalidArgumentError } from "commander";
|
|
63
|
+
function nonNegativeInt(raw) {
|
|
64
|
+
const n = parseInt(raw, 10);
|
|
65
|
+
if (Number.isNaN(n) || n < 0) {
|
|
66
|
+
throw new InvalidArgumentError("Must be a non-negative integer.");
|
|
67
|
+
}
|
|
68
|
+
return n;
|
|
69
|
+
}
|
|
63
70
|
function positiveInt(raw) {
|
|
64
71
|
const n = parseInt(raw, 10);
|
|
65
72
|
if (Number.isNaN(n) || n < 1) {
|
|
66
|
-
throw new InvalidArgumentError(
|
|
73
|
+
throw new InvalidArgumentError("Must be a positive integer.");
|
|
67
74
|
}
|
|
68
75
|
return n;
|
|
69
76
|
}
|
|
77
|
+
function text(raw) {
|
|
78
|
+
return raw;
|
|
79
|
+
}
|
|
80
|
+
function date(raw) {
|
|
81
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw);
|
|
82
|
+
if (!m) {
|
|
83
|
+
throw new InvalidArgumentError("Must be a date in YYYY-MM-DD format.");
|
|
84
|
+
}
|
|
85
|
+
const [, y, mo, d] = m;
|
|
86
|
+
const year = Number(y);
|
|
87
|
+
const month = Number(mo);
|
|
88
|
+
const day = Number(d);
|
|
89
|
+
const dt = new Date(Date.UTC(year, month - 1, day));
|
|
90
|
+
if (dt.getUTCFullYear() !== year || dt.getUTCMonth() !== month - 1 || dt.getUTCDate() !== day) {
|
|
91
|
+
throw new InvalidArgumentError("Not a real calendar date.");
|
|
92
|
+
}
|
|
93
|
+
return raw;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ../../cli-utils/dist/json.js
|
|
97
|
+
import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
98
|
+
function jsonShape(schema) {
|
|
99
|
+
return (raw) => {
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = JSON.parse(raw);
|
|
103
|
+
} catch {
|
|
104
|
+
throw new InvalidArgumentError2("Must be valid JSON.");
|
|
105
|
+
}
|
|
106
|
+
const result = schema.safeParse(parsed);
|
|
107
|
+
if (!result.success) {
|
|
108
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
|
|
109
|
+
throw new InvalidArgumentError2(`Invalid JSON shape \u2014 ${issues}`);
|
|
110
|
+
}
|
|
111
|
+
return result.data;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
70
114
|
|
|
71
115
|
// ../../cli-utils/dist/text-or-file.js
|
|
72
116
|
import { readFileSync as readFileSync3 } from "fs";
|
|
73
|
-
import { InvalidArgumentError as
|
|
117
|
+
import { InvalidArgumentError as InvalidArgumentError3, Option } from "commander";
|
|
74
118
|
var STDIN_REF = "-";
|
|
75
119
|
function rejectStdinSentinel(value) {
|
|
76
120
|
if (value === "@-" || value === STDIN_REF) {
|
|
77
|
-
throw new
|
|
121
|
+
throw new InvalidArgumentError3(`"${value}" looks like a stdin redirect, which is not supported here. Pass the text directly, or read it from a file/stdin with the matching --\u2026-file <path|-> option.`);
|
|
78
122
|
}
|
|
79
123
|
return value;
|
|
80
124
|
}
|
|
81
125
|
function readFileOrStdin(ref) {
|
|
82
126
|
if (ref === STDIN_REF) {
|
|
83
127
|
if (process.stdin.isTTY) {
|
|
84
|
-
throw new
|
|
128
|
+
throw new InvalidArgumentError3('"--\u2026-file -" reads stdin, but stdin is a terminal (nothing piped).');
|
|
85
129
|
}
|
|
86
130
|
try {
|
|
87
131
|
return readFileSync3(0, "utf8");
|
|
88
132
|
} catch (err) {
|
|
89
|
-
throw new
|
|
133
|
+
throw new InvalidArgumentError3(`failed to read stdin for "--\u2026-file -": ${err.message}`);
|
|
90
134
|
}
|
|
91
135
|
}
|
|
92
136
|
try {
|
|
@@ -94,28 +138,28 @@ function readFileOrStdin(ref) {
|
|
|
94
138
|
} catch (err) {
|
|
95
139
|
const e = err;
|
|
96
140
|
if (e.code === "ENOENT") {
|
|
97
|
-
throw new
|
|
141
|
+
throw new InvalidArgumentError3(`file not found: "${ref}".`);
|
|
98
142
|
}
|
|
99
|
-
throw new
|
|
143
|
+
throw new InvalidArgumentError3(`failed to read file "${ref}": ${e.message}`);
|
|
100
144
|
}
|
|
101
145
|
}
|
|
102
146
|
function textOrFileOption(cmd, name, opts = {}) {
|
|
103
147
|
const label = `${name.charAt(0).toUpperCase()}${name.slice(1)} content`;
|
|
104
148
|
cmd.option(`--${name} <text>`, opts.description ?? label, rejectStdinSentinel);
|
|
105
|
-
cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name));
|
|
149
|
+
cmd.addOption(new Option(`--${name}-file <path>`, `Read --${name} from a file, or "-" for stdin (mutually exclusive with --${name})`).conflicts(name).argParser(text));
|
|
106
150
|
return cmd;
|
|
107
151
|
}
|
|
108
152
|
function resolveTextOrFile(opts, name, { required = true } = {}) {
|
|
109
153
|
const literal = opts[name];
|
|
110
154
|
const ref = opts[`${name}File`];
|
|
111
155
|
if (literal !== void 0 && ref !== void 0) {
|
|
112
|
-
throw new
|
|
156
|
+
throw new InvalidArgumentError3(`--${name} and --${name}-file are mutually exclusive; provide only one.`);
|
|
113
157
|
}
|
|
114
158
|
if (ref !== void 0) {
|
|
115
159
|
return readFileOrStdin(ref);
|
|
116
160
|
}
|
|
117
161
|
if (literal === void 0 && required) {
|
|
118
|
-
throw new
|
|
162
|
+
throw new InvalidArgumentError3(`a ${name} is required: provide --${name} <text> or --${name}-file <path>.`);
|
|
119
163
|
}
|
|
120
164
|
return literal;
|
|
121
165
|
}
|
|
@@ -518,7 +562,7 @@ function directory(parent) {
|
|
|
518
562
|
|
|
519
563
|
// src/commands/employee/get.ts
|
|
520
564
|
function get(parent) {
|
|
521
|
-
const cmd = parent.command("get
|
|
565
|
+
const cmd = parent.command("get").description("Get employee data by ID (default: current user)").argument("[employeeId]", "Employee ID (0 or omitted = current user)", nonNegativeInt).option("--fields <fields>", "Comma-separated field names", text, "firstName,lastName,email,jobTitle").option("--include-future", "Include future-dated values from history fields").option("--with-photos", "Include the employee's signed photo URL and photoUploaded flag");
|
|
522
566
|
examples(cmd, [
|
|
523
567
|
"",
|
|
524
568
|
"123",
|
|
@@ -531,7 +575,7 @@ function get(parent) {
|
|
|
531
575
|
const client = getClient();
|
|
532
576
|
const fields2 = opts.withPhotos ? mergeFields(opts.fields, ["photoUrl", "photoUploaded"]) : opts.fields;
|
|
533
577
|
const result = await client.employees.get({
|
|
534
|
-
id: employeeId
|
|
578
|
+
id: employeeId !== void 0 ? String(employeeId) : "0",
|
|
535
579
|
fields: fields2,
|
|
536
580
|
onlyCurrent: !opts.includeFuture
|
|
537
581
|
});
|
|
@@ -551,12 +595,12 @@ function mergeFields(existing, extra) {
|
|
|
551
595
|
import { Option as Option2 } from "commander";
|
|
552
596
|
var GOAL_FILTERS = ["open", "closed", "all"];
|
|
553
597
|
function goals(parent) {
|
|
554
|
-
const cmd = parent.command("goals
|
|
598
|
+
const cmd = parent.command("goals").description("Get employee performance goals").argument("<employeeId>", "Employee ID (0 = current user)", nonNegativeInt).addOption(new Option2("--filter <filter>", "Filter goals by status").choices(GOAL_FILTERS).default("all"));
|
|
555
599
|
examples(cmd, ["123", ["123 --filter open", "only open goals"], ["123 --filter closed", "only closed goals"]]);
|
|
556
600
|
cmd.action(async (employeeId, opts) => {
|
|
557
601
|
const client = getClient();
|
|
558
602
|
const result = await client.goals.get({
|
|
559
|
-
employeeId,
|
|
603
|
+
employeeId: String(employeeId),
|
|
560
604
|
filter: opts.filter === "all" ? void 0 : opts.filter
|
|
561
605
|
});
|
|
562
606
|
output(transformGoals(result));
|
|
@@ -568,12 +612,12 @@ import { writeFileSync as writeFileSync2 } from "fs";
|
|
|
568
612
|
import { Option as Option3 } from "commander";
|
|
569
613
|
var PHOTO_SIZES = ["original", "large", "medium", "small", "xs", "tiny"];
|
|
570
614
|
function photo(parent) {
|
|
571
|
-
const cmd = parent.command("photo
|
|
615
|
+
const cmd = parent.command("photo").description("Download employee photo").argument("<employeeId>", "Employee ID (0 = current user)", nonNegativeInt).requiredOption("--output <path>", "File path to save photo", text).addOption(new Option3("--size <size>", "Photo size").choices(PHOTO_SIZES).default("medium"));
|
|
572
616
|
examples(cmd, [["123 --output ./photo.jpg", "medium size (default)"], "123 --output ./photo.jpg --size large"]);
|
|
573
617
|
cmd.action(async (employeeId, opts) => {
|
|
574
618
|
const client = getClient();
|
|
575
619
|
const buffer = await client.employees.getPhoto({
|
|
576
|
-
employeeId,
|
|
620
|
+
employeeId: String(employeeId),
|
|
577
621
|
size: opts.size
|
|
578
622
|
});
|
|
579
623
|
writeFileSync2(opts.output, buffer);
|
|
@@ -590,7 +634,7 @@ async function resolveEmployeeId(client, employeeId) {
|
|
|
590
634
|
|
|
591
635
|
// src/commands/employee/search.ts
|
|
592
636
|
function search(parent) {
|
|
593
|
-
const cmd = parent.command("search
|
|
637
|
+
const cmd = parent.command("search").description("Search and filter employees").argument("[query]", "Name fragment to search for", text).option("--supervisor <name>", 'Filter by supervisor name (use "me" for current user)', text).option("--department <name>", "Filter by department", text).option("--location <name>", "Filter by location", text).option("--division <name>", "Filter by division", text).option("--with-photos", "Include each result's signed photo URL and photoUploaded flag");
|
|
594
638
|
examples(cmd, [
|
|
595
639
|
"john",
|
|
596
640
|
"--supervisor me",
|
|
@@ -657,11 +701,11 @@ function registerEmployeeCommands(program) {
|
|
|
657
701
|
// src/commands/file/get.ts
|
|
658
702
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
659
703
|
function get2(parent) {
|
|
660
|
-
const cmd = parent.command("get
|
|
704
|
+
const cmd = parent.command("get").description("Download a company file").argument("<fileId>", "File ID", positiveInt).requiredOption("--output <path>", "File path to save to", text);
|
|
661
705
|
examples(cmd, ["42 --output ./handbook.pdf"]);
|
|
662
706
|
cmd.action(async (fileId, opts) => {
|
|
663
707
|
const client = getClient();
|
|
664
|
-
const buffer = await client.files.get({ fileId });
|
|
708
|
+
const buffer = await client.files.get({ fileId: String(fileId) });
|
|
665
709
|
writeFileSync3(opts.output, buffer);
|
|
666
710
|
output({ saved: true, path: opts.output, size: buffer.length });
|
|
667
711
|
});
|
|
@@ -745,59 +789,43 @@ function registerMetaCommands(program) {
|
|
|
745
789
|
|
|
746
790
|
// src/commands/timeoff/balance.ts
|
|
747
791
|
function balance(parent) {
|
|
748
|
-
const cmd = parent.command("balance
|
|
792
|
+
const cmd = parent.command("balance").description("Estimate time off balance (defaults to current user)").argument("[employeeId]", "Employee ID (0 or omitted = current user)", nonNegativeInt).option("--date <date>", "Future date to estimate balance for (YYYY-MM-DD)", date);
|
|
749
793
|
examples(cmd, ["", "123", ["--date 2026-06-30", "balance at a future date"]]);
|
|
750
794
|
cmd.action(async (employeeId, opts) => {
|
|
751
795
|
const client = getClient();
|
|
752
|
-
const id = await resolveEmployeeId(client, employeeId);
|
|
796
|
+
const id = await resolveEmployeeId(client, employeeId !== void 0 ? String(employeeId) : void 0);
|
|
753
797
|
const result = await client.timeOff.getBalance({ employeeId: id, date: opts.date });
|
|
754
798
|
output(transformTimeOffBalances(result));
|
|
755
799
|
});
|
|
756
800
|
}
|
|
757
801
|
|
|
758
802
|
// src/commands/timeoff/create.ts
|
|
759
|
-
import { InvalidArgumentError as
|
|
803
|
+
import { InvalidArgumentError as InvalidArgumentError5, Option as Option4 } from "commander";
|
|
804
|
+
import { z } from "zod";
|
|
760
805
|
|
|
761
806
|
// src/utils/timeoff-dates.ts
|
|
762
|
-
import { InvalidArgumentError as
|
|
807
|
+
import { InvalidArgumentError as InvalidArgumentError4 } from "commander";
|
|
763
808
|
var WEEKDAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
764
809
|
var YMD = /^\d{4}-\d{2}-\d{2}$/;
|
|
765
|
-
function parseDatesJson(raw) {
|
|
766
|
-
let parsed;
|
|
767
|
-
try {
|
|
768
|
-
parsed = JSON.parse(raw);
|
|
769
|
-
} catch {
|
|
770
|
-
throw new InvalidArgumentError3(
|
|
771
|
-
`--dates is not valid JSON. Expected an array like '[{"ymd":"2026-03-21","amount":0.5}]'.`
|
|
772
|
-
);
|
|
773
|
-
}
|
|
774
|
-
const isEntry = (d) => typeof d === "object" && d !== null && typeof d.ymd === "string" && YMD.test(d.ymd) && typeof d.amount === "number" && Number.isFinite(d.amount) && d.amount >= 0;
|
|
775
|
-
if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(isEntry)) {
|
|
776
|
-
throw new InvalidArgumentError3(
|
|
777
|
-
'--dates must be a non-empty JSON array of {"ymd":"YYYY-MM-DD","amount":<non-negative number>} objects.'
|
|
778
|
-
);
|
|
779
|
-
}
|
|
780
|
-
return parsed.map((d) => ({ ymd: d.ymd, amount: d.amount }));
|
|
781
|
-
}
|
|
782
810
|
function parseYmd(value, label) {
|
|
783
811
|
if (!YMD.test(value)) {
|
|
784
|
-
throw new
|
|
812
|
+
throw new InvalidArgumentError4(`${label} must be a YYYY-MM-DD date, got "${value}".`);
|
|
785
813
|
}
|
|
786
|
-
const
|
|
787
|
-
if (Number.isNaN(
|
|
788
|
-
throw new
|
|
814
|
+
const date2 = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
|
|
815
|
+
if (Number.isNaN(date2.getTime())) {
|
|
816
|
+
throw new InvalidArgumentError4(`${label} is not a valid date: "${value}".`);
|
|
789
817
|
}
|
|
790
|
-
return
|
|
818
|
+
return date2;
|
|
791
819
|
}
|
|
792
|
-
function toYmd(
|
|
793
|
-
return
|
|
820
|
+
function toYmd(date2) {
|
|
821
|
+
return date2.toISOString().slice(0, 10);
|
|
794
822
|
}
|
|
795
823
|
function buildTimeOffDates(params) {
|
|
796
824
|
const { start, end, units, defaultHours, holidays = [] } = params;
|
|
797
825
|
const startDate = parseYmd(start, "--start-date");
|
|
798
826
|
const endDate = parseYmd(end, "--end-date");
|
|
799
827
|
if (endDate < startDate) {
|
|
800
|
-
throw new
|
|
828
|
+
throw new InvalidArgumentError4(`--end-date ${end} is before --start-date ${start}.`);
|
|
801
829
|
}
|
|
802
830
|
const hoursByName = new Map(defaultHours.map((entry) => [entry.name, Number(entry.amount)]));
|
|
803
831
|
const fallbackHours = hoursByName.get("default") ?? 8;
|
|
@@ -813,12 +841,31 @@ function buildTimeOffDates(params) {
|
|
|
813
841
|
}
|
|
814
842
|
|
|
815
843
|
// src/commands/timeoff/create.ts
|
|
844
|
+
var datesSchema = z.array(
|
|
845
|
+
z.object({
|
|
846
|
+
// Reuse the shared `date` validator so an impossible calendar date (e.g. 2026-02-30)
|
|
847
|
+
// is rejected inside --dates JSON exactly as it is for --start-date/--end-date.
|
|
848
|
+
ymd: z.string().refine(
|
|
849
|
+
(v) => {
|
|
850
|
+
try {
|
|
851
|
+
date(v);
|
|
852
|
+
return true;
|
|
853
|
+
} catch {
|
|
854
|
+
return false;
|
|
855
|
+
}
|
|
856
|
+
},
|
|
857
|
+
{ message: "must be a real YYYY-MM-DD date" }
|
|
858
|
+
),
|
|
859
|
+
amount: z.number().finite().nonnegative()
|
|
860
|
+
})
|
|
861
|
+
).min(1, "must be a non-empty array");
|
|
816
862
|
function create(parent) {
|
|
817
|
-
const cmd = parent.command("create
|
|
863
|
+
const cmd = parent.command("create").description("Create a time off request (defaults to current user)").argument("[employeeId]", "Employee ID (0 or omitted = current user)", nonNegativeInt).requiredOption("--start-date <date>", "Start date (YYYY-MM-DD)", date).requiredOption("--end-date <date>", "End date (YYYY-MM-DD)", date).requiredOption("--type-id <id>", 'Time off type ID (use "timeoff types" to find IDs)', positiveInt).addOption(
|
|
818
864
|
new Option4("--status <status>", "Request status").choices(["requested", "approved"]).default("requested")
|
|
819
865
|
).option(
|
|
820
866
|
"--dates <json>",
|
|
821
|
-
`Per-day amounts as JSON array, e.g. '[{"ymd":"2026-03-21","amount":0.5}]' for a half day. When omitted, generated automatically: 1 day (or the weekday's working hours) per working day, 0 on weekends and company holidays
|
|
867
|
+
`Per-day amounts as JSON array, e.g. '[{"ymd":"2026-03-21","amount":0.5}]' for a half day. When omitted, generated automatically: 1 day (or the weekday's working hours) per working day, 0 on weekends and company holidays`,
|
|
868
|
+
jsonShape(datesSchema)
|
|
822
869
|
);
|
|
823
870
|
textOrFileOption(cmd, "note", { description: "Note to include with the request" });
|
|
824
871
|
examples(cmd, [
|
|
@@ -835,11 +882,11 @@ function create(parent) {
|
|
|
835
882
|
cmd.action(
|
|
836
883
|
async (employeeId, opts) => {
|
|
837
884
|
const client = getClient();
|
|
838
|
-
const id = await resolveEmployeeId(client, employeeId);
|
|
885
|
+
const id = await resolveEmployeeId(client, employeeId !== void 0 ? String(employeeId) : void 0);
|
|
839
886
|
const note = resolveTextOrFile(opts, "note", { required: false });
|
|
840
887
|
let dates;
|
|
841
888
|
if (opts.dates) {
|
|
842
|
-
dates =
|
|
889
|
+
dates = opts.dates;
|
|
843
890
|
} else {
|
|
844
891
|
const [types2, whosOut2] = await Promise.all([
|
|
845
892
|
getTimeOffTypes(client),
|
|
@@ -847,7 +894,7 @@ function create(parent) {
|
|
|
847
894
|
]);
|
|
848
895
|
const type = types2.timeOffTypes.find((t) => Number(t.id) === opts.typeId);
|
|
849
896
|
if (!type) {
|
|
850
|
-
throw new
|
|
897
|
+
throw new InvalidArgumentError5(`Unknown time off type ID ${opts.typeId}. Run "timeoff types" to list IDs.`);
|
|
851
898
|
}
|
|
852
899
|
const holidays = whosOut2.filter((e) => e.type === "holiday").map((e) => ({ start: e.start, end: e.end }));
|
|
853
900
|
dates = buildTimeOffDates({
|
|
@@ -860,7 +907,7 @@ function create(parent) {
|
|
|
860
907
|
}
|
|
861
908
|
const total = dates.reduce((sum, d) => sum + d.amount, 0);
|
|
862
909
|
if (total <= 0) {
|
|
863
|
-
throw new
|
|
910
|
+
throw new InvalidArgumentError5(
|
|
864
911
|
opts.dates ? "The per-day amounts in --dates sum to 0; a request must claim more than 0 days/hours." : "The requested range contains no working days (weekends/company holidays only). Adjust the dates or pass --dates explicitly."
|
|
865
912
|
);
|
|
866
913
|
}
|
|
@@ -884,7 +931,7 @@ function create(parent) {
|
|
|
884
931
|
// src/commands/timeoff/requests.ts
|
|
885
932
|
import { Option as Option5 } from "commander";
|
|
886
933
|
function requests(parent) {
|
|
887
|
-
const cmd = parent.command("requests").description("Get time off requests (defaults to current user)").option("--request-id <id>", "Specific request ID", positiveInt).addOption(new Option5("--action <action>", "Access level filter").choices(["view", "approve"])).option("--employee-id <id>", "Filter by employee ID").option("--all", "Show all visible requests instead of just current user").option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").addOption(
|
|
934
|
+
const cmd = parent.command("requests").description("Get time off requests (defaults to current user)").option("--request-id <id>", "Specific request ID", positiveInt).addOption(new Option5("--action <action>", "Access level filter").choices(["view", "approve"])).option("--employee-id <id>", "Filter by employee ID (0 = current user)", nonNegativeInt).option("--all", "Show all visible requests instead of just current user").option("--start-date <date>", "Start date (YYYY-MM-DD)", date).option("--end-date <date>", "End date (YYYY-MM-DD)", date).addOption(
|
|
888
935
|
new Option5("--status <status>", "Filter by request status").choices([
|
|
889
936
|
"approved",
|
|
890
937
|
"denied",
|
|
@@ -892,7 +939,7 @@ function requests(parent) {
|
|
|
892
939
|
"requested",
|
|
893
940
|
"canceled"
|
|
894
941
|
])
|
|
895
|
-
).option("--type-id <typeId>", "Filter by time off type ID");
|
|
942
|
+
).option("--type-id <typeId>", "Filter by time off type ID", positiveInt);
|
|
896
943
|
examples(cmd, [
|
|
897
944
|
"",
|
|
898
945
|
"--status requested",
|
|
@@ -905,7 +952,7 @@ function requests(parent) {
|
|
|
905
952
|
const start = opts.startDate ?? `${year}-01-01`;
|
|
906
953
|
const end = opts.endDate ?? `${year}-12-31`;
|
|
907
954
|
const client = getClient();
|
|
908
|
-
let employeeId = opts.employeeId;
|
|
955
|
+
let employeeId = opts.employeeId !== void 0 ? String(opts.employeeId) : void 0;
|
|
909
956
|
if (!employeeId && !opts.all) {
|
|
910
957
|
employeeId = await resolveEmployeeId(client);
|
|
911
958
|
}
|
|
@@ -916,7 +963,7 @@ function requests(parent) {
|
|
|
916
963
|
start,
|
|
917
964
|
end,
|
|
918
965
|
status: opts.status,
|
|
919
|
-
type: opts.typeId
|
|
966
|
+
type: opts.typeId !== void 0 ? String(opts.typeId) : void 0
|
|
920
967
|
});
|
|
921
968
|
output(transformTimeOffRequests(result));
|
|
922
969
|
}
|
|
@@ -937,7 +984,7 @@ function types(parent) {
|
|
|
937
984
|
// src/commands/timeoff/update-status.ts
|
|
938
985
|
import { Option as Option6 } from "commander";
|
|
939
986
|
function updateStatus(parent) {
|
|
940
|
-
const cmd = parent.command("update-status
|
|
987
|
+
const cmd = parent.command("update-status").description("Update time off request status (approve, deny, cancel)").argument("<requestId>", "Time off request ID", positiveInt).addOption(
|
|
941
988
|
new Option6("--status <status>", "New status").choices(["approved", "denied", "canceled"]).makeOptionMandatory()
|
|
942
989
|
);
|
|
943
990
|
textOrFileOption(cmd, "note", { description: "Note to attach to the status change" });
|
|
@@ -951,7 +998,7 @@ function updateStatus(parent) {
|
|
|
951
998
|
const client = getClient();
|
|
952
999
|
const note = resolveTextOrFile(opts, "note", { required: false });
|
|
953
1000
|
const result = await client.timeOff.updateRequestStatus({
|
|
954
|
-
requestId,
|
|
1001
|
+
requestId: String(requestId),
|
|
955
1002
|
status: opts.status,
|
|
956
1003
|
note
|
|
957
1004
|
});
|
|
@@ -962,7 +1009,7 @@ function updateStatus(parent) {
|
|
|
962
1009
|
|
|
963
1010
|
// src/commands/timeoff/whos-out.ts
|
|
964
1011
|
function whosOut(parent) {
|
|
965
|
-
const cmd = parent.command("whos-out").description("View who's out \u2014 upcoming time off and holidays").option("--start-date <date>", "Start date (YYYY-MM-DD, defaults to today)").option("--end-date <date>", "End date (YYYY-MM-DD, defaults to today)");
|
|
1012
|
+
const cmd = parent.command("whos-out").description("View who's out \u2014 upcoming time off and holidays").option("--start-date <date>", "Start date (YYYY-MM-DD, defaults to today)", date).option("--end-date <date>", "End date (YYYY-MM-DD, defaults to today)", date);
|
|
966
1013
|
examples(cmd, ["", ["--start-date 2026-03-20 --end-date 2026-04-03", "two-week window"]]);
|
|
967
1014
|
cmd.action(async (opts) => {
|
|
968
1015
|
const client = getClient();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bamboohr-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22-g6336787.1",
|
|
4
4
|
"publish": true,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
],
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"commander": "^13.1.0",
|
|
15
|
-
"
|
|
15
|
+
"zod": "^3.25.67",
|
|
16
|
+
"bamboohr-client": "1.0.24-g6336787.1"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
19
|
"@types/node": "24.10.4",
|