tiime-sdk 2.1.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { $Fetch } from 'ofetch';
2
-
3
1
  interface AuthTokens {
4
2
  access_token: string;
5
3
  expires_at: number;
@@ -9,7 +7,7 @@ interface AuthConfig {
9
7
  password: string;
10
8
  }
11
9
  interface TiimeClientOptions {
12
- companyId?: number;
10
+ companyId: number;
13
11
  tokens?: AuthTokens;
14
12
  email?: string;
15
13
  password?: string;
@@ -438,28 +436,29 @@ interface MatchableDocument {
438
436
  }[];
439
437
  }
440
438
 
441
- /**
442
- * Resolve companyId from multiple sources (in priority order):
443
- * 1. Explicit option
444
- * 2. TIIME_COMPANY_ID env var
445
- * 3. ~/.config/tiime/config.json
446
- */
447
- declare const resolveCompanyId: (explicit?: number) => number;
439
+ interface TokenStorage {
440
+ load(): AuthTokens | null;
441
+ save(tokens: AuthTokens): void;
442
+ clear(): void;
443
+ }
444
+ interface CredentialStorage {
445
+ load(): {
446
+ email: string;
447
+ password: string;
448
+ } | null;
449
+ save(email: string, password: string): void;
450
+ }
448
451
  declare class TokenManager {
449
452
  private tokens;
450
453
  private credentials;
451
- private persist;
452
- /**
453
- * @param options.tokens - Use these tokens directly (no disk I/O)
454
- * @param options.email - Login with these credentials
455
- * @param options.password - Login with these credentials
456
- * @param options.persist - Save tokens/credentials to disk (default: true when no explicit auth)
457
- */
454
+ private tokenStorage;
455
+ private credentialStorage;
458
456
  constructor(options?: {
459
457
  tokens?: AuthTokens;
460
458
  email?: string;
461
459
  password?: string;
462
- persist?: boolean;
460
+ tokenStorage?: TokenStorage;
461
+ credentialStorage?: CredentialStorage;
463
462
  });
464
463
  login(email: string, password: string): Promise<AuthTokens>;
465
464
  getValidToken(): Promise<string>;
@@ -470,14 +469,24 @@ declare class TokenManager {
470
469
  expiresAt: Date | null;
471
470
  };
472
471
  private isExpired;
473
- private loadFromDisk;
474
- private saveToDisk;
475
472
  }
476
473
 
477
- declare class BankAccountsResource {
478
- private fetch;
479
- private companyId;
480
- constructor(fetch: $Fetch, companyId: number);
474
+ interface FetchOptions {
475
+ method?: string;
476
+ headers?: Record<string, string>;
477
+ body?: unknown;
478
+ query?: Record<string, unknown> | object;
479
+ }
480
+ type FetchFn = <T = unknown>(url: string, options?: FetchOptions) => Promise<T>;
481
+
482
+ declare class Resource {
483
+ protected fetch: FetchFn;
484
+ protected companyId: number;
485
+ constructor(fetch: FetchFn, companyId: number);
486
+ protected url(path: string): string;
487
+ }
488
+
489
+ declare class BankAccountsResource extends Resource {
481
490
  list(enabled?: boolean): Promise<BankAccount[]>;
482
491
  get(bankAccountId: number): Promise<BankAccount>;
483
492
  balance(): Promise<{
@@ -499,10 +508,7 @@ interface BankTransactionsListParams {
499
508
  to?: string;
500
509
  search?: string;
501
510
  }
502
- declare class BankTransactionsResource {
503
- private fetch;
504
- private companyId;
505
- constructor(fetch: $Fetch, companyId: number);
511
+ declare class BankTransactionsResource extends Resource {
506
512
  list(params?: BankTransactionsListParams): Promise<BankTransactionsResponse>;
507
513
  listAll(params?: Omit<BankTransactionsListParams, "page">): Promise<BankTransaction[]>;
508
514
  unimputed(): Promise<BankTransaction[]>;
@@ -529,20 +535,14 @@ interface ClientCreateParams {
529
535
  siren_or_siret?: string;
530
536
  professional?: boolean;
531
537
  }
532
- declare class ClientsResource {
533
- private fetch;
534
- private companyId;
535
- constructor(fetch: $Fetch, companyId: number);
538
+ declare class ClientsResource extends Resource {
536
539
  list(params?: ClientsListParams): Promise<Client[]>;
537
540
  get(clientId: number): Promise<Client>;
538
541
  create(params: ClientCreateParams): Promise<Client>;
539
542
  search(query: string): Promise<Client[]>;
540
543
  }
541
544
 
542
- declare class CompanyResource {
543
- private fetch;
544
- private companyId;
545
- constructor(fetch: $Fetch, companyId: number);
545
+ declare class CompanyResource extends Resource {
546
546
  get(): Promise<Company>;
547
547
  users(): Promise<unknown>;
548
548
  appConfig(): Promise<unknown>;
@@ -559,10 +559,7 @@ interface DocumentsListParams {
559
559
  page?: number;
560
560
  pageSize?: number;
561
561
  }
562
- declare class DocumentsResource {
563
- private fetch;
564
- private companyId;
565
- constructor(fetch: $Fetch, companyId: number);
562
+ declare class DocumentsResource extends Resource {
566
563
  list(params?: DocumentsListParams): Promise<Document[]>;
567
564
  categories(): Promise<DocumentCategory[]>;
568
565
  preview(documentId: number): Promise<unknown>;
@@ -571,10 +568,7 @@ declare class DocumentsResource {
571
568
  download(documentId: number): Promise<ArrayBuffer>;
572
569
  }
573
570
 
574
- declare class ExpenseReportsResource {
575
- private fetch;
576
- private companyId;
577
- constructor(fetch: $Fetch, companyId: number);
571
+ declare class ExpenseReportsResource extends Resource {
578
572
  list(sorts?: string): Promise<ExpenseReport[]>;
579
573
  get(expenseReportId: number): Promise<ExpenseReport>;
580
574
  create(params: ExpenseReportCreateParams): Promise<ExpenseReport>;
@@ -586,10 +580,7 @@ interface InvoicesListParams {
586
580
  page?: number;
587
581
  pageSize?: number;
588
582
  }
589
- declare class InvoicesResource {
590
- private fetch;
591
- private companyId;
592
- constructor(fetch: $Fetch, companyId: number);
583
+ declare class InvoicesResource extends Resource {
593
584
  list(params?: InvoicesListParams): Promise<Invoice[]>;
594
585
  listAll(params?: {
595
586
  sorts?: string;
@@ -608,19 +599,13 @@ declare class InvoicesResource {
608
599
  }): Promise<Invoice>;
609
600
  }
610
601
 
611
- declare class LabelsResource {
612
- private fetch;
613
- private companyId;
614
- constructor(fetch: $Fetch, companyId: number);
602
+ declare class LabelsResource extends Resource {
615
603
  list(): Promise<Label[]>;
616
604
  standard(): Promise<Label[]>;
617
605
  tags(): Promise<Tag[]>;
618
606
  }
619
607
 
620
- declare class QuotationsResource {
621
- private fetch;
622
- private companyId;
623
- constructor(fetch: $Fetch, companyId: number);
608
+ declare class QuotationsResource extends Resource {
624
609
  list(expand?: string): Promise<Quotation[]>;
625
610
  get(quotationId: number): Promise<Quotation>;
626
611
  create(params: QuotationCreateParams): Promise<Quotation>;
@@ -629,18 +614,18 @@ declare class QuotationsResource {
629
614
  }
630
615
 
631
616
  declare class UsersResource {
632
- private fetch;
633
- constructor(fetch: $Fetch);
617
+ protected fetch: FetchFn;
618
+ constructor(fetch: FetchFn);
634
619
  me(): Promise<User>;
635
620
  legalInformations(): Promise<unknown>;
636
621
  settings(companyId: number): Promise<unknown>;
637
622
  }
638
623
 
639
624
  declare class TiimeClient {
640
- readonly fetch: $Fetch;
625
+ readonly fetch: FetchFn;
641
626
  readonly tokenManager: TokenManager;
642
627
  readonly companyId: number;
643
- constructor(options?: TiimeClientOptions & {
628
+ constructor(options: TiimeClientOptions & {
644
629
  tokenManager?: TokenManager;
645
630
  });
646
631
  listCompanies(): Promise<Company[]>;
@@ -670,4 +655,4 @@ declare class TiimeError extends Error {
670
655
  };
671
656
  }
672
657
 
673
- export { type AccountingPeriod, type Address, type ApeCode, type AuthConfig, type AuthTokens, type Bank, type BankAccount, type BankTransaction, type BankTransactionsResponse, type Client, type Company, type Country, type DashboardBlock, type Document, type DocumentCategory, type DocumentMatching, type ExpenseReport, type ExpenseReportCreateParams, type Imputation, type ImputationLabel, type ImputationParams, type Invoice, type InvoiceCreateParams, type InvoiceLine, type InvoiceSendParams, type Label, type LabelSuggestion, type MatchableDocument, type PaginatedResponse, type Quotation, type QuotationCreateParams, type QuotationSendParams, type Tag, TiimeClient, type TiimeClientOptions, TiimeError, TokenManager, type User, type VatSystem, resolveCompanyId };
658
+ export { type AccountingPeriod, type Address, type ApeCode, type AuthConfig, type AuthTokens, type Bank, type BankAccount, type BankTransaction, type BankTransactionsResponse, type Client, type Company, type Country, type CredentialStorage, type DashboardBlock, type Document, type DocumentCategory, type DocumentMatching, type ExpenseReport, type ExpenseReportCreateParams, type Imputation, type ImputationLabel, type ImputationParams, type Invoice, type InvoiceCreateParams, type InvoiceLine, type InvoiceSendParams, type Label, type LabelSuggestion, type MatchableDocument, type PaginatedResponse, type Quotation, type QuotationCreateParams, type QuotationSendParams, type Tag, TiimeClient, type TiimeClientOptions, TiimeError, TokenManager, type TokenStorage, type User, type VatSystem };
package/dist/index.js CHANGED
@@ -1,820 +1,2 @@
1
- // src/auth.ts
2
- import { execSync } from "child_process";
3
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
4
- import { homedir } from "os";
5
- import { join } from "path";
6
- import { ofetch } from "ofetch";
7
- var AUTH0_DOMAIN = "auth0.tiime.fr";
8
- var AUTH0_CLIENT_ID = "iEbsbe3o66gcTBfGRa012kj1Rb6vjAND";
9
- var AUTH0_AUDIENCE = "https://chronos/";
10
- var CONFIG_DIR = join(homedir(), ".config", "tiime");
11
- var AUTH_FILE = join(CONFIG_DIR, "auth.json");
12
- var CONFIG_FILE = join(CONFIG_DIR, "config.json");
13
- var KEYCHAIN_ACCOUNT = "tiime-cli";
14
- var KEYCHAIN_SERVICE = "tiime-credentials";
15
- var saveCredentialsToKeychain = (email, password) => {
16
- try {
17
- const payload = JSON.stringify({ email, password });
18
- execSync(
19
- `security add-generic-password -a "${KEYCHAIN_ACCOUNT}" -s "${KEYCHAIN_SERVICE}" -w '${payload.replace(/'/g, "'\\''")}' -U`,
20
- { stdio: "ignore" }
21
- );
22
- return true;
23
- } catch {
24
- return false;
25
- }
26
- };
27
- var loadCredentialsFromKeychain = () => {
28
- try {
29
- const raw = execSync(
30
- `security find-generic-password -a "${KEYCHAIN_ACCOUNT}" -s "${KEYCHAIN_SERVICE}" -w`,
31
- { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
32
- ).trim();
33
- const data = JSON.parse(raw);
34
- if (typeof data === "object" && data !== null && "email" in data && "password" in data && typeof data.email === "string" && typeof data.password === "string") {
35
- return data;
36
- }
37
- return null;
38
- } catch {
39
- return null;
40
- }
41
- };
42
- var saveCredentialsToFile = (email, password) => {
43
- if (!existsSync(CONFIG_DIR)) {
44
- mkdirSync(CONFIG_DIR, { recursive: true });
45
- }
46
- const filePath = join(CONFIG_DIR, "credentials.json");
47
- writeFileSync(filePath, JSON.stringify({ email, password }, null, 2), {
48
- mode: 384
49
- });
50
- };
51
- var loadCredentialsFromFile = () => {
52
- try {
53
- const filePath = join(CONFIG_DIR, "credentials.json");
54
- if (existsSync(filePath)) {
55
- const data = JSON.parse(readFileSync(filePath, "utf-8"));
56
- if (typeof data === "object" && data !== null && "email" in data && "password" in data && typeof data.email === "string" && typeof data.password === "string") {
57
- return data;
58
- }
59
- }
60
- } catch {
61
- }
62
- return null;
63
- };
64
- var saveCredentials = (email, password) => {
65
- if (!saveCredentialsToKeychain(email, password)) {
66
- saveCredentialsToFile(email, password);
67
- }
68
- };
69
- var loadCredentials = () => {
70
- return loadCredentialsFromKeychain() ?? loadCredentialsFromFile();
71
- };
72
- var resolveCompanyId = (explicit) => {
73
- if (explicit) return explicit;
74
- const envId = process.env.TIIME_COMPANY_ID;
75
- if (envId) {
76
- const parsed = Number.parseInt(envId, 10);
77
- if (!Number.isNaN(parsed)) return parsed;
78
- }
79
- try {
80
- if (existsSync(CONFIG_FILE)) {
81
- const config = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
82
- if (config.companyId) return config.companyId;
83
- }
84
- } catch {
85
- }
86
- throw new Error(
87
- "No company ID configured. Set TIIME_COMPANY_ID env var, pass companyId option, or run `tiime company use --id <ID>`."
88
- );
89
- };
90
- var TokenManager = class {
91
- tokens = null;
92
- credentials = null;
93
- persist;
94
- /**
95
- * @param options.tokens - Use these tokens directly (no disk I/O)
96
- * @param options.email - Login with these credentials
97
- * @param options.password - Login with these credentials
98
- * @param options.persist - Save tokens/credentials to disk (default: true when no explicit auth)
99
- */
100
- constructor(options = {}) {
101
- const hasExplicitAuth = options.tokens || options.email && options.password;
102
- this.persist = options.persist ?? !hasExplicitAuth;
103
- if (options.tokens) {
104
- this.tokens = options.tokens;
105
- return;
106
- }
107
- if (options.email && options.password) {
108
- this.credentials = { email: options.email, password: options.password };
109
- return;
110
- }
111
- const envToken = process.env.TIIME_ACCESS_TOKEN;
112
- if (envToken) {
113
- this.tokens = {
114
- access_token: envToken,
115
- // No expiry info from env — assume valid, never auto-refresh
116
- expires_at: Number.MAX_SAFE_INTEGER
117
- };
118
- return;
119
- }
120
- const envEmail = process.env.TIIME_EMAIL;
121
- const envPassword = process.env.TIIME_PASSWORD;
122
- if (envEmail && envPassword) {
123
- this.credentials = { email: envEmail, password: envPassword };
124
- return;
125
- }
126
- this.loadFromDisk();
127
- }
128
- async login(email, password) {
129
- const response = await ofetch(`https://${AUTH0_DOMAIN}/oauth/token`, {
130
- method: "POST",
131
- body: {
132
- grant_type: "password",
133
- client_id: AUTH0_CLIENT_ID,
134
- audience: AUTH0_AUDIENCE,
135
- scope: "openid email",
136
- username: email,
137
- password
138
- }
139
- });
140
- this.tokens = {
141
- access_token: response.access_token,
142
- expires_at: Date.now() + response.expires_in * 1e3
143
- };
144
- if (this.persist) {
145
- this.saveToDisk();
146
- saveCredentials(email, password);
147
- }
148
- return this.tokens;
149
- }
150
- async getValidToken() {
151
- if (!this.tokens || this.isExpired()) {
152
- const creds = this.credentials ?? loadCredentials();
153
- if (creds) {
154
- const tokens = await this.login(creds.email, creds.password);
155
- return tokens.access_token;
156
- }
157
- throw new Error(
158
- this.tokens ? "Token expired. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`." : "Not authenticated. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`."
159
- );
160
- }
161
- return this.tokens.access_token;
162
- }
163
- isAuthenticated() {
164
- return this.tokens !== null && !this.isExpired();
165
- }
166
- logout() {
167
- this.tokens = null;
168
- if (existsSync(AUTH_FILE)) {
169
- writeFileSync(AUTH_FILE, "{}");
170
- }
171
- }
172
- getTokenInfo() {
173
- if (!this.tokens) {
174
- return { email: null, expiresAt: null };
175
- }
176
- try {
177
- const payload = JSON.parse(
178
- Buffer.from(
179
- this.tokens.access_token.split(".")[1],
180
- "base64"
181
- ).toString()
182
- );
183
- return {
184
- email: payload["tiime/userEmail"] || null,
185
- expiresAt: new Date(this.tokens.expires_at)
186
- };
187
- } catch {
188
- return { email: null, expiresAt: new Date(this.tokens.expires_at) };
189
- }
190
- }
191
- isExpired() {
192
- if (!this.tokens) return true;
193
- return Date.now() >= this.tokens.expires_at - 6e4;
194
- }
195
- loadFromDisk() {
196
- try {
197
- if (existsSync(AUTH_FILE)) {
198
- const data = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
199
- if (data.access_token && data.expires_at) {
200
- this.tokens = data;
201
- }
202
- }
203
- } catch {
204
- }
205
- }
206
- saveToDisk() {
207
- if (!existsSync(CONFIG_DIR)) {
208
- mkdirSync(CONFIG_DIR, { recursive: true });
209
- }
210
- writeFileSync(AUTH_FILE, JSON.stringify(this.tokens, null, 2));
211
- }
212
- };
213
-
214
- // src/client.ts
215
- import { ofetch as ofetch2 } from "ofetch";
216
-
217
- // src/errors.ts
218
- var TiimeError = class extends Error {
219
- constructor(message, status, endpoint, details) {
220
- super(message);
221
- this.status = status;
222
- this.endpoint = endpoint;
223
- this.details = details;
224
- this.name = "TiimeError";
225
- }
226
- toJSON() {
227
- return {
228
- error: this.name,
229
- message: this.message,
230
- status: this.status,
231
- endpoint: this.endpoint,
232
- details: this.details
233
- };
234
- }
235
- };
236
-
237
- // src/resources/bank-accounts.ts
238
- var BankAccountsResource = class {
239
- constructor(fetch, companyId) {
240
- this.fetch = fetch;
241
- this.companyId = companyId;
242
- }
243
- list(enabled) {
244
- return this.fetch(
245
- `/companies/${this.companyId}/bank_accounts`,
246
- { query: enabled !== void 0 ? { enabled } : void 0 }
247
- );
248
- }
249
- get(bankAccountId) {
250
- return this.fetch(
251
- `/companies/${this.companyId}/bank_accounts/${bankAccountId}`
252
- );
253
- }
254
- async balance() {
255
- const accounts = await this.list(true);
256
- return accounts.map((a) => ({
257
- name: a.name,
258
- balance_amount: a.balance_amount,
259
- currency: a.balance_currency
260
- }));
261
- }
262
- };
263
-
264
- // src/resources/bank-transactions.ts
265
- var BankTransactionsResource = class {
266
- constructor(fetch, companyId) {
267
- this.fetch = fetch;
268
- this.companyId = companyId;
269
- }
270
- list(params) {
271
- const start = ((params?.page ?? 1) - 1) * (params?.pageSize ?? 100);
272
- const end = start + (params?.pageSize ?? 100);
273
- const { page: _, pageSize: __, from, to, search, ...rest } = params ?? {};
274
- const query = { ...rest };
275
- if (from) query.transaction_date_start = from;
276
- if (to) query.transaction_date_end = to;
277
- if (search) query.wording = search;
278
- return this.fetch(
279
- `/companies/${this.companyId}/bank_transactions`,
280
- {
281
- query: { hide_refused: false, ...query },
282
- headers: {
283
- Accept: "application/vnd.tiime.bank_transactions.v2+json",
284
- Range: `items=${start}-${end}`
285
- }
286
- }
287
- );
288
- }
289
- async listAll(params) {
290
- const pageSize = params?.pageSize ?? 200;
291
- const all = [];
292
- let page = 1;
293
- let hasMore = true;
294
- while (hasMore) {
295
- const response = await this.list({ ...params, page, pageSize });
296
- all.push(...response.transactions);
297
- hasMore = response.transactions.length === pageSize;
298
- page++;
299
- }
300
- return all;
301
- }
302
- unimputed() {
303
- return this.fetch(
304
- `/companies/${this.companyId}/bank_transactions/unimputed`
305
- );
306
- }
307
- get(transactionId) {
308
- return this.fetch(
309
- `/companies/${this.companyId}/bank_transactions/${transactionId}`
310
- );
311
- }
312
- labelSuggestions(transactionId) {
313
- return this.fetch(
314
- `/companies/${this.companyId}/bank_transactions/${transactionId}/label_suggestions`,
315
- {
316
- headers: {
317
- Accept: "application/vnd.tiime.bank_transactions.label_suggestions.v2+json"
318
- }
319
- }
320
- );
321
- }
322
- impute(transactionId, imputations) {
323
- return this.fetch(
324
- `/companies/${this.companyId}/bank_transactions/${transactionId}`,
325
- {
326
- method: "PATCH",
327
- body: { imputations }
328
- }
329
- );
330
- }
331
- matchDocuments(transactionId, documentIds) {
332
- return this.fetch(
333
- `/companies/${this.companyId}/bank_transactions/${transactionId}/document_matchings`,
334
- {
335
- method: "PUT",
336
- body: { documents: documentIds.map((id) => ({ id })) }
337
- }
338
- );
339
- }
340
- getMatchings(transactionId) {
341
- return this.fetch(
342
- `/companies/${this.companyId}/bank_transactions/${transactionId}/matchings`
343
- );
344
- }
345
- };
346
-
347
- // src/resources/clients.ts
348
- var ClientsResource = class {
349
- constructor(fetch, companyId) {
350
- this.fetch = fetch;
351
- this.companyId = companyId;
352
- }
353
- list(params) {
354
- return this.fetch(`/companies/${this.companyId}/clients`, {
355
- query: params,
356
- headers: {
357
- Accept: "application/vnd.tiime.timeline.v2+json",
358
- Range: "items=0-*"
359
- }
360
- });
361
- }
362
- get(clientId) {
363
- return this.fetch(
364
- `/companies/${this.companyId}/clients/${clientId}`
365
- );
366
- }
367
- create(params) {
368
- return this.fetch(`/companies/${this.companyId}/clients`, {
369
- method: "POST",
370
- body: params
371
- });
372
- }
373
- search(query) {
374
- return this.fetch(`/companies/${this.companyId}/clients`, {
375
- query: { search: query },
376
- headers: {
377
- Accept: "application/vnd.tiime.timeline.v2+json",
378
- Range: "items=0-*"
379
- }
380
- });
381
- }
382
- };
383
-
384
- // src/resources/company.ts
385
- var CompanyResource = class {
386
- constructor(fetch, companyId) {
387
- this.fetch = fetch;
388
- this.companyId = companyId;
389
- }
390
- get() {
391
- return this.fetch(`/companies/${this.companyId}`);
392
- }
393
- users() {
394
- return this.fetch(`/companies/${this.companyId}/users`);
395
- }
396
- appConfig() {
397
- return this.fetch(`/companies/${this.companyId}/app_config`);
398
- }
399
- accountingPeriod(rangeYear = 1) {
400
- return this.fetch(
401
- `/companies/${this.companyId}/accounting_period/current`,
402
- { query: { range_year: rangeYear } }
403
- );
404
- }
405
- tiles(keys) {
406
- return this.fetch(`/companies/${this.companyId}/tiles`, {
407
- query: { keys: keys.join(",") }
408
- });
409
- }
410
- dashboardBlocks(displayGroup = "monitoring") {
411
- return this.fetch(`/companies/${this.companyId}/dashboard_blocks`, {
412
- query: { sorts: "rank:asc", display_group: displayGroup }
413
- });
414
- }
415
- };
416
-
417
- // src/resources/documents.ts
418
- var DocumentsResource = class {
419
- constructor(fetch, companyId) {
420
- this.fetch = fetch;
421
- this.companyId = companyId;
422
- }
423
- list(params) {
424
- const start = ((params?.page ?? 1) - 1) * (params?.pageSize ?? 25);
425
- const end = start + (params?.pageSize ?? 25);
426
- const { page: _, pageSize: __, ...query } = params ?? {};
427
- return this.fetch(`/companies/${this.companyId}/documents`, {
428
- query: {
429
- sorts: "created_at:desc",
430
- expand: "file_family,preview_available",
431
- ...query
432
- },
433
- headers: {
434
- Accept: "application/vnd.tiime.documents.v2+json,application/vnd.tiime.docs.query+json,application/vnd.tiime.docs.imputation+json",
435
- Range: `items=${start}-${end}`
436
- }
437
- });
438
- }
439
- categories() {
440
- return this.fetch(
441
- `/companies/${this.companyId}/document_categories`,
442
- {
443
- headers: {
444
- Accept: "application/vnd.tiime.documents.v3+json"
445
- }
446
- }
447
- );
448
- }
449
- preview(documentId) {
450
- return this.fetch(
451
- `/companies/${this.companyId}/documents/${documentId}/preview`
452
- );
453
- }
454
- upload(file, filename, type) {
455
- const formData = new FormData();
456
- formData.append("file", new Blob([file]), filename);
457
- if (type) {
458
- formData.append("type", type);
459
- }
460
- return this.fetch(`/companies/${this.companyId}/documents`, {
461
- method: "POST",
462
- body: formData
463
- });
464
- }
465
- searchMatchable(query) {
466
- return this.fetch(
467
- `/companies/${this.companyId}/documents`,
468
- {
469
- query: { matchable: true, q: query },
470
- headers: {
471
- Accept: "application/vnd.tiime.documents.v3+json,application/vnd.tiime.docs.imputation+json",
472
- Range: "items=0-25"
473
- }
474
- }
475
- );
476
- }
477
- async download(documentId) {
478
- return this.fetch(
479
- `/companies/${this.companyId}/documents/${documentId}/download`,
480
- {
481
- headers: { Accept: "application/octet-stream" }
482
- }
483
- );
484
- }
485
- };
486
-
487
- // src/resources/expense-reports.ts
488
- var ExpenseReportsResource = class {
489
- constructor(fetch, companyId) {
490
- this.fetch = fetch;
491
- this.companyId = companyId;
492
- }
493
- list(sorts = "metadata.date:desc") {
494
- return this.fetch(
495
- `/companies/${this.companyId}/expense_reports`,
496
- {
497
- query: { expand: "total_amount", sorts },
498
- headers: { Range: "items=0-25" }
499
- }
500
- );
501
- }
502
- get(expenseReportId) {
503
- return this.fetch(
504
- `/companies/${this.companyId}/expense_reports/${expenseReportId}`
505
- );
506
- }
507
- create(params) {
508
- return this.fetch(
509
- `/companies/${this.companyId}/expense_reports`,
510
- {
511
- method: "POST",
512
- body: params
513
- }
514
- );
515
- }
516
- };
517
-
518
- // src/resources/invoices.ts
519
- var DEFAULT_INVOICE_TEMPLATE = {
520
- template: "advanced",
521
- status: "draft",
522
- due_date_mode: "thirty_days",
523
- title_enabled: true,
524
- free_field_enabled: false,
525
- free_field: "",
526
- discount_enabled: false,
527
- bank_detail_enabled: true,
528
- payment_condition_enabled: true,
529
- payment_condition: "En cas de retard de paiement, une p\xE9nalit\xE9 de 3 fois le taux d'int\xE9r\xEAt l\xE9gal sera appliqu\xE9e, \xE0 laquelle s'ajoutera une indemnit\xE9 forfaitaire pour frais de recouvrement de 40\u20AC.",
530
- text_lines: []
531
- };
532
- var InvoicesResource = class {
533
- constructor(fetch, companyId) {
534
- this.fetch = fetch;
535
- this.companyId = companyId;
536
- }
537
- list(params) {
538
- const start = ((params?.page ?? 1) - 1) * (params?.pageSize ?? 25);
539
- const end = start + (params?.pageSize ?? 25);
540
- const query = {
541
- sorts: params?.sorts ?? "invoice_number:desc"
542
- };
543
- if (params?.status) query.status = params.status;
544
- return this.fetch(`/companies/${this.companyId}/invoices`, {
545
- query,
546
- headers: { Range: `items=${start}-${end}` }
547
- });
548
- }
549
- async listAll(params) {
550
- const pageSize = params?.pageSize ?? 100;
551
- const all = [];
552
- let page = 1;
553
- let hasMore = true;
554
- while (hasMore) {
555
- const batch = await this.list({
556
- sorts: params?.sorts,
557
- status: params?.status,
558
- page,
559
- pageSize
560
- });
561
- all.push(...batch);
562
- hasMore = batch.length === pageSize;
563
- page++;
564
- }
565
- return all;
566
- }
567
- get(invoiceId) {
568
- return this.fetch(
569
- `/companies/${this.companyId}/invoices/${invoiceId}`
570
- );
571
- }
572
- create(params) {
573
- const body = {
574
- ...DEFAULT_INVOICE_TEMPLATE,
575
- ...params,
576
- lines: params.lines?.map((line) => ({ ...line }))
577
- };
578
- for (const line of body.lines ?? []) {
579
- line.line_amount = line.quantity * line.unit_amount;
580
- line.sequence ??= 1;
581
- line.invoicing_category_type ??= "benefit";
582
- line.discount_description ??= "";
583
- line.discount_amount ??= null;
584
- line.discount_percentage ??= null;
585
- }
586
- return this.fetch(`/companies/${this.companyId}/invoices`, {
587
- method: "POST",
588
- body
589
- });
590
- }
591
- update(invoiceId, params) {
592
- return this.fetch(
593
- `/companies/${this.companyId}/invoices/${invoiceId}`,
594
- {
595
- method: "PUT",
596
- body: params
597
- }
598
- );
599
- }
600
- send(invoiceId, params) {
601
- return this.fetch(
602
- `/companies/${this.companyId}/invoices/${invoiceId}/send`,
603
- {
604
- method: "POST",
605
- body: params
606
- }
607
- );
608
- }
609
- async downloadPdf(invoiceId) {
610
- return this.fetch(
611
- `/companies/${this.companyId}/invoices/${invoiceId}/pdf`,
612
- {
613
- headers: { Accept: "application/pdf" }
614
- }
615
- );
616
- }
617
- delete(invoiceId) {
618
- return this.fetch(
619
- `/companies/${this.companyId}/invoices/${invoiceId}`,
620
- { method: "DELETE" }
621
- );
622
- }
623
- async duplicate(invoiceId, overrides) {
624
- const source = await this.get(invoiceId);
625
- const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
626
- const lines = source.lines.map((l) => ({
627
- description: l.description,
628
- quantity: overrides?.quantity ?? l.quantity,
629
- unit_amount: l.unit_amount,
630
- vat_type: l.vat_type,
631
- invoicing_unit: l.invoicing_unit,
632
- invoicing_category_type: l.invoicing_category_type,
633
- article: l.article
634
- }));
635
- return this.create({
636
- client: source.client_id ? { id: source.client_id } : null,
637
- emission_date: overrides?.emission_date ?? today,
638
- title: source.title,
639
- title_enabled: !!source.title,
640
- lines,
641
- status: "draft"
642
- });
643
- }
644
- };
645
-
646
- // src/resources/labels.ts
647
- var LabelsResource = class {
648
- constructor(fetch, companyId) {
649
- this.fetch = fetch;
650
- this.companyId = companyId;
651
- }
652
- list() {
653
- return this.fetch(`/companies/${this.companyId}/labels`, {
654
- headers: {
655
- Accept: "application/vnd.tiime.labels.v2+json"
656
- }
657
- });
658
- }
659
- standard() {
660
- return this.fetch(`/companies/${this.companyId}/standard_labels`);
661
- }
662
- tags() {
663
- return this.fetch(`/companies/${this.companyId}/tags`, {
664
- query: { expand: "tag_detail" }
665
- });
666
- }
667
- };
668
-
669
- // src/resources/quotations.ts
670
- var QuotationsResource = class {
671
- constructor(fetch, companyId) {
672
- this.fetch = fetch;
673
- this.companyId = companyId;
674
- }
675
- list(expand = "invoices") {
676
- return this.fetch(`/companies/${this.companyId}/quotations`, {
677
- query: { expand },
678
- headers: { Range: "items=0-25" }
679
- });
680
- }
681
- get(quotationId) {
682
- return this.fetch(
683
- `/companies/${this.companyId}/quotations/${quotationId}`
684
- );
685
- }
686
- create(params) {
687
- const body = {
688
- ...params,
689
- lines: params.lines?.map((line) => ({ ...line }))
690
- };
691
- for (const line of body.lines ?? []) {
692
- line.line_amount = line.quantity * line.unit_amount;
693
- line.sequence ??= 1;
694
- line.invoicing_category_type ??= "benefit";
695
- line.discount_description ??= "";
696
- line.discount_amount ??= null;
697
- line.discount_percentage ??= null;
698
- }
699
- return this.fetch(`/companies/${this.companyId}/quotations`, {
700
- method: "POST",
701
- body
702
- });
703
- }
704
- async downloadPdf(quotationId) {
705
- return this.fetch(
706
- `/companies/${this.companyId}/quotations/${quotationId}/pdf`,
707
- {
708
- headers: { Accept: "application/pdf" }
709
- }
710
- );
711
- }
712
- send(quotationId, params) {
713
- return this.fetch(
714
- `/companies/${this.companyId}/quotations/${quotationId}/send`,
715
- {
716
- method: "POST",
717
- body: params
718
- }
719
- );
720
- }
721
- };
722
-
723
- // src/resources/users.ts
724
- var UsersResource = class {
725
- constructor(fetch) {
726
- this.fetch = fetch;
727
- }
728
- me() {
729
- return this.fetch("/users/me");
730
- }
731
- legalInformations() {
732
- return this.fetch("/users/me/legal_informations");
733
- }
734
- settings(companyId) {
735
- return this.fetch(`/users/me/companies/${companyId}/settings`);
736
- }
737
- };
738
-
739
- // src/client.ts
740
- var BASE_URL = "https://chronos-api.tiime-apps.com/v1";
741
- var TiimeClient = class {
742
- fetch;
743
- tokenManager;
744
- companyId;
745
- constructor(options = {}) {
746
- this.companyId = resolveCompanyId(options.companyId);
747
- this.tokenManager = options.tokenManager ?? new TokenManager({
748
- tokens: options.tokens,
749
- email: options.email,
750
- password: options.password
751
- });
752
- this.fetch = ofetch2.create({
753
- baseURL: BASE_URL,
754
- retry: 2,
755
- retryDelay: 500,
756
- retryStatusCodes: [408, 429, 500, 502, 503, 504],
757
- headers: {
758
- "tiime-app": "tiime",
759
- "tiime-app-version": "4.30.3",
760
- "tiime-app-platform": "cli"
761
- },
762
- onRequest: async ({ options: options2 }) => {
763
- const token = await this.tokenManager.getValidToken();
764
- options2.headers.set("Authorization", `Bearer ${token}`);
765
- },
766
- onResponseError: ({ request, response }) => {
767
- throw new TiimeError(
768
- response.statusText || `HTTP ${response.status}`,
769
- response.status,
770
- String(request),
771
- response._data
772
- );
773
- }
774
- });
775
- }
776
- listCompanies() {
777
- return this.fetch("/companies", {
778
- headers: {
779
- Accept: "application/vnd.tiime.companies.v2+json",
780
- Range: "items=0-101"
781
- }
782
- });
783
- }
784
- get users() {
785
- return new UsersResource(this.fetch);
786
- }
787
- get company() {
788
- return new CompanyResource(this.fetch, this.companyId);
789
- }
790
- get clients() {
791
- return new ClientsResource(this.fetch, this.companyId);
792
- }
793
- get invoices() {
794
- return new InvoicesResource(this.fetch, this.companyId);
795
- }
796
- get quotations() {
797
- return new QuotationsResource(this.fetch, this.companyId);
798
- }
799
- get bankAccounts() {
800
- return new BankAccountsResource(this.fetch, this.companyId);
801
- }
802
- get bankTransactions() {
803
- return new BankTransactionsResource(this.fetch, this.companyId);
804
- }
805
- get documents() {
806
- return new DocumentsResource(this.fetch, this.companyId);
807
- }
808
- get expenseReports() {
809
- return new ExpenseReportsResource(this.fetch, this.companyId);
810
- }
811
- get labels() {
812
- return new LabelsResource(this.fetch, this.companyId);
813
- }
814
- };
815
- export {
816
- TiimeClient,
817
- TiimeError,
818
- TokenManager,
819
- resolveCompanyId
820
- };
1
+ var E=(s,e,t)=>{let n=new URL(e,s.endsWith("/")?s:`${s}/`);if(t)for(let[r,i]of Object.entries(t))i!=null&&n.searchParams.set(r,String(i));return n.href},q=s=>new Promise(e=>setTimeout(e,s)),D=s=>!!s?.includes("application/json")||!!s?.includes("+json"),I=s=>{let e=s.retry??0,t=s.retryDelay??500,n=new Set(s.retryStatusCodes??[]);return async(r,i)=>{let o=E(s.baseURL,r,i?.query),h=new Headers(s.headers);if(i?.headers)for(let[u,c]of Object.entries(i.headers))h.set(u,c);let l;i?.body!==void 0&&(i.body instanceof FormData?l=i.body:(h.set("Content-Type","application/json"),l=JSON.stringify(i.body))),s.onRequest&&await s.onRequest({options:{headers:h}});let p;for(let u=0;u<=e;u++){u>0&&await q(t);let c;try{c=await fetch(o,{method:i?.method??"GET",headers:h,body:l});}catch(m){if(p=m,u<e)continue;throw m}if(!c.ok&&n.has(c.status)&&(p=c,u<e))continue;if(!c.ok&&s.onResponseError){let m;try{m=await c.clone().json();}catch{}let C=Object.assign(c,{_data:m});s.onResponseError({request:o,response:C});}let A=c.headers.get("content-type");return c.status===204||!A?void 0:D(A)?c.json():c.arrayBuffer()}throw p}},R=async(s,e)=>{let t=await fetch(s,e);if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);return t.json()};var $="auth0.tiime.fr",B="iEbsbe3o66gcTBfGRa012kj1Rb6vjAND",M="https://chronos/",d=class{tokens=null;credentials=null;tokenStorage;credentialStorage;constructor(e={}){if(this.tokenStorage=e.tokenStorage??null,this.credentialStorage=e.credentialStorage??null,e.tokens){this.tokens=e.tokens;return}if(e.email&&e.password){this.credentials={email:e.email,password:e.password};return}let t=process.env.TIIME_ACCESS_TOKEN;if(t){this.tokens={access_token:t,expires_at:Number.MAX_SAFE_INTEGER};return}let n=process.env.TIIME_EMAIL,r=process.env.TIIME_PASSWORD;if(n&&r){this.credentials={email:n,password:r};return}this.tokenStorage&&(this.tokens=this.tokenStorage.load());}async login(e,t){let n=await R(`https://${$}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"password",client_id:B,audience:M,scope:"openid email",username:e,password:t})});return this.tokens={access_token:n.access_token,expires_at:Date.now()+n.expires_in*1e3},this.tokenStorage?.save(this.tokens),this.credentialStorage?.save(e,t),this.tokens}async getValidToken(){if(!this.tokens||this.isExpired()){let e=this.credentials??this.credentialStorage?.load()??null;if(e)return (await this.login(e.email,e.password)).access_token;throw new Error(this.tokens?"Token expired. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`.":"Not authenticated. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`.")}return this.tokens.access_token}isAuthenticated(){return this.tokens!==null&&!this.isExpired()}logout(){this.tokens=null,this.tokenStorage?.clear();}getTokenInfo(){if(!this.tokens)return {email:null,expiresAt:null};try{return {email:JSON.parse(Buffer.from(this.tokens.access_token.split(".")[1],"base64").toString())["tiime/userEmail"]||null,expiresAt:new Date(this.tokens.expires_at)}}catch{return {email:null,expiresAt:new Date(this.tokens.expires_at)}}}isExpired(){return this.tokens?Date.now()>=this.tokens.expires_at-6e4:true}};var g=class extends Error{constructor(t,n,r,i){super(t);this.status=n;this.endpoint=r;this.details=i;this.name="TiimeError";}toJSON(){return {error:this.name,message:this.message,status:this.status,endpoint:this.endpoint,details:this.details}}};var a=class{constructor(e,t){this.fetch=e;this.companyId=t;}url(e){return `/companies/${this.companyId}${e}`}};var f=class extends a{list(e){return this.fetch(this.url("/bank_accounts"),{query:e!==void 0?{enabled:e}:void 0})}get(e){return this.fetch(this.url(`/bank_accounts/${e}`))}async balance(){return (await this.list(true)).map(t=>({name:t.name,balance_amount:t.balance_amount,currency:t.balance_currency}))}};var y=class extends a{list(e){let t=((e?.page??1)-1)*(e?.pageSize??100),n=t+(e?.pageSize??100),{page:r,pageSize:i,from:o,to:h,search:l,...p}=e??{},u={...p};return o&&(u.transaction_date_start=o),h&&(u.transaction_date_end=h),l&&(u.wording=l),this.fetch(this.url("/bank_transactions"),{query:{hide_refused:false,...u},headers:{Accept:"application/vnd.tiime.bank_transactions.v2+json",Range:`items=${t}-${n}`}})}async listAll(e){let t=e?.pageSize??200,n=[],r=1,i=true;for(;i;){let o=await this.list({...e,page:r,pageSize:t});n.push(...o.transactions),i=o.transactions.length===t,r++;}return n}unimputed(){return this.fetch(this.url("/bank_transactions/unimputed"))}get(e){return this.fetch(this.url(`/bank_transactions/${e}`))}labelSuggestions(e){return this.fetch(this.url(`/bank_transactions/${e}/label_suggestions`),{headers:{Accept:"application/vnd.tiime.bank_transactions.label_suggestions.v2+json"}})}impute(e,t){return this.fetch(this.url(`/bank_transactions/${e}`),{method:"PATCH",body:{imputations:t}})}matchDocuments(e,t){return this.fetch(this.url(`/bank_transactions/${e}/document_matchings`),{method:"PUT",body:{documents:t.map(n=>({id:n}))}})}getMatchings(e){return this.fetch(this.url(`/bank_transactions/${e}/matchings`))}};var k=class extends a{list(e){return this.fetch(this.url("/clients"),{query:e,headers:{Accept:"application/vnd.tiime.timeline.v2+json",Range:"items=0-*"}})}get(e){return this.fetch(this.url(`/clients/${e}`))}create(e){return this.fetch(this.url("/clients"),{method:"POST",body:e})}search(e){return this.fetch(this.url("/clients"),{query:{search:e},headers:{Accept:"application/vnd.tiime.timeline.v2+json",Range:"items=0-*"}})}};var b=class extends a{get(){return this.fetch(this.url(""))}users(){return this.fetch(this.url("/users"))}appConfig(){return this.fetch(this.url("/app_config"))}accountingPeriod(e=1){return this.fetch(this.url("/accounting_period/current"),{query:{range_year:e}})}tiles(e){return this.fetch(this.url("/tiles"),{query:{keys:e.join(",")}})}dashboardBlocks(e="monitoring"){return this.fetch(this.url("/dashboard_blocks"),{query:{sorts:"rank:asc",display_group:e}})}};var _=class extends a{list(e){let t=((e?.page??1)-1)*(e?.pageSize??25),n=t+(e?.pageSize??25),{page:r,pageSize:i,...o}=e??{};return this.fetch(this.url("/documents"),{query:{sorts:"created_at:desc",expand:"file_family,preview_available",...o},headers:{Accept:"application/vnd.tiime.documents.v2+json,application/vnd.tiime.docs.query+json,application/vnd.tiime.docs.imputation+json",Range:`items=${t}-${n}`}})}categories(){return this.fetch(this.url("/document_categories"),{headers:{Accept:"application/vnd.tiime.documents.v3+json"}})}preview(e){return this.fetch(this.url(`/documents/${e}/preview`))}upload(e,t,n){let r=new FormData;return r.append("file",new Blob([e]),t),n&&r.append("type",n),this.fetch(this.url("/documents"),{method:"POST",body:r})}searchMatchable(e){return this.fetch(this.url("/documents"),{query:{matchable:true,q:e},headers:{Accept:"application/vnd.tiime.documents.v3+json,application/vnd.tiime.docs.imputation+json",Range:"items=0-25"}})}async download(e){return this.fetch(this.url(`/documents/${e}/download`),{headers:{Accept:"application/octet-stream"}})}};var v=class extends a{list(e="metadata.date:desc"){return this.fetch(this.url("/expense_reports"),{query:{expand:"total_amount",sorts:e},headers:{Range:"items=0-25"}})}get(e){return this.fetch(this.url(`/expense_reports/${e}`))}create(e){return this.fetch(this.url("/expense_reports"),{method:"POST",body:e})}};var w=class extends a{list(e){let t=((e?.page??1)-1)*(e?.pageSize??25),n=t+(e?.pageSize??25),r={sorts:e?.sorts??"invoice_number:desc"};return e?.status&&(r.status=e.status),this.fetch(this.url("/invoices"),{query:r,headers:{Range:`items=${t}-${n}`}})}async listAll(e){let t=e?.pageSize??100,n=[],r=1,i=true;for(;i;){let o=await this.list({sorts:e?.sorts,status:e?.status,page:r,pageSize:t});n.push(...o),i=o.length===t,r++;}return n}get(e){return this.fetch(this.url(`/invoices/${e}`))}create(e){let t={...e,lines:e.lines?.map(n=>({...n}))};for(let n of t.lines??[])n.line_amount=n.quantity*n.unit_amount,n.sequence??=1,n.invoicing_category_type??="benefit",n.discount_description??="",n.discount_amount??=null,n.discount_percentage??=null;return this.fetch(this.url("/invoices"),{method:"POST",body:t})}update(e,t){return this.fetch(this.url(`/invoices/${e}`),{method:"PUT",body:t})}send(e,t){return this.fetch(this.url(`/invoices/${e}/send`),{method:"POST",body:t})}async downloadPdf(e){return this.fetch(this.url(`/invoices/${e}/pdf`),{headers:{Accept:"application/pdf"}})}delete(e){return this.fetch(this.url(`/invoices/${e}`),{method:"DELETE"})}async duplicate(e,t){let n=await this.get(e),r=new Date().toISOString().split("T")[0],i=n.lines.map(o=>({description:o.description,quantity:t?.quantity??o.quantity,unit_amount:o.unit_amount,vat_type:o.vat_type,invoicing_unit:o.invoicing_unit,invoicing_category_type:o.invoicing_category_type,article:o.article}));return this.create({client:n.client_id?{id:n.client_id}:null,emission_date:t?.emission_date??r,title:n.title,title_enabled:!!n.title,lines:i,status:"draft"})}};var T=class extends a{list(){return this.fetch(this.url("/labels"),{headers:{Accept:"application/vnd.tiime.labels.v2+json"}})}standard(){return this.fetch(this.url("/standard_labels"))}tags(){return this.fetch(this.url("/tags"),{query:{expand:"tag_detail"}})}};var S=class extends a{list(e="invoices"){return this.fetch(this.url("/quotations"),{query:{expand:e},headers:{Range:"items=0-25"}})}get(e){return this.fetch(this.url(`/quotations/${e}`))}create(e){let t={...e,lines:e.lines?.map(n=>({...n}))};for(let n of t.lines??[])n.line_amount=n.quantity*n.unit_amount,n.sequence??=1,n.invoicing_category_type??="benefit",n.discount_description??="",n.discount_amount??=null,n.discount_percentage??=null;return this.fetch(this.url("/quotations"),{method:"POST",body:t})}async downloadPdf(e){return this.fetch(this.url(`/quotations/${e}/pdf`),{headers:{Accept:"application/pdf"}})}send(e,t){return this.fetch(this.url(`/quotations/${e}/send`),{method:"POST",body:t})}};var P=class{constructor(e){this.fetch=e;}me(){return this.fetch("/users/me")}legalInformations(){return this.fetch("/users/me/legal_informations")}settings(e){return this.fetch(`/users/me/companies/${e}/settings`)}};var O="https://chronos-api.tiime-apps.com/v1",x=class{fetch;tokenManager;companyId;constructor(e){this.companyId=e.companyId,this.tokenManager=e.tokenManager??new d({tokens:e.tokens,email:e.email,password:e.password}),this.fetch=I({baseURL:O,retry:2,retryDelay:500,retryStatusCodes:[408,429,500,502,503,504],headers:{"tiime-app":"tiime","tiime-app-version":"4.30.3","tiime-app-platform":"cli"},onRequest:async({options:t})=>{let n=await this.tokenManager.getValidToken();t.headers.set("Authorization",`Bearer ${n}`);},onResponseError:({request:t,response:n})=>{throw new g(n.statusText||`HTTP ${n.status}`,n.status,String(t),n._data)}});}listCompanies(){return this.fetch("/companies",{headers:{Accept:"application/vnd.tiime.companies.v2+json",Range:"items=0-101"}})}get users(){return new P(this.fetch)}get company(){return new b(this.fetch,this.companyId)}get clients(){return new k(this.fetch,this.companyId)}get invoices(){return new w(this.fetch,this.companyId)}get quotations(){return new S(this.fetch,this.companyId)}get bankAccounts(){return new f(this.fetch,this.companyId)}get bankTransactions(){return new y(this.fetch,this.companyId)}get documents(){return new _(this.fetch,this.companyId)}get expenseReports(){return new v(this.fetch,this.companyId)}get labels(){return new T(this.fetch,this.companyId)}};
2
+ export{x as TiimeClient,g as TiimeError,d as TokenManager};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiime-sdk",
3
- "version": "2.1.2",
3
+ "version": "3.0.0",
4
4
  "description": "TypeScript SDK for Tiime accounting API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,9 +44,6 @@
44
44
  "engines": {
45
45
  "node": ">=20"
46
46
  },
47
- "dependencies": {
48
- "ofetch": "^1.5.1"
49
- },
50
47
  "devDependencies": {
51
48
  "@biomejs/biome": "^2.4.6",
52
49
  "@types/node": "^25.3.5",