@ikatec/digisac-api-sdk 4.1.0 → 4.3.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.
Files changed (127) hide show
  1. package/README.md +7 -4
  2. package/dist/apis/authHistory/AuthHistoryApi.cjs +12 -12
  3. package/dist/apis/authHistory/AuthHistoryApi.cjs.map +1 -1
  4. package/dist/apis/authHistory/AuthHistoryApi.d.ts +12 -19
  5. package/dist/apis/authHistory/AuthHistoryApi.d.ts.map +1 -1
  6. package/dist/apis/authHistory/AuthHistoryApi.mjs +12 -12
  7. package/dist/apis/authHistory/AuthHistoryApi.mjs.map +1 -1
  8. package/dist/apis/authHistory/types.d.ts +4 -3
  9. package/dist/apis/authHistory/types.d.ts.map +1 -1
  10. package/dist/apis/customFields/types.d.ts +21 -19
  11. package/dist/apis/customFields/types.d.ts.map +1 -1
  12. package/dist/apis/dashboard/DashboardApi.cjs +54 -0
  13. package/dist/apis/dashboard/DashboardApi.cjs.map +1 -0
  14. package/dist/apis/dashboard/DashboardApi.d.ts +65 -0
  15. package/dist/apis/dashboard/DashboardApi.d.ts.map +1 -0
  16. package/dist/apis/dashboard/DashboardApi.mjs +53 -0
  17. package/dist/apis/dashboard/DashboardApi.mjs.map +1 -0
  18. package/dist/apis/dashboard/index.cjs +4 -0
  19. package/dist/apis/dashboard/index.d.ts +3 -0
  20. package/dist/apis/dashboard/index.d.ts.map +1 -0
  21. package/dist/apis/dashboard/index.mjs +3 -0
  22. package/dist/apis/dashboard/types.cjs +0 -0
  23. package/dist/apis/dashboard/types.d.ts +124 -0
  24. package/dist/apis/dashboard/types.d.ts.map +1 -0
  25. package/dist/apis/dashboard/types.mjs +0 -0
  26. package/dist/apis/holiday/types.d.ts +34 -8
  27. package/dist/apis/holiday/types.d.ts.map +1 -1
  28. package/dist/apis/index.cjs +6 -0
  29. package/dist/apis/index.d.ts +2 -0
  30. package/dist/apis/index.d.ts.map +1 -1
  31. package/dist/apis/index.mjs +5 -1
  32. package/dist/apis/now/NowApi.cjs +37 -0
  33. package/dist/apis/now/NowApi.cjs.map +1 -0
  34. package/dist/apis/now/NowApi.d.ts +26 -0
  35. package/dist/apis/now/NowApi.d.ts.map +1 -0
  36. package/dist/apis/now/NowApi.mjs +36 -0
  37. package/dist/apis/now/NowApi.mjs.map +1 -0
  38. package/dist/apis/now/index.cjs +4 -0
  39. package/dist/apis/now/index.d.ts +3 -0
  40. package/dist/apis/now/index.d.ts.map +1 -0
  41. package/dist/apis/now/index.mjs +3 -0
  42. package/dist/apis/now/types.cjs +0 -0
  43. package/dist/apis/now/types.d.ts +45 -0
  44. package/dist/apis/now/types.d.ts.map +1 -0
  45. package/dist/apis/now/types.mjs +0 -0
  46. package/dist/apis/people/types.d.ts +7 -2
  47. package/dist/apis/people/types.d.ts.map +1 -1
  48. package/dist/apis/permissions/PermissionsApi.cjs +6 -2
  49. package/dist/apis/permissions/PermissionsApi.cjs.map +1 -1
  50. package/dist/apis/permissions/PermissionsApi.d.ts +7 -3
  51. package/dist/apis/permissions/PermissionsApi.d.ts.map +1 -1
  52. package/dist/apis/permissions/PermissionsApi.mjs +6 -2
  53. package/dist/apis/permissions/PermissionsApi.mjs.map +1 -1
  54. package/dist/apis/permissions/types.d.ts +4 -14
  55. package/dist/apis/permissions/types.d.ts.map +1 -1
  56. package/dist/apis/personalAccessTokens/PersonalAccessTokensApi.cjs +5 -0
  57. package/dist/apis/personalAccessTokens/PersonalAccessTokensApi.cjs.map +1 -1
  58. package/dist/apis/personalAccessTokens/PersonalAccessTokensApi.d.ts +5 -0
  59. package/dist/apis/personalAccessTokens/PersonalAccessTokensApi.d.ts.map +1 -1
  60. package/dist/apis/personalAccessTokens/PersonalAccessTokensApi.mjs +5 -0
  61. package/dist/apis/personalAccessTokens/PersonalAccessTokensApi.mjs.map +1 -1
  62. package/dist/apis/personalAccessTokens/types.d.ts +23 -4
  63. package/dist/apis/personalAccessTokens/types.d.ts.map +1 -1
  64. package/dist/apis/roles/RolesApi.cjs.map +1 -1
  65. package/dist/apis/roles/RolesApi.d.ts +2 -2
  66. package/dist/apis/roles/RolesApi.d.ts.map +1 -1
  67. package/dist/apis/roles/RolesApi.mjs.map +1 -1
  68. package/dist/apis/roles/types.d.ts +27 -4
  69. package/dist/apis/roles/types.d.ts.map +1 -1
  70. package/dist/apis/terms/TermsApi.cjs +4 -1
  71. package/dist/apis/terms/TermsApi.cjs.map +1 -1
  72. package/dist/apis/terms/TermsApi.d.ts +4 -1
  73. package/dist/apis/terms/TermsApi.d.ts.map +1 -1
  74. package/dist/apis/terms/TermsApi.mjs +4 -1
  75. package/dist/apis/terms/TermsApi.mjs.map +1 -1
  76. package/dist/apis/timetable/types.d.ts +12 -7
  77. package/dist/apis/timetable/types.d.ts.map +1 -1
  78. package/dist/core/BaseCrudApi.cjs +3 -30
  79. package/dist/core/BaseCrudApi.cjs.map +1 -1
  80. package/dist/core/BaseCrudApi.d.ts +4 -24
  81. package/dist/core/BaseCrudApi.d.ts.map +1 -1
  82. package/dist/core/BaseCrudApi.mjs +3 -30
  83. package/dist/core/BaseCrudApi.mjs.map +1 -1
  84. package/dist/core/BaseReadApi.cjs +44 -0
  85. package/dist/core/BaseReadApi.cjs.map +1 -0
  86. package/dist/core/BaseReadApi.d.ts +32 -0
  87. package/dist/core/BaseReadApi.d.ts.map +1 -0
  88. package/dist/core/BaseReadApi.mjs +43 -0
  89. package/dist/core/BaseReadApi.mjs.map +1 -0
  90. package/dist/core/index.cjs +2 -0
  91. package/dist/core/index.d.ts +1 -0
  92. package/dist/core/index.d.ts.map +1 -1
  93. package/dist/core/index.mjs +2 -1
  94. package/dist/index.cjs +2 -0
  95. package/dist/index.mjs +2 -1
  96. package/package.json +1 -1
  97. package/src/apis/authHistory/AuthHistoryApi.test.ts +10 -2
  98. package/src/apis/authHistory/AuthHistoryApi.ts +13 -39
  99. package/src/apis/authHistory/types.ts +4 -3
  100. package/src/apis/customFields/types.ts +21 -25
  101. package/src/apis/dashboard/DashboardApi.test-d.ts +49 -0
  102. package/src/apis/dashboard/DashboardApi.test.ts +270 -0
  103. package/src/apis/dashboard/DashboardApi.ts +146 -0
  104. package/src/apis/dashboard/index.ts +2 -0
  105. package/src/apis/dashboard/types.ts +131 -0
  106. package/src/apis/holiday/types.ts +36 -8
  107. package/src/apis/index.ts +2 -0
  108. package/src/apis/now/NowApi.test.ts +125 -0
  109. package/src/apis/now/NowApi.ts +59 -0
  110. package/src/apis/now/index.ts +2 -0
  111. package/src/apis/now/types.ts +47 -0
  112. package/src/apis/payloads.test-d.ts +39 -0
  113. package/src/apis/payloads.test.ts +81 -0
  114. package/src/apis/people/types.ts +7 -2
  115. package/src/apis/permissions/PermissionsApi.test.ts +93 -0
  116. package/src/apis/permissions/PermissionsApi.ts +7 -7
  117. package/src/apis/permissions/types.ts +4 -16
  118. package/src/apis/personalAccessTokens/PersonalAccessTokensApi.ts +5 -0
  119. package/src/apis/personalAccessTokens/types.ts +25 -4
  120. package/src/apis/queryFormat.test.ts +139 -0
  121. package/src/apis/roles/RolesApi.ts +7 -2
  122. package/src/apis/roles/types.ts +27 -4
  123. package/src/apis/terms/TermsApi.ts +4 -1
  124. package/src/apis/timetable/types.ts +13 -7
  125. package/src/core/BaseCrudApi.ts +4 -60
  126. package/src/core/BaseReadApi.ts +70 -0
  127. package/src/core/index.ts +1 -0
@@ -0,0 +1,43 @@
1
+ import { BaseApi } from "./BaseApi.mjs";
2
+
3
+ //#region src/core/BaseReadApi.ts
4
+ /**
5
+ * Generic read-only resource: `getMany`, `getOne` and `getById` under `basePath`. Base of
6
+ * `BaseCrudApi`, and of the resources the backend only serves for reading (e.g. permissions,
7
+ * auth history).
8
+ */
9
+ var BaseReadApi = class extends BaseApi {
10
+ basePath;
11
+ constructor(client, basePath) {
12
+ super(client);
13
+ this.basePath = basePath.replace(/\/$/, "");
14
+ }
15
+ getMany(query, headers) {
16
+ const queryString = this.toQueryString(query);
17
+ return this.client.get(`${this.basePath}${queryString}`, headers);
18
+ }
19
+ /**
20
+ * Returns the first resource matching the query, or `null` when none match.
21
+ * Convenience over `getMany` with `limit: 1`.
22
+ * @permissions $resourceName.view
23
+ */
24
+ async getOne(query, headers) {
25
+ return (await this.getMany({
26
+ ...query,
27
+ limit: 1,
28
+ paginate: false
29
+ }, headers))?.[0] ?? null;
30
+ }
31
+ /**
32
+ * Returns a single resource by ID. When it does not exist most routes answer 200 with an empty
33
+ * body, which resolves to `undefined`.
34
+ * @permissions $resourceName.view
35
+ */
36
+ getById(id, query, headers) {
37
+ return this.client.get(`${this.basePath}/${id}${this.toQueryString(query)}`, headers);
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ export { BaseReadApi };
43
+ //# sourceMappingURL=BaseReadApi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseReadApi.mjs","names":[],"sources":["../../src/core/BaseReadApi.ts"],"sourcesContent":["import type { ApiClient } from './ApiClient'\nimport { BaseApi } from './BaseApi'\nimport type { GetByIdQuery, HasGetById, HasGetMany, ListQuery, Paginated } from './types'\n\n/**\n * Generic read-only resource: `getMany`, `getOne` and `getById` under `basePath`. Base of\n * `BaseCrudApi`, and of the resources the backend only serves for reading (e.g. permissions,\n * auth history).\n */\nexport class BaseReadApi<TResponse, TQuery extends ListQuery<TResponse> = ListQuery<TResponse>>\n extends BaseApi\n implements HasGetMany<TResponse, TQuery>, HasGetById<TResponse>\n{\n public readonly basePath: string\n\n constructor(client: ApiClient, basePath: string) {\n super(client)\n this.basePath = basePath.replace(/\\/$/, '')\n }\n\n getMany(\n query: TQuery & { paginate: false },\n headers?: Record<string, string>,\n ): Promise<TResponse[]>\n getMany(\n query?: TQuery & { paginate?: true },\n headers?: Record<string, string>,\n ): Promise<Paginated<TResponse>>\n getMany(\n query?: TQuery,\n headers?: Record<string, string>,\n ): Promise<Paginated<TResponse> | TResponse[]>\n getMany(\n query?: TQuery,\n headers?: Record<string, string>,\n ): Promise<Paginated<TResponse> | TResponse[]> {\n const queryString = this.toQueryString(query)\n return this.client.get<Paginated<TResponse> | TResponse[]>(\n `${this.basePath}${queryString}`,\n headers,\n )\n }\n\n /**\n * Returns the first resource matching the query, or `null` when none match.\n * Convenience over `getMany` with `limit: 1`.\n * @permissions $resourceName.view\n */\n async getOne(query?: TQuery, headers?: Record<string, string>): Promise<TResponse | null> {\n const results = await this.getMany(\n { ...query, limit: 1, paginate: false } as TQuery & { paginate: false },\n headers,\n )\n // An empty response body resolves to `undefined`.\n return results?.[0] ?? null\n }\n\n /**\n * Returns a single resource by ID. When it does not exist most routes answer 200 with an empty\n * body, which resolves to `undefined`.\n * @permissions $resourceName.view\n */\n getById(\n id: string,\n query?: GetByIdQuery<TResponse>,\n headers?: Record<string, string>,\n ): Promise<TResponse> {\n return this.client.get<TResponse>(`${this.basePath}/${id}${this.toQueryString(query)}`, headers)\n }\n}\n"],"mappings":";;;;;;;;AASA,IAAa,cAAb,cACU,QAEV;CACE,AAAgB;CAEhB,YAAY,QAAmB,UAAkB;AAC/C,QAAM,OAAO;AACb,OAAK,WAAW,SAAS,QAAQ,OAAO,GAAG;;CAe7C,QACE,OACA,SAC6C;EAC7C,MAAM,cAAc,KAAK,cAAc,MAAM;AAC7C,SAAO,KAAK,OAAO,IACjB,GAAG,KAAK,WAAW,eACnB,QACD;;;;;;;CAQH,MAAM,OAAO,OAAgB,SAA6D;AAMxF,UALgB,MAAM,KAAK,QACzB;GAAE,GAAG;GAAO,OAAO;GAAG,UAAU;GAAO,EACvC,QACD,IAEgB,MAAM;;;;;;;CAQzB,QACE,IACA,OACA,SACoB;AACpB,SAAO,KAAK,OAAO,IAAe,GAAG,KAAK,SAAS,GAAG,KAAK,KAAK,cAAc,MAAM,IAAI,QAAQ"}
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_core_errors = require('./errors.cjs');
3
3
  const require_core_BaseApiClient = require('./BaseApiClient.cjs');
4
4
  const require_core_BaseApi = require('./BaseApi.cjs');
5
+ const require_core_BaseReadApi = require('./BaseReadApi.cjs');
5
6
  const require_core_BaseCrudApi = require('./BaseCrudApi.cjs');
6
7
  const require_core_ArchivableCrudApi = require('./ArchivableCrudApi.cjs');
7
8
 
@@ -13,6 +14,7 @@ exports.BadRequestError = require_core_errors.BadRequestError;
13
14
  exports.BaseApi = require_core_BaseApi.BaseApi;
14
15
  exports.BaseApiClient = require_core_BaseApiClient.BaseApiClient;
15
16
  exports.BaseCrudApi = require_core_BaseCrudApi.BaseCrudApi;
17
+ exports.BaseReadApi = require_core_BaseReadApi.BaseReadApi;
16
18
  exports.ConflictError = require_core_errors.ConflictError;
17
19
  exports.DigisacError = require_core_errors.DigisacError;
18
20
  exports.InternalServerError = require_core_errors.InternalServerError;
@@ -5,6 +5,7 @@ export type { QueryFormat } from './queryString';
5
5
  export { DigisacError, ApiConnectionError, ApiError, BadRequestError, ValidationError, AuthenticationError, PaymentRequiredError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableEntityError, RateLimitError, InternalServerError, parseFieldErrors, } from './errors';
6
6
  export type { FieldError, ErrorClassName, ApiErrorOptions } from './errors';
7
7
  export { BaseApi } from './BaseApi';
8
+ export { BaseReadApi } from './BaseReadApi';
8
9
  export { BaseCrudApi } from './BaseCrudApi';
9
10
  export { ArchivableCrudApi } from './ArchivableCrudApi';
10
11
  export type { WhereClause, IncludeItem, ListQuery, GetByIdQuery, Paginated } from './types';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,UAAU,CAAA;AACjB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA"}
@@ -1,7 +1,8 @@
1
1
  import { ApiConnectionError, ApiError, AuthenticationError, BadRequestError, ConflictError, DigisacError, InternalServerError, NotFoundError, PaymentRequiredError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, ValidationError, parseFieldErrors } from "./errors.mjs";
2
2
  import { BaseApiClient } from "./BaseApiClient.mjs";
3
3
  import { BaseApi } from "./BaseApi.mjs";
4
+ import { BaseReadApi } from "./BaseReadApi.mjs";
4
5
  import { BaseCrudApi } from "./BaseCrudApi.mjs";
5
6
  import { ArchivableCrudApi } from "./ArchivableCrudApi.mjs";
6
7
 
7
- export { ApiConnectionError, ApiError, ArchivableCrudApi, AuthenticationError, BadRequestError, BaseApi, BaseApiClient, BaseCrudApi, ConflictError, DigisacError, InternalServerError, NotFoundError, PaymentRequiredError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, ValidationError, parseFieldErrors };
8
+ export { ApiConnectionError, ApiError, ArchivableCrudApi, AuthenticationError, BadRequestError, BaseApi, BaseApiClient, BaseCrudApi, BaseReadApi, ConflictError, DigisacError, InternalServerError, NotFoundError, PaymentRequiredError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, ValidationError, parseFieldErrors };
package/dist/index.cjs CHANGED
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_core_errors = require('./core/errors.cjs');
3
3
  const require_core_BaseApiClient = require('./core/BaseApiClient.cjs');
4
4
  const require_core_BaseApi = require('./core/BaseApi.cjs');
5
+ const require_core_BaseReadApi = require('./core/BaseReadApi.cjs');
5
6
  const require_core_BaseCrudApi = require('./core/BaseCrudApi.cjs');
6
7
  const require_core_ArchivableCrudApi = require('./core/ArchivableCrudApi.cjs');
7
8
  require('./core/index.cjs');
@@ -14,6 +15,7 @@ exports.BadRequestError = require_core_errors.BadRequestError;
14
15
  exports.BaseApi = require_core_BaseApi.BaseApi;
15
16
  exports.BaseApiClient = require_core_BaseApiClient.BaseApiClient;
16
17
  exports.BaseCrudApi = require_core_BaseCrudApi.BaseCrudApi;
18
+ exports.BaseReadApi = require_core_BaseReadApi.BaseReadApi;
17
19
  exports.ConflictError = require_core_errors.ConflictError;
18
20
  exports.DigisacError = require_core_errors.DigisacError;
19
21
  exports.InternalServerError = require_core_errors.InternalServerError;
package/dist/index.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  import { ApiConnectionError, ApiError, AuthenticationError, BadRequestError, ConflictError, DigisacError, InternalServerError, NotFoundError, PaymentRequiredError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, ValidationError, parseFieldErrors } from "./core/errors.mjs";
2
2
  import { BaseApiClient } from "./core/BaseApiClient.mjs";
3
3
  import { BaseApi } from "./core/BaseApi.mjs";
4
+ import { BaseReadApi } from "./core/BaseReadApi.mjs";
4
5
  import { BaseCrudApi } from "./core/BaseCrudApi.mjs";
5
6
  import { ArchivableCrudApi } from "./core/ArchivableCrudApi.mjs";
6
7
  import "./core/index.mjs";
7
8
 
8
- export { ApiConnectionError, ApiError, ArchivableCrudApi, AuthenticationError, BadRequestError, BaseApi, BaseApiClient, BaseCrudApi, ConflictError, DigisacError, InternalServerError, NotFoundError, PaymentRequiredError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, ValidationError, parseFieldErrors };
9
+ export { ApiConnectionError, ApiError, ArchivableCrudApi, AuthenticationError, BadRequestError, BaseApi, BaseApiClient, BaseCrudApi, BaseReadApi, ConflictError, DigisacError, InternalServerError, NotFoundError, PaymentRequiredError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, ValidationError, parseFieldErrors };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikatec/digisac-api-sdk",
3
- "version": "4.1.0",
3
+ "version": "4.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -25,7 +25,6 @@ const entry: AuthHistory = {
25
25
  event: 'auth',
26
26
  userId: 'user-1',
27
27
  accountId: 'acc-1',
28
- branch: 'main',
29
28
  originIP: '127.0.0.1',
30
29
  originUA: 'Mozilla/5.0',
31
30
  createdAt: '2024-01-01T00:00:00Z',
@@ -95,10 +94,19 @@ describe('AuthHistoryApi', () => {
95
94
  expect(result).toEqual(entry)
96
95
  })
97
96
 
97
+ it('sends the query (e.g. include) in the query string, not as headers', async () => {
98
+ vi.mocked(client.get).mockResolvedValue(entry)
99
+ await api.getById('ah-1', { include: ['user'] })
100
+ expect(client.get).toHaveBeenCalledWith(
101
+ `/auth-history/ah-1?query=${encodeURIComponent(JSON.stringify({ include: ['user'] }))}`,
102
+ undefined,
103
+ )
104
+ })
105
+
98
106
  it('forwards custom headers', async () => {
99
107
  vi.mocked(client.get).mockResolvedValue(entry)
100
108
  const headers = { 'X-Custom': 'h' }
101
- await api.getById('ah-1', headers)
109
+ await api.getById('ah-1', undefined, headers)
102
110
  expect(client.get).toHaveBeenCalledWith('/auth-history/ah-1', headers)
103
111
  })
104
112
 
@@ -1,43 +1,17 @@
1
- import { BaseApi } from '../../core/BaseApi'
2
- import type { ListQuery, Paginated, HasGetMany, HasGetById } from '../../core/types'
1
+ import type { ApiClient } from '../../core/ApiClient'
2
+ import { BaseReadApi } from '../../core/BaseReadApi'
3
3
  import type { AuthHistory } from './types'
4
4
 
5
- export class AuthHistoryApi
6
- extends BaseApi
7
- implements HasGetMany<AuthHistory>, HasGetById<AuthHistory>
8
- {
9
- /**
10
- * Returns a paginated list of authentication events (auth, password_change, logout). Non-admin users can only see their own records.
11
- * @permissions authHistory.view
12
- */
13
- getMany(
14
- query: ListQuery<AuthHistory> & { paginate: false },
15
- headers?: Record<string, string>,
16
- ): Promise<AuthHistory[]>
17
- getMany(
18
- query?: ListQuery<AuthHistory> & { paginate?: true },
19
- headers?: Record<string, string>,
20
- ): Promise<Paginated<AuthHistory>>
21
- getMany(
22
- query?: ListQuery<AuthHistory>,
23
- headers?: Record<string, string>,
24
- ): Promise<Paginated<AuthHistory> | AuthHistory[]>
25
- getMany(
26
- query?: ListQuery<AuthHistory>,
27
- headers?: Record<string, string>,
28
- ): Promise<Paginated<AuthHistory> | AuthHistory[]> {
29
- const queryString = this.toQueryString(query)
30
- return this.client.get<Paginated<AuthHistory> | AuthHistory[]>(
31
- `/auth-history${queryString}`,
32
- headers,
33
- )
34
- }
35
-
36
- /**
37
- * Returns a single authentication event by its ID. Non-admin users can only access their own records.
38
- * @permissions authHistory.view
39
- */
40
- getById(id: string, headers?: Record<string, string>): Promise<AuthHistory> {
41
- return this.client.get<AuthHistory>(`/auth-history/${id}`, headers)
5
+ /**
6
+ * Authentication events (auth, password_change, logout), read-only (guarded by
7
+ * `authHistory.view`). Non-admin users can only see and access their own records.
8
+ *
9
+ * Since 4.2 `getById` has the base signature `(id, query?, headers?)`: a call written as
10
+ * `getById(id, headers)` with the headers in a variable still compiles, but the headers are sent
11
+ * as the query string — move them to the third argument.
12
+ */
13
+ export class AuthHistoryApi extends BaseReadApi<AuthHistory> {
14
+ constructor(client: ApiClient) {
15
+ super(client, '/auth-history')
42
16
  }
43
17
  }
@@ -8,9 +8,10 @@ export type AuthHistory = {
8
8
  event: AuthHistoryEvent
9
9
  userId: string
10
10
  accountId: string
11
- branch: string
12
- originIP: string
13
- originUA: string
11
+ /** Nullable in the database. */
12
+ originIP: string | null
13
+ /** Nullable in the database. */
14
+ originUA: string | null
14
15
  createdAt: string
15
16
  updatedAt: string
16
17
  // relationships
@@ -17,33 +17,29 @@ export type CustomFieldType =
17
17
  | 'list'
18
18
 
19
19
  export type CustomFieldOption = {
20
- id?: string
21
- label?: string
20
+ id?: string | null
21
+ label?: string | null
22
22
  }
23
23
 
24
- /** Settings for `list` and `checkbox` types: a list of selectable options. */
25
- export type CustomFieldListSettings = {
26
- options: CustomFieldOption[]
24
+ /**
25
+ * Settings of a custom field — a free JSONB the backend does not validate, echoed back as sent.
26
+ * The fields below are the ones the web app form sends (`front/src/pages/custom-fields/components/
27
+ * form.tsx`): `options` for the `list` and `checkbox` types, `min`/`max` for `numeric` and `monetary`,
28
+ * `currency` for `monetary`, `maxLength` for `text` and `long-text`, and `placeholder` for the inputs.
29
+ */
30
+ export type CustomFieldSettings = {
31
+ options?: CustomFieldOption[]
32
+ placeholder?: string | null
33
+ currency?: string | null
34
+ maxLength?: number | null
35
+ min?: string | null
36
+ max?: string | null
27
37
  }
28
38
 
29
- /** Settings for `monetary` type: optional min/max value constraints. */
30
- export type CustomFieldMonetarySettings = {
31
- options: CustomFieldOption[]
32
- min?: string
33
- max?: string
34
- }
35
-
36
- /** Settings for `text` and `long-text` types: optional max length constraint. */
37
- export type CustomFieldTextSettings = {
38
- options: CustomFieldOption[]
39
- maxLength?: number
40
- }
41
-
42
- export type CustomFieldSettings =
43
- | CustomFieldListSettings
44
- | CustomFieldMonetarySettings
45
- | CustomFieldTextSettings
46
-
39
+ /**
40
+ * A custom field of the account. Custom fields are soft-deleted, but `deletedAt` is never returned
41
+ * (customFieldsTransformer).
42
+ */
47
43
  export type CustomField = {
48
44
  id: string
49
45
  name: string
@@ -55,7 +51,6 @@ export type CustomField = {
55
51
  accountId: string
56
52
  createdAt: string
57
53
  updatedAt: string
58
- deletedAt: string | null
59
54
  }
60
55
 
61
56
  export type CreateCustomFieldPayload = {
@@ -64,12 +59,13 @@ export type CreateCustomFieldPayload = {
64
59
  allowed: 'contacts'
65
60
  showOnRegister?: boolean
66
61
  required?: boolean
67
- settings?: CustomFieldSettings
62
+ settings?: CustomFieldSettings | null
68
63
  }
69
64
 
70
65
  export type UpdateCustomFieldPayload = {
71
66
  name?: string
72
67
  type?: CustomFieldType
68
+ allowed?: 'contacts'
73
69
  showOnRegister?: boolean
74
70
  required?: boolean
75
71
  settings?: CustomFieldSettings | null
@@ -0,0 +1,49 @@
1
+ import { expectError, expectType } from 'tsd'
2
+ import type { ApiClient } from '../../core/ApiClient'
3
+ import { DashboardApi } from './DashboardApi'
4
+ import type {
5
+ DashboardDepartmentItem,
6
+ DashboardGrouped,
7
+ DashboardPeriodItem,
8
+ DashboardQuery,
9
+ DashboardUserItem,
10
+ } from './types'
11
+
12
+ declare const client: ApiClient
13
+ declare const filters: DashboardQuery
14
+ declare const flag: boolean
15
+ const dashboard = new DashboardApi(client)
16
+
17
+ // ── without `withTotals` (or `false`): the plain array ──────────────
18
+
19
+ expectType<Promise<DashboardPeriodItem[]>>(dashboard.getByPeriod())
20
+ expectType<Promise<DashboardPeriodItem[]>>(dashboard.getByPeriod({ grouping: 'weekly' }))
21
+ expectType<Promise<DashboardPeriodItem[]>>(dashboard.getByPeriod({ withTotals: false }))
22
+ expectType<Promise<DashboardPeriodItem[]>>(dashboard.getByPeriod(filters))
23
+ expectType<Promise<DashboardUserItem[]>>(dashboard.getByUser(filters))
24
+ expectType<Promise<DashboardDepartmentItem[]>>(dashboard.getByDepartment(filters))
25
+
26
+ // ── `withTotals: true`: `{ totals, items }` ─────────────────────────
27
+
28
+ expectType<Promise<DashboardGrouped<DashboardPeriodItem>>>(
29
+ dashboard.getByPeriod({ withTotals: true }),
30
+ )
31
+ expectType<Promise<DashboardGrouped<DashboardPeriodItem>>>(
32
+ dashboard.getByPeriod({ ...filters, withTotals: true }),
33
+ )
34
+ expectType<Promise<DashboardGrouped<DashboardUserItem>>>(dashboard.getByUser({ withTotals: true }))
35
+ expectType<Promise<DashboardGrouped<DashboardDepartmentItem>>>(
36
+ dashboard.getByDepartment({ withTotals: true }),
37
+ )
38
+
39
+ // ── `withTotals` only known at runtime: the union ───────────────────
40
+
41
+ expectType<Promise<DashboardPeriodItem[] | DashboardGrouped<DashboardPeriodItem>>>(
42
+ dashboard.getByPeriod({ ...filters, withTotals: flag }),
43
+ )
44
+
45
+ // ── what the backend does not take ──────────────────────────────────
46
+
47
+ expectError(dashboard.getByPeriod({ grouping: 'quarterly' }))
48
+ expectError(dashboard.getByTopic({ withTotals: true }))
49
+ expectError(dashboard.getByService({ withTotals: true }))
@@ -0,0 +1,270 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { DashboardApi } from './DashboardApi'
3
+ import type { ApiClient } from '../../core/ApiClient'
4
+ import type {
5
+ DashboardDepartmentItem,
6
+ DashboardGeneral,
7
+ DashboardPeriodItem,
8
+ DashboardQuery,
9
+ DashboardServiceItem,
10
+ DashboardTopicItem,
11
+ DashboardUserItem,
12
+ DashboardWithTotals,
13
+ } from './types'
14
+
15
+ // ── Mock client factory ──────────────────────────────────────────────
16
+
17
+ function createMockClient(): ApiClient {
18
+ return {
19
+ setAccessToken: vi.fn().mockReturnThis(),
20
+ request: vi.fn(),
21
+ get: vi.fn(),
22
+ post: vi.fn(),
23
+ put: vi.fn(),
24
+ patch: vi.fn(),
25
+ delete: vi.fn(),
26
+ }
27
+ }
28
+
29
+ // ── Fixtures ─────────────────────────────────────────────────────────
30
+
31
+ const general: DashboardGeneral = {
32
+ sentMessagesCount: 10,
33
+ receivedMessagesCount: 5,
34
+ totalMessagesCount: 15,
35
+ openedTicketsCount: 2,
36
+ closedTicketsCount: 3,
37
+ totalTicketsCount: 5,
38
+ waitingTime: 60,
39
+ waitingTimeAfterBot: 30,
40
+ waitingTimeAvg: 45,
41
+ ticketTime: 600,
42
+ contactsCount: 4,
43
+ }
44
+
45
+ const periodItems: DashboardPeriodItem[] = [
46
+ { name: '01/09/2026', sentMessagesCount: 4, receivedMessagesCount: 2, totalMessagesCount: 6 },
47
+ { name: '02/09/2026', openedTicketsCount: 1, closedTicketsCount: 1, totalTicketsCount: 2 },
48
+ ]
49
+
50
+ const userItems: DashboardUserItem[] = [
51
+ { name: 'Alice', sentMessagesCount: 7, closedTicketsCount: 3, ticketTopicsCount: 1 },
52
+ ]
53
+
54
+ const departmentItems: DashboardDepartmentItem[] = [
55
+ { name: 'Suporte', openedTicketsCount: 2, waitingTime: 60, ticketTime: 600 },
56
+ ]
57
+
58
+ const topicItems: DashboardTopicItem[] = [
59
+ { name: 'Financeiro', openedTicketsCount: 1, waitingTimeAfterBot: 30, waitingTimeAvg: 45 },
60
+ ]
61
+
62
+ const serviceItems: DashboardServiceItem[] = [
63
+ { name: 'WhatsApp', receivedMessagesCount: 5, contactsCount: 4, ticketTopicsCount: 2 },
64
+ ]
65
+
66
+ const filters: DashboardQuery = {
67
+ startPeriod: '2026-09-01T00:00:00.000Z',
68
+ endPeriod: '2026-09-07T23:59:59.999Z',
69
+ status: 'closed',
70
+ departmentId: ['d1'],
71
+ }
72
+
73
+ const queryString = (query: DashboardQuery & DashboardWithTotals) =>
74
+ `?query=${encodeURIComponent(JSON.stringify(query))}`
75
+
76
+ // ── Tests ────────────────────────────────────────────────────────────
77
+
78
+ describe('DashboardApi', () => {
79
+ let client: ReturnType<typeof createMockClient>
80
+ let api: DashboardApi
81
+
82
+ beforeEach(() => {
83
+ client = createMockClient()
84
+ api = new DashboardApi(client)
85
+ })
86
+
87
+ it('has no CRUD routes', () => {
88
+ expect(api.basePath).toBe('/dashboard')
89
+ expect(api).not.toHaveProperty('getMany')
90
+ })
91
+
92
+ describe('getGeneral', () => {
93
+ it('calls client.get with /dashboard/general and no query string', async () => {
94
+ vi.mocked(client.get).mockResolvedValue(general)
95
+ const result = await api.getGeneral()
96
+ expect(client.get).toHaveBeenCalledWith('/dashboard/general', undefined)
97
+ expect(result).toEqual(general)
98
+ })
99
+
100
+ it('sends the filters in the query string', async () => {
101
+ vi.mocked(client.get).mockResolvedValue(general)
102
+ await api.getGeneral(filters)
103
+ expect(client.get).toHaveBeenCalledWith(
104
+ `/dashboard/general${queryString(filters)}`,
105
+ undefined,
106
+ )
107
+ })
108
+
109
+ it('forwards custom headers', async () => {
110
+ vi.mocked(client.get).mockResolvedValue(general)
111
+ const headers = { 'X-Custom': 'h' }
112
+ await api.getGeneral(undefined, headers)
113
+ expect(client.get).toHaveBeenCalledWith('/dashboard/general', headers)
114
+ })
115
+ })
116
+
117
+ describe('getByPeriod', () => {
118
+ it('calls client.get with /dashboard/by-period and no query string', async () => {
119
+ vi.mocked(client.get).mockResolvedValue(periodItems)
120
+ const result = await api.getByPeriod()
121
+ expect(client.get).toHaveBeenCalledWith('/dashboard/by-period', undefined)
122
+ expect(result).toEqual(periodItems)
123
+ })
124
+
125
+ it('sends the filters and the grouping in the query string', async () => {
126
+ vi.mocked(client.get).mockResolvedValue(periodItems)
127
+ const query: DashboardQuery = { ...filters, grouping: 'weekly' }
128
+ await api.getByPeriod(query)
129
+ expect(client.get).toHaveBeenCalledWith(
130
+ `/dashboard/by-period${queryString(query)}`,
131
+ undefined,
132
+ )
133
+ })
134
+
135
+ it('answers { totals, items } with withTotals: true', async () => {
136
+ const grouped = { totals: general, items: periodItems }
137
+ vi.mocked(client.get).mockResolvedValue(grouped)
138
+ const query = { ...filters, withTotals: true as const }
139
+ const result = await api.getByPeriod(query)
140
+ expect(client.get).toHaveBeenCalledWith(
141
+ `/dashboard/by-period${queryString(query)}`,
142
+ undefined,
143
+ )
144
+ expect(result).toEqual(grouped)
145
+ expect(result.totals.totalTicketsCount).toBe(5)
146
+ expect(result.items).toHaveLength(2)
147
+ })
148
+
149
+ it('does not send withTotals: false (the backend reads it as truthy in the qs format)', async () => {
150
+ vi.mocked(client.get).mockResolvedValue(periodItems)
151
+ await api.getByPeriod({ ...filters, withTotals: false })
152
+ expect(client.get).toHaveBeenCalledWith(
153
+ `/dashboard/by-period${queryString(filters)}`,
154
+ undefined,
155
+ )
156
+ await api.withQueryFormat('qs').getByPeriod({ withTotals: false, grouping: 'weekly' })
157
+ expect(client.get).toHaveBeenLastCalledWith('/dashboard/by-period?grouping=weekly', undefined)
158
+ await api.getByPeriod({ withTotals: false })
159
+ expect(client.get).toHaveBeenLastCalledWith('/dashboard/by-period', undefined)
160
+ })
161
+
162
+ it('forwards custom headers', async () => {
163
+ vi.mocked(client.get).mockResolvedValue(periodItems)
164
+ const headers = { 'X-Custom': 'h' }
165
+ await api.getByPeriod(undefined, headers)
166
+ expect(client.get).toHaveBeenCalledWith('/dashboard/by-period', headers)
167
+ })
168
+ })
169
+
170
+ describe('getByUser', () => {
171
+ it('calls client.get with /dashboard/by-user and the filters', async () => {
172
+ vi.mocked(client.get).mockResolvedValue(userItems)
173
+ const result = await api.getByUser(filters)
174
+ expect(client.get).toHaveBeenCalledWith(
175
+ `/dashboard/by-user${queryString(filters)}`,
176
+ undefined,
177
+ )
178
+ expect(result).toEqual(userItems)
179
+ })
180
+
181
+ it('answers { totals, items } with withTotals: true', async () => {
182
+ const grouped = { totals: general, items: userItems }
183
+ vi.mocked(client.get).mockResolvedValue(grouped)
184
+ const result = await api.getByUser({ withTotals: true })
185
+ expect(client.get).toHaveBeenCalledWith(
186
+ `/dashboard/by-user${queryString({ withTotals: true })}`,
187
+ undefined,
188
+ )
189
+ expect(result.items[0]?.name).toBe('Alice')
190
+ })
191
+
192
+ it('forwards custom headers', async () => {
193
+ vi.mocked(client.get).mockResolvedValue(userItems)
194
+ const headers = { 'X-Custom': 'h' }
195
+ await api.getByUser(undefined, headers)
196
+ expect(client.get).toHaveBeenCalledWith('/dashboard/by-user', headers)
197
+ })
198
+ })
199
+
200
+ describe('getByDepartment', () => {
201
+ it('calls client.get with /dashboard/by-department and the filters', async () => {
202
+ vi.mocked(client.get).mockResolvedValue(departmentItems)
203
+ const result = await api.getByDepartment(filters)
204
+ expect(client.get).toHaveBeenCalledWith(
205
+ `/dashboard/by-department${queryString(filters)}`,
206
+ undefined,
207
+ )
208
+ expect(result).toEqual(departmentItems)
209
+ })
210
+
211
+ it('answers { totals, items } with withTotals: true', async () => {
212
+ const grouped = { totals: general, items: departmentItems }
213
+ vi.mocked(client.get).mockResolvedValue(grouped)
214
+ const result = await api.getByDepartment({ withTotals: true })
215
+ expect(result).toEqual(grouped)
216
+ })
217
+
218
+ it('forwards custom headers', async () => {
219
+ vi.mocked(client.get).mockResolvedValue(departmentItems)
220
+ const headers = { 'X-Custom': 'h' }
221
+ await api.getByDepartment(undefined, headers)
222
+ expect(client.get).toHaveBeenCalledWith('/dashboard/by-department', headers)
223
+ })
224
+ })
225
+
226
+ describe('getByTopic', () => {
227
+ it('calls client.get with /dashboard/by-topic and the filters', async () => {
228
+ vi.mocked(client.get).mockResolvedValue(topicItems)
229
+ const result = await api.getByTopic(filters)
230
+ expect(client.get).toHaveBeenCalledWith(
231
+ `/dashboard/by-topic${queryString(filters)}`,
232
+ undefined,
233
+ )
234
+ expect(result).toEqual(topicItems)
235
+ })
236
+
237
+ it('forwards custom headers', async () => {
238
+ vi.mocked(client.get).mockResolvedValue(topicItems)
239
+ const headers = { 'X-Custom': 'h' }
240
+ await api.getByTopic(undefined, headers)
241
+ expect(client.get).toHaveBeenCalledWith('/dashboard/by-topic', headers)
242
+ })
243
+ })
244
+
245
+ describe('getByService', () => {
246
+ it('calls client.get with /dashboard/by-service and the filters', async () => {
247
+ vi.mocked(client.get).mockResolvedValue(serviceItems)
248
+ const result = await api.getByService(filters)
249
+ expect(client.get).toHaveBeenCalledWith(
250
+ `/dashboard/by-service${queryString(filters)}`,
251
+ undefined,
252
+ )
253
+ expect(result).toEqual(serviceItems)
254
+ })
255
+
256
+ it('forwards custom headers', async () => {
257
+ vi.mocked(client.get).mockResolvedValue(serviceItems)
258
+ const headers = { 'X-Custom': 'h' }
259
+ await api.getByService(undefined, headers)
260
+ expect(client.get).toHaveBeenCalledWith('/dashboard/by-service', headers)
261
+ })
262
+ })
263
+
264
+ describe('error propagation', () => {
265
+ it('propagates errors from the grouped routes', async () => {
266
+ vi.mocked(client.get).mockRejectedValue(new Error('Unauthorized'))
267
+ await expect(api.getByPeriod()).rejects.toThrow('Unauthorized')
268
+ })
269
+ })
270
+ })