@typeb-digital/nucleus-sdk 0.0.6 → 0.1.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.
@@ -68,6 +68,44 @@ class NucleusTransport {
68
68
  return makeErrorResult('NETWORK_ERROR', String(err));
69
69
  }
70
70
  }
71
+ async put(path, body) {
72
+ try {
73
+ const envelope = await ofetch.$fetch(`${this.baseUrl}${path}`, {
74
+ method: 'PUT',
75
+ headers: this.headers,
76
+ body: JSON.stringify(body)
77
+ });
78
+ if (!envelope.success) return makeErrorResult('FORBIDDEN', envelope.error);
79
+ return {
80
+ data: envelope.data
81
+ };
82
+ } catch (err) {
83
+ if (err instanceof ofetch.FetchError) {
84
+ const errBody = err.data;
85
+ return makeErrorResult(statusToCode(err.status ?? 0, errBody?.error), err.message);
86
+ }
87
+ return makeErrorResult('NETWORK_ERROR', String(err));
88
+ }
89
+ }
90
+ async patch(path, body) {
91
+ try {
92
+ const envelope = await ofetch.$fetch(`${this.baseUrl}${path}`, {
93
+ method: 'PATCH',
94
+ headers: this.headers,
95
+ body: JSON.stringify(body)
96
+ });
97
+ if (!envelope.success) return makeErrorResult('FORBIDDEN', envelope.error);
98
+ return {
99
+ data: envelope.data
100
+ };
101
+ } catch (err) {
102
+ if (err instanceof ofetch.FetchError) {
103
+ const errBody = err.data;
104
+ return makeErrorResult(statusToCode(err.status ?? 0, errBody?.error), err.message);
105
+ }
106
+ return makeErrorResult('NETWORK_ERROR', String(err));
107
+ }
108
+ }
71
109
  async del(path, query) {
72
110
  try {
73
111
  const params = query ? Object.fromEntries(Object.entries(query).filter(([, v])=>v !== undefined)) : undefined;
@@ -124,7 +162,20 @@ class NucleusTransport {
124
162
  /**
125
163
  * Transform utilities — map snake_case Prisma API responses to camelCase SDK types.
126
164
  * Each function accepts `unknown` so it works regardless of which buckets were active.
127
- */ function str(v) {
165
+ */ /**
166
+ * Serialize a camelCase mutation input to the snake_case body the API expects.
167
+ * Shallow is sufficient — write bodies are flat. `undefined` keys are dropped;
168
+ * `null` is preserved (explicit clear).
169
+ */ function toSnakeBody(input) {
170
+ const out = {};
171
+ for (const [key, value] of Object.entries(input)){
172
+ if (value === undefined) continue;
173
+ const snake = key.replace(/[A-Z]/g, (m)=>`_${m.toLowerCase()}`);
174
+ out[snake] = value;
175
+ }
176
+ return out;
177
+ }
178
+ function str(v) {
128
179
  return typeof v === 'string' ? v : null;
129
180
  }
130
181
  function num(v) {
@@ -157,6 +208,7 @@ function transformCompensation(raw) {
157
208
  hourlyBillableRate: num(r['hourly_billable_rate']),
158
209
  monthlyCostRate: num(r['monthly_cost_rate']),
159
210
  monthlyBillableRate: num(r['monthly_billable_rate']),
211
+ salary: num(r['salary']),
160
212
  currencyCode: str(r['currency_code']) ?? 'USD',
161
213
  effectiveFrom: str(r['effective_from']) ?? ''
162
214
  };
@@ -168,6 +220,7 @@ function transformCompensationHistoryEntry(raw) {
168
220
  hourlyBillableRate: num(r['hourly_billable_rate']),
169
221
  monthlyCostRate: num(r['monthly_cost_rate']),
170
222
  monthlyBillableRate: num(r['monthly_billable_rate']),
223
+ salary: num(r['salary']),
171
224
  currencyCode: str(r['currency_code']) ?? 'USD',
172
225
  effectiveFrom: str(r['effective_from']) ?? '',
173
226
  effectiveTo: str(r['effective_to'])
@@ -187,6 +240,7 @@ function transformEmployee(raw) {
187
240
  if ('job_title' in r) out['jobTitle'] = str(r['job_title']);
188
241
  if ('department' in r) out['department'] = str(r['department']);
189
242
  if ('employment_status' in r) out['employmentStatus'] = str(r['employment_status']);
243
+ if ('employment_type' in r) out['employmentType'] = str(r['employment_type']);
190
244
  if ('is_external' in r) out['isExternal'] = bool(r['is_external']);
191
245
  // employment
192
246
  if ('start_date' in r) out['startDate'] = str(r['start_date']);
@@ -247,6 +301,11 @@ function transformProject(raw) {
247
301
  return entry;
248
302
  });
249
303
  }
304
+ // financials
305
+ if ('contract_value' in r) out['contractValue'] = num(r['contract_value']);
306
+ if ('budget' in r) out['budget'] = num(r['budget']);
307
+ if ('margin_target' in r) out['marginTarget'] = num(r['margin_target']);
308
+ if ('financials_currency' in r) out['financialsCurrency'] = str(r['financials_currency']);
250
309
  // integrations
251
310
  if ('source' in r) out['source'] = str(r['source']);
252
311
  if ('clockify_project_id' in r) out['clockifyProjectId'] = str(r['clockify_project_id']);
@@ -346,6 +405,155 @@ function transformGenericRate(raw) {
346
405
  if ('billable_rate' in r) out['billableRate'] = num(r['billable_rate']);
347
406
  return out;
348
407
  }
408
+ function transformJurisdiction(raw) {
409
+ if (!raw || typeof raw !== 'object') return {};
410
+ const r = raw;
411
+ const out = {};
412
+ if ('id' in r) out['id'] = r['id'];
413
+ if ('name' in r) out['name'] = str(r['name']);
414
+ if ('code' in r) out['code'] = str(r['code']);
415
+ if ('country' in r) out['country'] = str(r['country']);
416
+ return out;
417
+ }
418
+ function transformLeaveType(raw) {
419
+ if (!raw || typeof raw !== 'object') return {};
420
+ const r = raw;
421
+ const out = {};
422
+ if ('id' in r) out['id'] = r['id'];
423
+ if ('name' in r) out['name'] = str(r['name']);
424
+ if ('description' in r) out['description'] = str(r['description']);
425
+ if ('color' in r) out['color'] = str(r['color']);
426
+ if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
427
+ return out;
428
+ }
429
+ function transformLeave(raw) {
430
+ if (!raw || typeof raw !== 'object') return {};
431
+ const r = raw;
432
+ const out = {};
433
+ // core
434
+ if ('id' in r) out['id'] = r['id'];
435
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
436
+ if ('leave_type_id' in r) out['leaveTypeId'] = str(r['leave_type_id']);
437
+ if ('start_date' in r) out['startDate'] = str(r['start_date']);
438
+ if ('end_date' in r) out['endDate'] = str(r['end_date']);
439
+ if ('days' in r) out['days'] = num(r['days']);
440
+ if ('status' in r) out['status'] = str(r['status']);
441
+ if ('source' in r) out['source'] = str(r['source']);
442
+ // details
443
+ if ('reason' in r) out['reason'] = str(r['reason']);
444
+ // expand: employee / leaveType
445
+ if ('employee' in r) {
446
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
447
+ }
448
+ if ('leave_type' in r || 'leaveType' in r) {
449
+ const lt = r['leave_type'] ?? r['leaveType'];
450
+ out['leaveType'] = lt ? transformLeaveType(lt) : null;
451
+ }
452
+ return out;
453
+ }
454
+ function transformLeaveBalance(raw) {
455
+ if (!raw || typeof raw !== 'object') return {};
456
+ const r = raw;
457
+ const out = {};
458
+ // core
459
+ if ('id' in r) out['id'] = r['id'];
460
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
461
+ if ('leave_type_id' in r) out['leaveTypeId'] = str(r['leave_type_id']);
462
+ if ('year' in r) out['year'] = num(r['year']);
463
+ if ('balance_days' in r) out['balanceDays'] = num(r['balance_days']);
464
+ // expand: employee / leaveType
465
+ if ('employee' in r) {
466
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
467
+ }
468
+ if ('leave_type' in r || 'leaveType' in r) {
469
+ const lt = r['leave_type'] ?? r['leaveType'];
470
+ out['leaveType'] = lt ? transformLeaveType(lt) : null;
471
+ }
472
+ return out;
473
+ }
474
+ function transformPolicy(raw) {
475
+ if (!raw || typeof raw !== 'object') return {};
476
+ const r = raw;
477
+ const out = {};
478
+ // core
479
+ if ('id' in r) out['id'] = r['id'];
480
+ if ('title' in r) out['title'] = str(r['title']);
481
+ if ('code' in r) out['code'] = str(r['code']);
482
+ if ('category' in r) out['category'] = str(r['category']);
483
+ if ('description' in r) out['description'] = str(r['description']);
484
+ if ('current_version' in r) out['currentVersion'] = num(r['current_version']) ?? 1;
485
+ if ('requires_acknowledgement' in r) {
486
+ out['requiresAcknowledgement'] = bool(r['requires_acknowledgement']);
487
+ }
488
+ if ('is_published' in r) out['isPublished'] = bool(r['is_published']);
489
+ // content
490
+ if ('body' in r) out['body'] = str(r['body']);
491
+ if ('file_key' in r) out['fileKey'] = str(r['file_key']);
492
+ return out;
493
+ }
494
+ function transformPolicyAcknowledgement(raw) {
495
+ if (!raw || typeof raw !== 'object') return {};
496
+ const r = raw;
497
+ const out = {};
498
+ // core
499
+ if ('id' in r) out['id'] = r['id'];
500
+ if ('policy_id' in r) out['policyId'] = str(r['policy_id']);
501
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
502
+ if ('version' in r) out['version'] = num(r['version']);
503
+ if ('acknowledged_at' in r) out['acknowledgedAt'] = str(r['acknowledged_at']);
504
+ // expand: employee / policy
505
+ if ('employee' in r) {
506
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
507
+ }
508
+ if ('policy' in r) {
509
+ out['policy'] = r['policy'] ? transformPolicy(r['policy']) : null;
510
+ }
511
+ return out;
512
+ }
513
+ function transformCalendarEvent(raw) {
514
+ if (!raw || typeof raw !== 'object') return {};
515
+ const r = raw;
516
+ const out = {};
517
+ if ('id' in r) out['id'] = r['id'];
518
+ if ('title' in r) out['title'] = str(r['title']);
519
+ if ('description' in r) out['description'] = str(r['description']);
520
+ if ('start_date' in r) out['startDate'] = str(r['start_date']);
521
+ if ('end_date' in r) out['endDate'] = str(r['end_date']);
522
+ if ('all_day' in r) out['allDay'] = bool(r['all_day']);
523
+ if ('type' in r) out['type'] = str(r['type']);
524
+ if ('location' in r) out['location'] = str(r['location']);
525
+ if ('color' in r) out['color'] = str(r['color']);
526
+ if ('is_published' in r) out['isPublished'] = bool(r['is_published']);
527
+ return out;
528
+ }
529
+ function transformTimesheet(raw) {
530
+ if (!raw || typeof raw !== 'object') return {};
531
+ const r = raw;
532
+ const out = {};
533
+ // core
534
+ if ('id' in r) out['id'] = r['id'];
535
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
536
+ if ('project_id' in r) out['projectId'] = str(r['project_id']);
537
+ if ('start_time' in r) out['startTime'] = str(r['start_time']);
538
+ if ('end_time' in r) out['endTime'] = str(r['end_time']);
539
+ if ('duration_minutes' in r) out['durationMinutes'] = num(r['duration_minutes']);
540
+ if ('billable' in r) out['billable'] = bool(r['billable']);
541
+ // details
542
+ if ('description' in r) out['description'] = str(r['description']);
543
+ if ('activity_name' in r) out['activityName'] = str(r['activity_name']);
544
+ // integrations
545
+ if ('source' in r) out['source'] = str(r['source']);
546
+ if ('kimai_id' in r) out['kimaiId'] = str(r['kimai_id']);
547
+ if ('kimai_activity_id' in r) out['kimaiActivityId'] = str(r['kimai_activity_id']);
548
+ // expand: employee / project
549
+ if ('employee' in r) {
550
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
551
+ }
552
+ if ('project' in r) {
553
+ out['project'] = r['project'] ? transformProject(r['project']) : null;
554
+ }
555
+ return out;
556
+ }
349
557
 
350
558
  class EmployeesAccessor {
351
559
  constructor(transport){
@@ -405,6 +613,27 @@ class ProjectsAccessor {
405
613
  data: transformProject(result.data)
406
614
  };
407
615
  }
616
+ /** Create a project. Requires `projects.create` scope. */ async create(data) {
617
+ const result = await this.transport.post('/api/v1/data/projects', toSnakeBody(data));
618
+ if ('error' in result) return result;
619
+ return {
620
+ data: transformProject(result.data)
621
+ };
622
+ }
623
+ /** Update a project. Requires `projects.update` scope. */ async update(id, data) {
624
+ const result = await this.transport.put(`/api/v1/data/projects/${id}`, toSnakeBody(data));
625
+ if ('error' in result) return result;
626
+ return {
627
+ data: transformProject(result.data)
628
+ };
629
+ }
630
+ /** Soft-delete a project. Requires `projects.delete` scope. */ async delete(id) {
631
+ const result = await this.transport.del(`/api/v1/data/projects/${id}`);
632
+ if ('error' in result) return result;
633
+ return {
634
+ data: null
635
+ };
636
+ }
408
637
  }
409
638
 
410
639
  class ClientsAccessor {
@@ -435,6 +664,27 @@ class ClientsAccessor {
435
664
  data: transformClient(result.data)
436
665
  };
437
666
  }
667
+ /** Create a client. Requires `clients.create` scope. */ async create(data) {
668
+ const result = await this.transport.post('/api/v1/data/clients', toSnakeBody(data));
669
+ if ('error' in result) return result;
670
+ return {
671
+ data: transformClient(result.data)
672
+ };
673
+ }
674
+ /** Update a client. Requires `clients.update` scope. */ async update(id, data) {
675
+ const result = await this.transport.put(`/api/v1/data/clients/${id}`, toSnakeBody(data));
676
+ if ('error' in result) return result;
677
+ return {
678
+ data: transformClient(result.data)
679
+ };
680
+ }
681
+ /** Soft-delete a client. Requires `clients.delete` scope. */ async delete(id) {
682
+ const result = await this.transport.del(`/api/v1/data/clients/${id}`);
683
+ if ('error' in result) return result;
684
+ return {
685
+ data: null
686
+ };
687
+ }
438
688
  }
439
689
 
440
690
  class PartnersAccessor {
@@ -463,6 +713,27 @@ class PartnersAccessor {
463
713
  data: transformPartner(result.data)
464
714
  };
465
715
  }
716
+ /** Create a partner. Requires `partners.create` scope. */ async create(data) {
717
+ const result = await this.transport.post('/api/v1/data/partners', toSnakeBody(data));
718
+ if ('error' in result) return result;
719
+ return {
720
+ data: transformPartner(result.data)
721
+ };
722
+ }
723
+ /** Update a partner. Requires `partners.update` scope. */ async update(id, data) {
724
+ const result = await this.transport.put(`/api/v1/data/partners/${id}`, toSnakeBody(data));
725
+ if ('error' in result) return result;
726
+ return {
727
+ data: transformPartner(result.data)
728
+ };
729
+ }
730
+ /** Soft-delete a partner. Requires `partners.delete` scope. */ async delete(id) {
731
+ const result = await this.transport.del(`/api/v1/data/partners/${id}`);
732
+ if ('error' in result) return result;
733
+ return {
734
+ data: null
735
+ };
736
+ }
466
737
  }
467
738
 
468
739
  class DepartmentsAccessor {
@@ -488,6 +759,27 @@ class DepartmentsAccessor {
488
759
  data: transformDepartment(result.data)
489
760
  };
490
761
  }
762
+ /** Create a department. Requires `departments.create` scope. */ async create(data) {
763
+ const result = await this.transport.post('/api/v1/data/departments', toSnakeBody(data));
764
+ if ('error' in result) return result;
765
+ return {
766
+ data: transformDepartment(result.data)
767
+ };
768
+ }
769
+ /** Update a department. Requires `departments.update` scope. */ async update(id, data) {
770
+ const result = await this.transport.put(`/api/v1/data/departments/${id}`, toSnakeBody(data));
771
+ if ('error' in result) return result;
772
+ return {
773
+ data: transformDepartment(result.data)
774
+ };
775
+ }
776
+ /** Soft-delete a department. Requires `departments.delete` scope. */ async delete(id) {
777
+ const result = await this.transport.del(`/api/v1/data/departments/${id}`);
778
+ if ('error' in result) return result;
779
+ return {
780
+ data: null
781
+ };
782
+ }
491
783
  }
492
784
 
493
785
  class ProjectTypesAccessor {
@@ -512,6 +804,27 @@ class ProjectTypesAccessor {
512
804
  data: transformProjectType(result.data)
513
805
  };
514
806
  }
807
+ /** Create a project type. Requires `projectTypes.create` scope. */ async create(data) {
808
+ const result = await this.transport.post('/api/v1/data/project-types', toSnakeBody(data));
809
+ if ('error' in result) return result;
810
+ return {
811
+ data: transformProjectType(result.data)
812
+ };
813
+ }
814
+ /** Update a project type. Requires `projectTypes.update` scope. */ async update(id, data) {
815
+ const result = await this.transport.put(`/api/v1/data/project-types/${id}`, toSnakeBody(data));
816
+ if ('error' in result) return result;
817
+ return {
818
+ data: transformProjectType(result.data)
819
+ };
820
+ }
821
+ /** Soft-delete a project type. Requires `projectTypes.delete` scope. */ async delete(id) {
822
+ const result = await this.transport.del(`/api/v1/data/project-types/${id}`);
823
+ if ('error' in result) return result;
824
+ return {
825
+ data: null
826
+ };
827
+ }
515
828
  }
516
829
 
517
830
  class CurrenciesAccessor {
@@ -536,6 +849,30 @@ class CurrenciesAccessor {
536
849
  data: transformCurrency(result.data)
537
850
  };
538
851
  }
852
+ /** Create a currency. Requires `currencies.create` scope. */ async create(data) {
853
+ const result = await this.transport.post('/api/v1/data/currencies', toSnakeBody(data));
854
+ if ('error' in result) return result;
855
+ return {
856
+ data: transformCurrency(result.data)
857
+ };
858
+ }
859
+ /**
860
+ * Update a currency (keyed by its ISO code; `code` itself is immutable).
861
+ * Requires `currencies.update` scope.
862
+ */ async update(code, data) {
863
+ const result = await this.transport.put(`/api/v1/data/currencies/${code}`, toSnakeBody(data));
864
+ if ('error' in result) return result;
865
+ return {
866
+ data: transformCurrency(result.data)
867
+ };
868
+ }
869
+ /** Soft-delete a currency (keyed by its ISO code). Requires `currencies.delete` scope. */ async delete(code) {
870
+ const result = await this.transport.del(`/api/v1/data/currencies/${code}`);
871
+ if ('error' in result) return result;
872
+ return {
873
+ data: null
874
+ };
875
+ }
539
876
  }
540
877
 
541
878
  class GenericRatesAccessor {
@@ -561,6 +898,415 @@ class GenericRatesAccessor {
561
898
  data: transformGenericRate(result.data)
562
899
  };
563
900
  }
901
+ /** Create a generic rate. Requires `genericRates.create` scope. */ async create(data) {
902
+ const result = await this.transport.post('/api/v1/data/generic-rates', toSnakeBody(data));
903
+ if ('error' in result) return result;
904
+ return {
905
+ data: transformGenericRate(result.data)
906
+ };
907
+ }
908
+ /** Update a generic rate. Requires `genericRates.update` scope. */ async update(id, data) {
909
+ const result = await this.transport.put(`/api/v1/data/generic-rates/${id}`, toSnakeBody(data));
910
+ if ('error' in result) return result;
911
+ return {
912
+ data: transformGenericRate(result.data)
913
+ };
914
+ }
915
+ /** Soft-delete a generic rate. Requires `genericRates.delete` scope. */ async delete(id) {
916
+ const result = await this.transport.del(`/api/v1/data/generic-rates/${id}`);
917
+ if ('error' in result) return result;
918
+ return {
919
+ data: null
920
+ };
921
+ }
922
+ }
923
+
924
+ class JurisdictionsAccessor {
925
+ constructor(transport){
926
+ this.transport = transport;
927
+ }
928
+ async list(params) {
929
+ const query = {};
930
+ if (params?.search) query['search'] = params.search;
931
+ if (params?.page) query['page'] = params.page;
932
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
933
+ const result = await this.transport.getList('/api/v1/data/jurisdictions', query);
934
+ if ('error' in result) return result;
935
+ return {
936
+ data: result.data.map((r)=>transformJurisdiction(r)),
937
+ meta: result.meta
938
+ };
939
+ }
940
+ async getById(id) {
941
+ const result = await this.transport.get(`/api/v1/data/jurisdictions/${id}`);
942
+ if ('error' in result) return result;
943
+ return {
944
+ data: transformJurisdiction(result.data)
945
+ };
946
+ }
947
+ /** Create a jurisdiction. Requires `jurisdictions.create` scope. */ async create(data) {
948
+ const result = await this.transport.post('/api/v1/data/jurisdictions', toSnakeBody(data));
949
+ if ('error' in result) return result;
950
+ return {
951
+ data: transformJurisdiction(result.data)
952
+ };
953
+ }
954
+ /** Update a jurisdiction. Requires `jurisdictions.update` scope. */ async update(id, data) {
955
+ const result = await this.transport.put(`/api/v1/data/jurisdictions/${id}`, toSnakeBody(data));
956
+ if ('error' in result) return result;
957
+ return {
958
+ data: transformJurisdiction(result.data)
959
+ };
960
+ }
961
+ /** Soft-delete a jurisdiction. Requires `jurisdictions.delete` scope. */ async delete(id) {
962
+ const result = await this.transport.del(`/api/v1/data/jurisdictions/${id}`);
963
+ if ('error' in result) return result;
964
+ return {
965
+ data: null
966
+ };
967
+ }
968
+ }
969
+
970
+ class LeaveTypesAccessor {
971
+ constructor(transport){
972
+ this.transport = transport;
973
+ }
974
+ async list(params) {
975
+ const query = {};
976
+ if (params?.search) query['search'] = params.search;
977
+ if (params?.page) query['page'] = params.page;
978
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
979
+ const result = await this.transport.getList('/api/v1/data/leave-types', query);
980
+ if ('error' in result) return result;
981
+ return {
982
+ data: result.data.map((r)=>transformLeaveType(r)),
983
+ meta: result.meta
984
+ };
985
+ }
986
+ async getById(id) {
987
+ const result = await this.transport.get(`/api/v1/data/leave-types/${id}`);
988
+ if ('error' in result) return result;
989
+ return {
990
+ data: transformLeaveType(result.data)
991
+ };
992
+ }
993
+ /** Create a leave type. Requires `leaveTypes.create` scope. */ async create(data) {
994
+ const result = await this.transport.post('/api/v1/data/leave-types', toSnakeBody(data));
995
+ if ('error' in result) return result;
996
+ return {
997
+ data: transformLeaveType(result.data)
998
+ };
999
+ }
1000
+ /** Update a leave type. Requires `leaveTypes.update` scope. */ async update(id, data) {
1001
+ const result = await this.transport.put(`/api/v1/data/leave-types/${id}`, toSnakeBody(data));
1002
+ if ('error' in result) return result;
1003
+ return {
1004
+ data: transformLeaveType(result.data)
1005
+ };
1006
+ }
1007
+ /** Soft-delete a leave type. Requires `leaveTypes.delete` scope. */ async delete(id) {
1008
+ const result = await this.transport.del(`/api/v1/data/leave-types/${id}`);
1009
+ if ('error' in result) return result;
1010
+ return {
1011
+ data: null
1012
+ };
1013
+ }
1014
+ }
1015
+
1016
+ class LeavesAccessor {
1017
+ constructor(transport){
1018
+ this.transport = transport;
1019
+ }
1020
+ async list(params) {
1021
+ const query = {};
1022
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1023
+ if (params?.leaveTypeId) query['leaveTypeId'] = params.leaveTypeId;
1024
+ if (params?.status) query['status'] = params.status;
1025
+ if (params?.page) query['page'] = params.page;
1026
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1027
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1028
+ const result = await this.transport.getList('/api/v1/data/leaves', query);
1029
+ if ('error' in result) return result;
1030
+ return {
1031
+ data: result.data.map((r)=>transformLeave(r)),
1032
+ meta: result.meta
1033
+ };
1034
+ }
1035
+ async getById(id, options) {
1036
+ const query = {};
1037
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1038
+ const result = await this.transport.get(`/api/v1/data/leaves/${id}`, query);
1039
+ if ('error' in result) return result;
1040
+ return {
1041
+ data: transformLeave(result.data)
1042
+ };
1043
+ }
1044
+ /** Create a leave record. Requires `leaves.create` scope. */ async create(data) {
1045
+ const result = await this.transport.post('/api/v1/data/leaves', toSnakeBody(data));
1046
+ if ('error' in result) return result;
1047
+ return {
1048
+ data: transformLeave(result.data)
1049
+ };
1050
+ }
1051
+ /** Update a leave record. Requires `leaves.update` scope. */ async update(id, data) {
1052
+ const result = await this.transport.put(`/api/v1/data/leaves/${id}`, toSnakeBody(data));
1053
+ if ('error' in result) return result;
1054
+ return {
1055
+ data: transformLeave(result.data)
1056
+ };
1057
+ }
1058
+ /** Soft-delete a leave record. Requires `leaves.delete` scope. */ async delete(id) {
1059
+ const result = await this.transport.del(`/api/v1/data/leaves/${id}`);
1060
+ if ('error' in result) return result;
1061
+ return {
1062
+ data: null
1063
+ };
1064
+ }
1065
+ }
1066
+
1067
+ class LeaveBalancesAccessor {
1068
+ constructor(transport){
1069
+ this.transport = transport;
1070
+ }
1071
+ async list(params) {
1072
+ const query = {};
1073
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1074
+ if (params?.leaveTypeId) query['leaveTypeId'] = params.leaveTypeId;
1075
+ if (params?.year) query['year'] = params.year;
1076
+ if (params?.page) query['page'] = params.page;
1077
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1078
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1079
+ const result = await this.transport.getList('/api/v1/data/leave-balances', query);
1080
+ if ('error' in result) return result;
1081
+ return {
1082
+ data: result.data.map((r)=>transformLeaveBalance(r)),
1083
+ meta: result.meta
1084
+ };
1085
+ }
1086
+ async getById(id, options) {
1087
+ const query = {};
1088
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1089
+ const result = await this.transport.get(`/api/v1/data/leave-balances/${id}`, query);
1090
+ if ('error' in result) return result;
1091
+ return {
1092
+ data: transformLeaveBalance(result.data)
1093
+ };
1094
+ }
1095
+ /** Create a leave balance. Requires `leaveBalances.create` scope. */ async create(data) {
1096
+ const result = await this.transport.post('/api/v1/data/leave-balances', toSnakeBody(data));
1097
+ if ('error' in result) return result;
1098
+ return {
1099
+ data: transformLeaveBalance(result.data)
1100
+ };
1101
+ }
1102
+ /** Update a leave balance. Requires `leaveBalances.update` scope. */ async update(id, data) {
1103
+ const result = await this.transport.put(`/api/v1/data/leave-balances/${id}`, toSnakeBody(data));
1104
+ if ('error' in result) return result;
1105
+ return {
1106
+ data: transformLeaveBalance(result.data)
1107
+ };
1108
+ }
1109
+ /** Soft-delete a leave balance. Requires `leaveBalances.delete` scope. */ async delete(id) {
1110
+ const result = await this.transport.del(`/api/v1/data/leave-balances/${id}`);
1111
+ if ('error' in result) return result;
1112
+ return {
1113
+ data: null
1114
+ };
1115
+ }
1116
+ }
1117
+
1118
+ class PoliciesAccessor {
1119
+ constructor(transport){
1120
+ this.transport = transport;
1121
+ }
1122
+ async list(params) {
1123
+ const query = {};
1124
+ if (params?.search) query['search'] = params.search;
1125
+ if (params?.category) query['category'] = params.category;
1126
+ if (params?.page) query['page'] = params.page;
1127
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1128
+ const result = await this.transport.getList('/api/v1/data/policies', query);
1129
+ if ('error' in result) return result;
1130
+ return {
1131
+ data: result.data.map((r)=>transformPolicy(r)),
1132
+ meta: result.meta
1133
+ };
1134
+ }
1135
+ async getById(id) {
1136
+ const result = await this.transport.get(`/api/v1/data/policies/${id}`);
1137
+ if ('error' in result) return result;
1138
+ return {
1139
+ data: transformPolicy(result.data)
1140
+ };
1141
+ }
1142
+ /** Create a policy. Requires `policies.create` scope. */ async create(data) {
1143
+ const result = await this.transport.post('/api/v1/data/policies', toSnakeBody(data));
1144
+ if ('error' in result) return result;
1145
+ return {
1146
+ data: transformPolicy(result.data)
1147
+ };
1148
+ }
1149
+ /** Update a policy. Requires `policies.update` scope. */ async update(id, data) {
1150
+ const result = await this.transport.put(`/api/v1/data/policies/${id}`, toSnakeBody(data));
1151
+ if ('error' in result) return result;
1152
+ return {
1153
+ data: transformPolicy(result.data)
1154
+ };
1155
+ }
1156
+ /** Soft-delete a policy. Requires `policies.delete` scope. */ async delete(id) {
1157
+ const result = await this.transport.del(`/api/v1/data/policies/${id}`);
1158
+ if ('error' in result) return result;
1159
+ return {
1160
+ data: null
1161
+ };
1162
+ }
1163
+ }
1164
+
1165
+ class PolicyAcknowledgementsAccessor {
1166
+ constructor(transport){
1167
+ this.transport = transport;
1168
+ }
1169
+ async list(params) {
1170
+ const query = {};
1171
+ if (params?.policyId) query['policyId'] = params.policyId;
1172
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1173
+ if (params?.page) query['page'] = params.page;
1174
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1175
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1176
+ const result = await this.transport.getList('/api/v1/data/policy-acknowledgements', query);
1177
+ if ('error' in result) return result;
1178
+ return {
1179
+ data: result.data.map((r)=>transformPolicyAcknowledgement(r)),
1180
+ meta: result.meta
1181
+ };
1182
+ }
1183
+ async getById(id, options) {
1184
+ const query = {};
1185
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1186
+ const result = await this.transport.get(`/api/v1/data/policy-acknowledgements/${id}`, query);
1187
+ if ('error' in result) return result;
1188
+ return {
1189
+ data: transformPolicyAcknowledgement(result.data)
1190
+ };
1191
+ }
1192
+ /** Create a policy acknowledgement. Requires `policyAcknowledgements.create` scope. */ async create(data) {
1193
+ const result = await this.transport.post('/api/v1/data/policy-acknowledgements', toSnakeBody(data));
1194
+ if ('error' in result) return result;
1195
+ return {
1196
+ data: transformPolicyAcknowledgement(result.data)
1197
+ };
1198
+ }
1199
+ /** Update a policy acknowledgement. Requires `policyAcknowledgements.update` scope. */ async update(id, data) {
1200
+ const result = await this.transport.put(`/api/v1/data/policy-acknowledgements/${id}`, toSnakeBody(data));
1201
+ if ('error' in result) return result;
1202
+ return {
1203
+ data: transformPolicyAcknowledgement(result.data)
1204
+ };
1205
+ }
1206
+ /** Soft-delete a policy acknowledgement. Requires `policyAcknowledgements.delete` scope. */ async delete(id) {
1207
+ const result = await this.transport.del(`/api/v1/data/policy-acknowledgements/${id}`);
1208
+ if ('error' in result) return result;
1209
+ return {
1210
+ data: null
1211
+ };
1212
+ }
1213
+ }
1214
+
1215
+ class CalendarEventsAccessor {
1216
+ constructor(transport){
1217
+ this.transport = transport;
1218
+ }
1219
+ async list(params) {
1220
+ const query = {};
1221
+ if (params?.search) query['search'] = params.search;
1222
+ if (params?.type) query['type'] = params.type;
1223
+ if (params?.page) query['page'] = params.page;
1224
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1225
+ const result = await this.transport.getList('/api/v1/data/calendar-events', query);
1226
+ if ('error' in result) return result;
1227
+ return {
1228
+ data: result.data.map((r)=>transformCalendarEvent(r)),
1229
+ meta: result.meta
1230
+ };
1231
+ }
1232
+ async getById(id) {
1233
+ const result = await this.transport.get(`/api/v1/data/calendar-events/${id}`);
1234
+ if ('error' in result) return result;
1235
+ return {
1236
+ data: transformCalendarEvent(result.data)
1237
+ };
1238
+ }
1239
+ /** Create a calendar event. Requires `calendarEvents.create` scope. */ async create(data) {
1240
+ const result = await this.transport.post('/api/v1/data/calendar-events', toSnakeBody(data));
1241
+ if ('error' in result) return result;
1242
+ return {
1243
+ data: transformCalendarEvent(result.data)
1244
+ };
1245
+ }
1246
+ /** Update a calendar event. Requires `calendarEvents.update` scope. */ async update(id, data) {
1247
+ const result = await this.transport.put(`/api/v1/data/calendar-events/${id}`, toSnakeBody(data));
1248
+ if ('error' in result) return result;
1249
+ return {
1250
+ data: transformCalendarEvent(result.data)
1251
+ };
1252
+ }
1253
+ /** Soft-delete a calendar event. Requires `calendarEvents.delete` scope. */ async delete(id) {
1254
+ const result = await this.transport.del(`/api/v1/data/calendar-events/${id}`);
1255
+ if ('error' in result) return result;
1256
+ return {
1257
+ data: null
1258
+ };
1259
+ }
1260
+ }
1261
+
1262
+ class TimesheetsAccessor {
1263
+ constructor(transport){
1264
+ this.transport = transport;
1265
+ }
1266
+ async list(params) {
1267
+ const query = {};
1268
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1269
+ if (params?.projectId) query['projectId'] = params.projectId;
1270
+ if (params?.page) query['page'] = params.page;
1271
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1272
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1273
+ const result = await this.transport.getList('/api/v1/data/timesheets', query);
1274
+ if ('error' in result) return result;
1275
+ return {
1276
+ data: result.data.map((r)=>transformTimesheet(r)),
1277
+ meta: result.meta
1278
+ };
1279
+ }
1280
+ async getById(id, options) {
1281
+ const query = {};
1282
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1283
+ const result = await this.transport.get(`/api/v1/data/timesheets/${id}`, query);
1284
+ if ('error' in result) return result;
1285
+ return {
1286
+ data: transformTimesheet(result.data)
1287
+ };
1288
+ }
1289
+ /** Create a timesheet entry. Requires `timesheets.create` scope. */ async create(data) {
1290
+ const result = await this.transport.post('/api/v1/data/timesheets', toSnakeBody(data));
1291
+ if ('error' in result) return result;
1292
+ return {
1293
+ data: transformTimesheet(result.data)
1294
+ };
1295
+ }
1296
+ /** Update a timesheet entry. Requires `timesheets.update` scope. */ async update(id, data) {
1297
+ const result = await this.transport.put(`/api/v1/data/timesheets/${id}`, toSnakeBody(data));
1298
+ if ('error' in result) return result;
1299
+ return {
1300
+ data: transformTimesheet(result.data)
1301
+ };
1302
+ }
1303
+ /** Soft-delete a timesheet entry. Requires `timesheets.delete` scope. */ async delete(id) {
1304
+ const result = await this.transport.del(`/api/v1/data/timesheets/${id}`);
1305
+ if ('error' in result) return result;
1306
+ return {
1307
+ data: null
1308
+ };
1309
+ }
564
1310
  }
565
1311
 
566
1312
  /**
@@ -695,9 +1441,9 @@ class AuthAccessor {
695
1441
  * export const nucleus = new NucleusClient({
696
1442
  * token: process.env.NUCLEUS_TOKEN!,
697
1443
  * scopes: {
698
- * employees: ['identity', 'employment'],
699
- * projects: ['core'],
700
- * clients: ['identity'],
1444
+ * employees: { read: ['identity', 'employment'], update: ['contact'] },
1445
+ * projects: { read: ['core'] },
1446
+ * leaves: { read: ['core'], create: ['core'], delete: true },
701
1447
  * },
702
1448
  * });
703
1449
  * ```
@@ -716,6 +1462,14 @@ class AuthAccessor {
716
1462
  this.projectTypes = new ProjectTypesAccessor(transport);
717
1463
  this.currencies = new CurrenciesAccessor(transport);
718
1464
  this.genericRates = new GenericRatesAccessor(transport);
1465
+ this.jurisdictions = new JurisdictionsAccessor(transport);
1466
+ this.leaveTypes = new LeaveTypesAccessor(transport);
1467
+ this.leaves = new LeavesAccessor(transport);
1468
+ this.leaveBalances = new LeaveBalancesAccessor(transport);
1469
+ this.policies = new PoliciesAccessor(transport);
1470
+ this.policyAcknowledgements = new PolicyAcknowledgementsAccessor(transport);
1471
+ this.calendarEvents = new CalendarEventsAccessor(transport);
1472
+ this.timesheets = new TimesheetsAccessor(transport);
719
1473
  this.apps = new AppsAccessor(transport);
720
1474
  this.files = new FilesAccessor(transport);
721
1475
  this.auth = new AuthAccessor(config.baseUrl);