timber-node 0.4.4 → 0.4.6

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/README.md CHANGED
@@ -1,123 +1,127 @@
1
- # Timber SDK
2
-
3
- Official Node.js SDK for integrating with the Timber accounting backend API.
4
-
5
- Easily interact with Timber's core features like managing expenses, invoices, vendors, customers, payroll, and more using a unified SDK.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install timber-node
11
- ```
12
-
13
- ## Getting Started
14
-
15
- ```typescript
16
- import { createClient } from 'timber-node';
17
-
18
- const client = createClient('your-api-key', {
19
- baseURL: 'https://api.timber.me', // optional
20
- });
21
-
22
- // Example: List expenses
23
- const expenses = await client.expense.list({ page: 1, limit: 10 });
24
- console.log(expenses.data);
25
- ```
26
-
27
- ## Authentication
28
-
29
- Timber uses API Key-based authentication. Generate this API key from your Timber profile developer settings.
30
-
31
- ```typescript
32
- const client = createClient('your-api-key');
33
- ```
34
-
35
- You can also load your API key from environment variables using `dotenv`.
36
-
37
- ## SDK Structure
38
-
39
- The SDK client exposes the following services:
40
-
41
- ```typescript
42
- client.expense;
43
- client.expenseCategory;
44
- client.rawExpense;
45
- client.invoice;
46
- client.invoicePayment;
47
- client.vendorPayment;
48
- client.billPayment;
49
- client.customer;
50
- client.taxRate;
51
- client.salary;
52
- client.employee;
53
- client.bankStatement;
54
- client.cheque;
55
- ```
56
-
57
- Each service provides common operations like `create`, `get`, `list`, `update`, and `delete` where applicable.
58
-
59
- ## Usage Examples
60
-
61
- ### Create an Expense
62
-
63
- ```typescript
64
- const response = await client.expense.create({
65
- type: 'Travel',
66
- merchant: 'Uber',
67
- category: 'Transportation',
68
- date: '2025-06-23',
69
- payment_method: 'cash',
70
- amount: 45.75,
71
- });
72
- console.log(response.data);
73
- ```
74
-
75
- ### List Expenses
76
-
77
- ```typescript
78
- const response = await client.expense.list({ page: 1, limit: 5 });
79
- console.log(response.data);
80
- ```
81
-
82
- ### Update an Expense
83
-
84
- ```typescript
85
- const updates = { amount: 50.0 };
86
- const response = await client.expense.update('expense_id_here', updates);
87
- console.log(response.data);
88
- ```
89
-
90
- ### Delete an Expense
91
-
92
- ```typescript
93
- const response = await client.expense.delete('expense_id_here');
94
- console.log(response.data.message);
95
- ```
96
-
97
- ## TypeScript Support
98
-
99
- The SDK includes full TypeScript support:
100
-
101
- ```typescript
102
- import type { Expense, CreateExpenseRequest } from 'timber-node';
103
- ```
104
-
105
- ## Error Handling
106
-
107
- Errors are returned as Axios errors:
108
-
109
- ```typescript
110
- import axios from 'axios';
111
-
112
- try {
113
- await client.expense.get('invalid-id');
114
- } catch (err) {
115
- if (axios.isAxiosError(err)) {
116
- console.error(err.response?.status, err.response?.data);
117
- }
118
- }
119
- ```
120
-
121
- ## Related Links
122
-
123
- - [Timber Website](https://timber.me)
1
+ # Timber SDK
2
+
3
+ Official Node.js SDK for integrating with the Timber accounting backend API.
4
+
5
+ Easily interact with Timber's core features like managing expenses, invoices, vendors, customers, payroll, and more using a unified SDK.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install timber-node
11
+ ```
12
+
13
+ ## Getting Started
14
+
15
+ ```typescript
16
+ import { createClient } from 'timber-node';
17
+
18
+ const client = createClient('your-api-key', {
19
+ baseURL: 'https://api.timber.me', // optional
20
+ });
21
+
22
+ // Example: List expenses
23
+ const expenses = await client.expense.list({ page: 1, limit: 10 });
24
+ console.log(expenses.data);
25
+ ```
26
+
27
+ ## Authentication
28
+
29
+ Timber uses API Key-based authentication. Generate this API key from your Timber profile developer settings.
30
+
31
+ ```typescript
32
+ const client = createClient('your-api-key');
33
+ ```
34
+
35
+ You can also load your API key from environment variables using `dotenv`.
36
+
37
+ ## SDK Structure
38
+
39
+ The SDK client exposes the following services:
40
+
41
+ ```typescript
42
+ client.expense;
43
+ client.expenseCategory;
44
+ client.rawExpense;
45
+ client.invoice;
46
+ client.invoicePayment;
47
+ client.vendorPayment;
48
+ client.billPayment;
49
+ client.customer;
50
+ client.taxRate;
51
+ client.salary;
52
+ client.employee;
53
+ client.cheque;
54
+ client.bankStatement;
55
+ client.company;
56
+ client.invoiceNumber;
57
+ client.invoiceSettings;
58
+ client.invoiceItem;
59
+ ```
60
+
61
+ Each service provides common operations like `create`, `get`, `list`, `update`, and `delete` where applicable.
62
+
63
+ ## Usage Examples
64
+
65
+ ### Create an Expense
66
+
67
+ ```typescript
68
+ const response = await client.expense.create({
69
+ type: 'Travel',
70
+ merchant: 'Uber',
71
+ category: 'Transportation',
72
+ date: '2025-06-23',
73
+ payment_method: 'cash',
74
+ amount: 45.75,
75
+ });
76
+ console.log(response.data);
77
+ ```
78
+
79
+ ### List Expenses
80
+
81
+ ```typescript
82
+ const response = await client.expense.list({ page: 1, limit: 5 });
83
+ console.log(response.data);
84
+ ```
85
+
86
+ ### Update an Expense
87
+
88
+ ```typescript
89
+ const updates = { amount: 50.0 };
90
+ const response = await client.expense.update('expense_id_here', updates);
91
+ console.log(response.data);
92
+ ```
93
+
94
+ ### Delete an Expense
95
+
96
+ ```typescript
97
+ const response = await client.expense.delete('expense_id_here');
98
+ console.log(response.data.message);
99
+ ```
100
+
101
+ ## TypeScript Support
102
+
103
+ The SDK includes full TypeScript support:
104
+
105
+ ```typescript
106
+ import type { Expense, CreateExpenseRequest } from 'timber-node';
107
+ ```
108
+
109
+ ## Error Handling
110
+
111
+ Errors are returned as Axios errors:
112
+
113
+ ```typescript
114
+ import axios from 'axios';
115
+
116
+ try {
117
+ await client.expense.get('invalid-id');
118
+ } catch (err) {
119
+ if (axios.isAxiosError(err)) {
120
+ console.error(err.response?.status, err.response?.data);
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## Related Links
126
+
127
+ - [Timber Website](https://timber.me)
package/dist/auth.js CHANGED
@@ -63,7 +63,7 @@ class AuthService {
63
63
  * ```
64
64
  */
65
65
  async create(data) {
66
- return await this.http.post('/auth/register', data);
66
+ return await this.http.post('/user/sdk/auth/register', data);
67
67
  }
68
68
  }
69
69
  exports.AuthService = AuthService;
@@ -30,7 +30,9 @@ class BankStatementService {
30
30
  * ```
31
31
  */
32
32
  async list(params = {}) {
33
- return await this.http.get('/customer/reconcile/bank-statement', { params });
33
+ return await this.http.get('/reconcile/sdk/customer/bank-statement', {
34
+ params,
35
+ });
34
36
  }
35
37
  /**
36
38
  * Create a new bank statement.
@@ -55,7 +57,7 @@ class BankStatementService {
55
57
  else {
56
58
  throw new Error('File is required');
57
59
  }
58
- return await this.http.post('/customer/reconcile/bank-statement', formData, {
60
+ return await this.http.post('/reconcile/sdk/customer/bank-statement', formData, {
59
61
  headers,
60
62
  cancelToken: data.cancelToken,
61
63
  onUploadProgress: data.progressCallback,
@@ -30,7 +30,7 @@ class BillPaymentService {
30
30
  * ```
31
31
  */
32
32
  async list(params) {
33
- return await this.http.get('/customer/purchase/payment-record', {
33
+ return await this.http.get('/user/sdk/customer/purchase/payment-record', {
34
34
  params,
35
35
  });
36
36
  }
@@ -79,7 +79,7 @@ class BillPaymentService {
79
79
  if (data.file) {
80
80
  formData.append('file', data.file);
81
81
  }
82
- return await this.http.post('/customer/purchase/payment-record', formData, {
82
+ return await this.http.post('/user/sdk/customer/purchase/payment-record', formData, {
83
83
  headers,
84
84
  });
85
85
  }
@@ -118,7 +118,7 @@ class BillPaymentService {
118
118
  if (data.file) {
119
119
  formData.append('file', data.file);
120
120
  }
121
- return await this.http.put(`/customer/purchase/payment-record/${id}`, formData, {
121
+ return await this.http.put(`/user/sdk/customer/purchase/payment-record/${id}`, formData, {
122
122
  headers,
123
123
  });
124
124
  }
@@ -135,7 +135,7 @@ class BillPaymentService {
135
135
  * ```
136
136
  */
137
137
  async delete(id) {
138
- return await this.http.delete(`/customer/purchase/payment-record/${id}`);
138
+ return await this.http.delete(`/user/sdk/customer/purchase/payment-record/${id}`);
139
139
  }
140
140
  }
141
141
  exports.BillPaymentService = BillPaymentService;
package/dist/cheque.js CHANGED
@@ -30,7 +30,7 @@ class ChequeService {
30
30
  * ```
31
31
  */
32
32
  async list(params = {}) {
33
- return await this.http.get('/customer/reconcile/cheque', { params });
33
+ return await this.http.get('/reconcile/sdk/customer/cheque', { params });
34
34
  }
35
35
  /**
36
36
  * Create a new cheque.
@@ -55,7 +55,7 @@ class ChequeService {
55
55
  else {
56
56
  throw new Error('File is required');
57
57
  }
58
- return await this.http.post('/customer/reconcile/cheque', formData, {
58
+ return await this.http.post('/reconcile/sdk/customer/cheque', formData, {
59
59
  headers,
60
60
  cancelToken: data.cancelToken,
61
61
  onUploadProgress: data.progressCallback,
package/dist/company.d.ts CHANGED
@@ -4,13 +4,26 @@ export interface CompanyData {
4
4
  currency: string;
5
5
  language: string;
6
6
  address: string;
7
+ address_details: Map<string, any>;
7
8
  city: string;
8
9
  state: string;
9
10
  zip_code: string;
10
- country: string;
11
+ country: {
12
+ _id: string;
13
+ name: string;
14
+ country_code: string;
15
+ currency: string;
16
+ timezone: string;
17
+ logo: string;
18
+ is_active: boolean;
19
+ created_at: string;
20
+ updated_at: string;
21
+ };
11
22
  email: string;
12
23
  country_code: string;
13
24
  mobile: string;
25
+ is_zakat: boolean;
26
+ zakat_number: string;
14
27
  tax_number: string;
15
28
  financial_start_date: string;
16
29
  license_expiry: string;
@@ -25,6 +38,7 @@ export interface CompanyData {
25
38
  license_number: string;
26
39
  license_authority: string;
27
40
  trn: string;
41
+ crn: string;
28
42
  }
29
43
  export interface Company extends CompanyData {
30
44
  _id: string;
package/dist/company.js CHANGED
@@ -48,7 +48,7 @@ class CompanyService {
48
48
  * ```
49
49
  */
50
50
  async get() {
51
- return await this.http.get(`/customer/company`);
51
+ return await this.http.get(`/user/sdk/customer/company`);
52
52
  }
53
53
  /**
54
54
  * Create a new company.
@@ -118,7 +118,7 @@ class CompanyService {
118
118
  data.sector.forEach((item, index) => {
119
119
  formData.append(`sector[${index}]`, item);
120
120
  });
121
- return await this.http.post('/customer/company', formData, {
121
+ return await this.http.post('/user/sdk/customer/company', formData, {
122
122
  headers: formData.getHeaders(),
123
123
  });
124
124
  }
@@ -169,7 +169,7 @@ class CompanyService {
169
169
  formData.append(`sector[${index}]`, item);
170
170
  });
171
171
  }
172
- return await this.http.put(`/customer/company/${id}`, data, {
172
+ return await this.http.put(`/user/sdk/customer/company/${id}`, data, {
173
173
  headers: formData.getHeaders(),
174
174
  });
175
175
  }
@@ -185,7 +185,7 @@ class CompanyService {
185
185
  * ```
186
186
  * */
187
187
  async default(id) {
188
- return await this.http.patch(`/customer/company/${id}/default`);
188
+ return await this.http.patch(`/user/sdk/customer/company/${id}/default`);
189
189
  }
190
190
  }
191
191
  exports.CompanyService = CompanyService;
@@ -8,6 +8,7 @@ export interface CustomerData {
8
8
  city: string;
9
9
  role: 'customer' | 'vendor' | 'biller';
10
10
  address: string;
11
+ address_details?: Record<string, string>;
11
12
  trn?: string;
12
13
  [key: string]: any;
13
14
  }
package/dist/customer.js CHANGED
@@ -30,7 +30,7 @@ class CustomerService {
30
30
  * ```
31
31
  */
32
32
  async list(params = { role: 'customer' }) {
33
- return await this.http.get('/customer/customer', { params });
33
+ return await this.http.get('/user/sdk/customer/customer', { params });
34
34
  }
35
35
  /**
36
36
  * Fetch a single customer by ID.
@@ -46,17 +46,36 @@ class CustomerService {
46
46
  */
47
47
  async create(data) {
48
48
  const { formData, headers } = await (0, getFormData_1.getFormData)();
49
- Object.entries(data).forEach(([key, value]) => {
49
+ const appendFormData = (key, value) => {
50
+ if (value === undefined || value === null)
51
+ return;
50
52
  if (value instanceof File) {
51
53
  formData.append(key, value);
54
+ return;
52
55
  }
53
- else {
54
- formData.append(key, value);
56
+ if (Array.isArray(value)) {
57
+ value.forEach((item, index) => {
58
+ if (item instanceof File) {
59
+ formData.append(key, item);
60
+ }
61
+ else {
62
+ appendFormData(`${key}[${index}]`, item);
63
+ }
64
+ });
65
+ return;
55
66
  }
67
+ if (typeof value === 'object') {
68
+ Object.entries(value).forEach(([childKey, childValue]) => {
69
+ appendFormData(`${key}[${childKey}]`, childValue);
70
+ });
71
+ return;
72
+ }
73
+ formData.append(key, String(value));
74
+ };
75
+ Object.entries(data).forEach(([key, value]) => {
76
+ appendFormData(key, value);
56
77
  });
57
- return await this.http.post('/customer/customer', formData, {
58
- headers,
59
- });
78
+ return await this.http.post('/user/sdk/customer/customer', formData, { headers });
60
79
  }
61
80
  /**
62
81
  * Update an existing customer.
@@ -74,15 +93,36 @@ class CustomerService {
74
93
  */
75
94
  async update(id, data) {
76
95
  const { formData, headers } = await (0, getFormData_1.getFormData)();
77
- Object.entries(data).forEach(([key, value]) => {
96
+ const appendFormData = (key, value) => {
97
+ if (value === undefined || value === null)
98
+ return;
78
99
  if (value instanceof File) {
79
100
  formData.append(key, value);
101
+ return;
80
102
  }
81
- else {
82
- formData.append(key, value);
103
+ if (Array.isArray(value)) {
104
+ value.forEach((item, index) => {
105
+ if (item instanceof File) {
106
+ formData.append(key, item);
107
+ }
108
+ else {
109
+ appendFormData(`${key}[${index}]`, item);
110
+ }
111
+ });
112
+ return;
83
113
  }
114
+ if (typeof value === 'object') {
115
+ Object.entries(value).forEach(([childKey, childValue]) => {
116
+ appendFormData(`${key}[${childKey}]`, childValue);
117
+ });
118
+ return;
119
+ }
120
+ formData.append(key, String(value));
121
+ };
122
+ Object.entries(data).forEach(([key, value]) => {
123
+ appendFormData(key, value);
84
124
  });
85
- return await this.http.put(`/customer/customer/${id}`, formData, {
125
+ return await this.http.put(`/user/sdk/customer/customer/${id}`, formData, {
86
126
  headers,
87
127
  });
88
128
  }
@@ -99,7 +139,7 @@ class CustomerService {
99
139
  * ```
100
140
  */
101
141
  async delete(id) {
102
- return await this.http.delete(`/customer/customer/${id}`);
142
+ return await this.http.delete(`/user/sdk/customer/customer/${id}`);
103
143
  }
104
144
  }
105
145
  exports.CustomerService = CustomerService;
package/dist/employee.js CHANGED
@@ -18,7 +18,7 @@ class EmployeeService {
18
18
  * ```
19
19
  */
20
20
  async list(params) {
21
- return await this.http.get('/customer/employee', {
21
+ return await this.http.get('/user/sdk/customer/employee', {
22
22
  params,
23
23
  });
24
24
  }
package/dist/expense.js CHANGED
@@ -29,7 +29,7 @@ class ExpenseService {
29
29
  * ```
30
30
  */
31
31
  async list(params) {
32
- return await this.http.get('/customer/expense', { params });
32
+ return await this.http.get('/user/sdk/customer/expense', { params });
33
33
  }
34
34
  /**
35
35
  * Fetch a single expense by ID.
@@ -44,7 +44,7 @@ class ExpenseService {
44
44
  * ```
45
45
  */
46
46
  async get(id) {
47
- return await this.http.get(`/customer/expense/${id}`);
47
+ return await this.http.get(`/user/sdk/customer/expense/${id}`);
48
48
  }
49
49
  /**
50
50
  * Create a new expense.
@@ -67,7 +67,7 @@ class ExpenseService {
67
67
  * ```
68
68
  */
69
69
  async create(data) {
70
- return await this.http.post('/customer/expense', data);
70
+ return await this.http.post('/user/sdk/customer/expense', data);
71
71
  }
72
72
  /**
73
73
  * Update an existing expense.
@@ -84,7 +84,7 @@ class ExpenseService {
84
84
  * ```
85
85
  */
86
86
  async update(id, data) {
87
- return await this.http.put(`/customer/expense/${id}`, data);
87
+ return await this.http.put(`/user/sdk/customer/expense/${id}`, data);
88
88
  }
89
89
  /**
90
90
  * Delete an expense by ID.
@@ -99,7 +99,7 @@ class ExpenseService {
99
99
  * ```
100
100
  */
101
101
  async delete(id) {
102
- return await this.http.patch(`/customer/expense/${id}`);
102
+ return await this.http.patch(`/user/sdk/customer/expense/${id}`);
103
103
  }
104
104
  }
105
105
  exports.ExpenseService = ExpenseService;
@@ -29,7 +29,7 @@ class ExpenseCategoryService {
29
29
  * ```
30
30
  */
31
31
  async list(params) {
32
- return await this.http.get('/customer/expense/category', {
32
+ return await this.http.get('/user/sdk/customer/expense/category', {
33
33
  params,
34
34
  });
35
35
  }
@@ -49,7 +49,7 @@ class ExpenseCategoryService {
49
49
  * ```
50
50
  */
51
51
  async create(data) {
52
- return await this.http.post('/customer/expense/category', data);
52
+ return await this.http.post('/user/sdk/customer/expense/category', data);
53
53
  }
54
54
  /**
55
55
  * Update an existing expense category.
@@ -66,7 +66,7 @@ class ExpenseCategoryService {
66
66
  * ```
67
67
  */
68
68
  async update(id, data) {
69
- return await this.http.put(`/customer/expense/category/${id}`, data);
69
+ return await this.http.put(`/user/sdk/customer/expense/category/${id}`, data);
70
70
  }
71
71
  /**
72
72
  * Delete an expense category by ID.
@@ -81,7 +81,7 @@ class ExpenseCategoryService {
81
81
  * ```
82
82
  */
83
83
  async delete(id) {
84
- return await this.http.delete(`/customer/expense/category/${id}`);
84
+ return await this.http.delete(`/user/sdk/customer/expense/category/${id}`);
85
85
  }
86
86
  }
87
87
  exports.ExpenseCategoryService = ExpenseCategoryService;
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ import { ChequeService } from './cheque';
14
14
  import { BankStatementService } from './bankStatement';
15
15
  import { CompanyService } from './company';
16
16
  import { InvoiceNumberService } from './invoiceNumber';
17
- import { InvoiceTemplateService } from './invoiceTemplates';
17
+ import { InvoiceSettingsService } from './invoiceSettings';
18
18
  import { InvoiceItemService } from './invoiceItem';
19
19
  declare class TimberClient {
20
20
  auth: AuthService;
@@ -33,7 +33,7 @@ declare class TimberClient {
33
33
  bankStatement: BankStatementService;
34
34
  company: CompanyService;
35
35
  invoiceNumber: InvoiceNumberService;
36
- invoiceTemplate: InvoiceTemplateService;
36
+ invoiceSettings: InvoiceSettingsService;
37
37
  invoiceItem: InvoiceItemService;
38
38
  constructor(apiKey: string, options?: {
39
39
  baseURL?: string;
package/dist/index.js CHANGED
@@ -21,11 +21,11 @@ const cheque_1 = require("./cheque");
21
21
  const bankStatement_1 = require("./bankStatement");
22
22
  const company_1 = require("./company");
23
23
  const invoiceNumber_1 = require("./invoiceNumber");
24
- const invoiceTemplates_1 = require("./invoiceTemplates");
24
+ const invoiceSettings_1 = require("./invoiceSettings");
25
25
  const invoiceItem_1 = require("./invoiceItem");
26
26
  class TimberClient {
27
27
  constructor(apiKey, options = {}) {
28
- const baseURL = `${options.baseURL || 'https://api.timber.me'}/api/v1/user/sdk`;
28
+ const baseURL = `${options.baseURL || 'https://api.timber.me'}/api/v1`;
29
29
  // Create HTTP client for regular services (non-auth)
30
30
  const http = axios_1.default.create({
31
31
  baseURL: baseURL,
@@ -60,7 +60,7 @@ class TimberClient {
60
60
  this.bankStatement = new bankStatement_1.BankStatementService(http);
61
61
  this.company = new company_1.CompanyService(http);
62
62
  this.invoiceNumber = new invoiceNumber_1.InvoiceNumberService(http);
63
- this.invoiceTemplate = new invoiceTemplates_1.InvoiceTemplateService(http);
63
+ this.invoiceSettings = new invoiceSettings_1.InvoiceSettingsService(http);
64
64
  this.invoiceItem = new invoiceItem_1.InvoiceItemService(http);
65
65
  }
66
66
  }