bamboohr-cli 1.0.15 → 1.0.16

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.
Files changed (2) hide show
  1. package/dist/index.js +151 -38
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -106,32 +106,13 @@ function getClient() {
106
106
  return new BambooHRClient({ apiToken, companyDomain });
107
107
  }
108
108
 
109
- // src/utils/strip-response.ts
110
- function stripResponse(obj) {
111
- if (Array.isArray(obj)) {
112
- return obj.map(stripResponse);
113
- }
114
- if (obj === null || typeof obj !== "object") {
115
- return obj;
116
- }
117
- const record = obj;
118
- const result = {};
119
- for (const [key, value] of Object.entries(record)) {
120
- if (value === null || value === void 0) {
121
- continue;
122
- }
123
- result[key] = stripResponse(value);
124
- }
125
- return result;
126
- }
127
-
128
109
  // src/utils/output.ts
129
110
  var prettyPrint = false;
130
111
  function setPretty(value) {
131
112
  prettyPrint = value;
132
113
  }
133
114
  function output(data) {
134
- process.stdout.write(`${JSON.stringify(stripResponse(data), null, prettyPrint ? 2 : void 0)}
115
+ process.stdout.write(`${JSON.stringify(data, null, prettyPrint ? 2 : void 0)}
135
116
  `);
136
117
  }
137
118
  function handleError(err) {
@@ -197,35 +178,166 @@ function handleError(err) {
197
178
  process.exit(1);
198
179
  }
199
180
 
181
+ // src/utils/transformers/base.ts
182
+ function bamboohrBaseUrl() {
183
+ return `https://${process.env.BAMBOO_COMPANY_DOMAIN ?? ""}.bamboohr.com`;
184
+ }
185
+ function stripNullish(value) {
186
+ if (Array.isArray(value)) {
187
+ return value.map(stripNullish);
188
+ }
189
+ if (value === null || typeof value !== "object") {
190
+ return value;
191
+ }
192
+ const record = value;
193
+ const result = {};
194
+ for (const [key, v] of Object.entries(record)) {
195
+ if (v === null || v === void 0) {
196
+ continue;
197
+ }
198
+ result[key] = stripNullish(v);
199
+ }
200
+ return result;
201
+ }
202
+
203
+ // src/utils/transformers/employee.ts
204
+ function employeeUrl(id) {
205
+ return `${bamboohrBaseUrl()}/employees/employee.php?id=${id}`;
206
+ }
207
+ function transformEmployee(employee, opts = {}) {
208
+ const { photoUrl, canUploadPhoto: _canUploadPhoto, photoUploaded, ...rest } = employee;
209
+ const id = typeof rest.id === "string" ? rest.id : void 0;
210
+ const withUrl = id ? { ...rest, url: employeeUrl(id) } : { ...rest };
211
+ if (opts.withPhotos) {
212
+ if (photoUrl !== null && photoUrl !== void 0) {
213
+ withUrl.photoUrl = photoUrl;
214
+ }
215
+ if (photoUploaded !== null && photoUploaded !== void 0) {
216
+ withUrl.photoUploaded = photoUploaded;
217
+ }
218
+ }
219
+ return stripNullish(withUrl);
220
+ }
221
+ function transformEmployeeDirectory(directory2, opts = {}) {
222
+ return { employees: directory2.employees.map((e) => transformEmployee(e, opts)) };
223
+ }
224
+
225
+ // src/utils/transformers/goal.ts
226
+ function transformGoalMilestone(milestone) {
227
+ return stripNullish(milestone);
228
+ }
229
+ function transformGoal(goal) {
230
+ const { milestones, ...rest } = goal;
231
+ const shaped = {
232
+ ...rest,
233
+ ...milestones && { milestones: milestones.map(transformGoalMilestone) }
234
+ };
235
+ return stripNullish(shaped);
236
+ }
237
+ function transformGoals(response) {
238
+ return { goals: response.goals.map(transformGoal) };
239
+ }
240
+
241
+ // src/utils/transformers/timeoff.ts
242
+ function transformTimeOffRequest(request) {
243
+ const { actions: _actions, ...rest } = request;
244
+ return stripNullish(rest);
245
+ }
246
+ function transformTimeOffRequests(requests2) {
247
+ return requests2.map(transformTimeOffRequest);
248
+ }
249
+ function transformTimeOffBalance(balance2) {
250
+ return stripNullish(balance2);
251
+ }
252
+ function transformTimeOffBalances(balances) {
253
+ return balances.map(transformTimeOffBalance);
254
+ }
255
+ function transformTimeOffType(type) {
256
+ return stripNullish(type);
257
+ }
258
+ function transformTimeOffTypesResponse(response) {
259
+ return {
260
+ timeOffTypes: response.timeOffTypes.map(transformTimeOffType),
261
+ defaultHours: response.defaultHours
262
+ };
263
+ }
264
+ function transformWhosOutEvent(event) {
265
+ return stripNullish(event);
266
+ }
267
+ function transformWhosOut(events) {
268
+ return events.map(transformWhosOutEvent);
269
+ }
270
+
271
+ // src/utils/transformers/file.ts
272
+ function transformCompanyFile(file) {
273
+ const {
274
+ shareWithEmployees: _shareWithEmployees,
275
+ canRenameFile: _canRenameFile,
276
+ canDeleteFile: _canDeleteFile,
277
+ ...rest
278
+ } = file;
279
+ return stripNullish(rest);
280
+ }
281
+ function transformCompanyFileCategory(category) {
282
+ const { files, canUploadFiles: _canUploadFiles, ...rest } = category;
283
+ return stripNullish({ ...rest, files: files.map(transformCompanyFile) });
284
+ }
285
+ function transformCompanyFiles(response) {
286
+ return { categories: response.categories.map(transformCompanyFileCategory) };
287
+ }
288
+
289
+ // src/utils/transformers/meta.ts
290
+ function transformField(field) {
291
+ return stripNullish(field);
292
+ }
293
+ function transformFields(fields2) {
294
+ return fields2.map(transformField);
295
+ }
296
+
200
297
  // src/commands/employee/directory.ts
201
298
  function directory(parent) {
202
- parent.command("directory").description("Get the company employee directory").addHelpText("after", "\nExamples:\n $ bamboohr employee directory").action(async () => {
299
+ parent.command("directory").description("Get the company employee directory").option("--with-photos", "Include each employee's signed photo URL and photoUploaded flag (large)").addHelpText(
300
+ "after",
301
+ `
302
+ Examples:
303
+ $ bamboohr employee directory
304
+ $ bamboohr employee directory --with-photos`
305
+ ).action(async (opts) => {
203
306
  const client = getClient();
204
307
  const result = await getDirectory(client);
205
- output(result);
308
+ output(transformEmployeeDirectory(result, { withPhotos: opts.withPhotos }));
206
309
  });
207
310
  }
208
311
 
209
312
  // src/commands/employee/get.ts
210
313
  function get(parent) {
211
- parent.command("get [id]").description("Get employee data by ID (default: current user)").option("--fields <fields>", "Comma-separated field names", "firstName,lastName,email,jobTitle").option("--include-future", "Include future-dated values from history fields").addHelpText(
314
+ parent.command("get [id]").description("Get employee data by ID (default: current user)").option("--fields <fields>", "Comma-separated field names", "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").addHelpText(
212
315
  "after",
213
316
  `
214
317
  Examples:
215
318
  $ bamboohr employee get
216
319
  $ bamboohr employee get 123
217
320
  $ bamboohr employee get 123 --fields "firstName,lastName,department,hireDate"
218
- $ bamboohr employee get 123 --include-future`
321
+ $ bamboohr employee get 123 --include-future
322
+ $ bamboohr employee get 123 --with-photos`
219
323
  ).action(async (id, opts) => {
220
324
  const client = getClient();
325
+ const fields2 = opts.withPhotos ? mergeFields(opts.fields, ["photoUrl", "photoUploaded"]) : opts.fields;
221
326
  const result = await client.employees.get({
222
327
  id: id ?? "0",
223
- fields: opts.fields,
328
+ fields: fields2,
224
329
  onlyCurrent: !opts.includeFuture
225
330
  });
226
- output(result);
331
+ output(transformEmployee(result, { withPhotos: opts.withPhotos }));
227
332
  });
228
333
  }
334
+ function mergeFields(existing, extra) {
335
+ const set = new Set(
336
+ existing.split(",").map((s) => s.trim()).filter(Boolean)
337
+ );
338
+ for (const f of extra) set.add(f);
339
+ return [...set].join(",");
340
+ }
229
341
 
230
342
  // src/commands/employee/goals.ts
231
343
  import { Option } from "commander";
@@ -243,7 +355,7 @@ Examples:
243
355
  employeeId: id,
244
356
  filter: opts.filter === "all" ? void 0 : opts.filter
245
357
  });
246
- output(result);
358
+ output(transformGoals(result));
247
359
  });
248
360
  }
249
361
 
@@ -278,14 +390,15 @@ async function resolveEmployeeId(client, employeeId) {
278
390
 
279
391
  // src/commands/employee/search.ts
280
392
  function search(parent) {
281
- parent.command("search [query]").description("Search and filter employees").option("--supervisor <name>", 'Filter by supervisor name (use "me" for current user)').option("--department <name>", "Filter by department").option("--location <name>", "Filter by location").option("--division <name>", "Filter by division").addHelpText(
393
+ parent.command("search [query]").description("Search and filter employees").option("--supervisor <name>", 'Filter by supervisor name (use "me" for current user)').option("--department <name>", "Filter by department").option("--location <name>", "Filter by location").option("--division <name>", "Filter by division").option("--with-photos", "Include each result's signed photo URL and photoUploaded flag").addHelpText(
282
394
  "after",
283
395
  `
284
396
  Examples:
285
397
  bamboohr employee search john
286
398
  bamboohr employee search --supervisor me
287
399
  bamboohr employee search --department "R&D" --location Sofia
288
- bamboohr employee search --supervisor "Borislav Mihaylov"`
400
+ bamboohr employee search --supervisor "Borislav Mihaylov"
401
+ bamboohr employee search john --with-photos`
289
402
  ).action(
290
403
  async (query, opts) => {
291
404
  const client = getClient();
@@ -320,7 +433,7 @@ Examples:
320
433
  const dv = opts.division.toLowerCase();
321
434
  matches = matches.filter((e) => (e.division ?? "").toLowerCase().includes(dv));
322
435
  }
323
- output(matches);
436
+ output(matches.map((e) => transformEmployee(e, { withPhotos: opts.withPhotos })));
324
437
  }
325
438
  );
326
439
  }
@@ -366,7 +479,7 @@ function list(parent) {
366
479
  parent.command("list").description("List all company files and categories").addHelpText("after", "\nExamples:\n $ bamboohr file list").action(async () => {
367
480
  const client = getClient();
368
481
  const result = await client.files.list();
369
- output(result);
482
+ output(transformCompanyFiles(result));
370
483
  });
371
484
  }
372
485
 
@@ -409,7 +522,7 @@ function fields(parent) {
409
522
  parent.command("fields").description("List all available BambooHR fields").addHelpText("after", "\nExamples:\n $ bamboohr meta fields").action(async () => {
410
523
  const client = getClient();
411
524
  const result = await getMetaFields(client);
412
- output(result);
525
+ output(transformFields(result));
413
526
  });
414
527
  }
415
528
 
@@ -454,7 +567,7 @@ Examples:
454
567
  const client = getClient();
455
568
  const id = await resolveEmployeeId(client, employeeId);
456
569
  const result = await client.timeOff.getBalance({ employeeId: id, date: opts.date });
457
- output(result);
570
+ output(transformTimeOffBalances(result));
458
571
  });
459
572
  }
460
573
 
@@ -495,7 +608,7 @@ Examples:
495
608
  notes: opts.note ? [{ from: "employee", note: opts.note }] : void 0,
496
609
  dates: opts.dates ? JSON.parse(opts.dates) : void 0
497
610
  });
498
- output(result || { created: true, employeeId: id, start: opts.start, end: opts.end });
611
+ output(result ? stripNullish(result) : { created: true, employeeId: id, start: opts.start, end: opts.end });
499
612
  }
500
613
  );
501
614
  }
@@ -538,7 +651,7 @@ Examples:
538
651
  status: opts.status,
539
652
  type: opts.type
540
653
  });
541
- output(result);
654
+ output(transformTimeOffRequests(result));
542
655
  }
543
656
  );
544
657
  }
@@ -554,7 +667,7 @@ Examples:
554
667
  ).action(async (opts) => {
555
668
  const client = getClient();
556
669
  const result = opts.requestable ? await client.timeOff.getTypes({ mode: "request" }) : await getTimeOffTypes(client);
557
- output(result);
670
+ output(transformTimeOffTypesResponse(result));
558
671
  });
559
672
  }
560
673
 
@@ -577,7 +690,7 @@ Examples:
577
690
  status: opts.status,
578
691
  note: opts.note
579
692
  });
580
- output(result || { updated: true, requestId, status: opts.status });
693
+ output(result ? stripNullish(result) : { updated: true, requestId, status: opts.status });
581
694
  });
582
695
  }
583
696
 
@@ -595,7 +708,7 @@ Examples:
595
708
  const start = opts.start ?? today;
596
709
  const end = opts.end ?? (opts.start ? void 0 : today);
597
710
  const result = await client.timeOff.getWhosOut({ start, end });
598
- output(result);
711
+ output(transformWhosOut(result));
599
712
  });
600
713
  }
601
714
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bamboohr-cli",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "publish": true,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,7 @@
12
12
  ],
13
13
  "dependencies": {
14
14
  "commander": "^13.1.0",
15
- "bamboohr-client": "1.0.22"
15
+ "bamboohr-client": "1.0.23"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "24.10.4",
@@ -22,8 +22,8 @@
22
22
  "tsx": "^4.19.2",
23
23
  "typescript": "^5.7.2",
24
24
  "vitest": "^4.0.16",
25
- "cli-utils": "1.0.0",
26
25
  "config-eslint": "0.0.0",
26
+ "cli-utils": "1.0.0",
27
27
  "config-typescript": "0.0.0"
28
28
  },
29
29
  "engines": {