@medyll/idae-api 0.137.0 → 0.139.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 (47) hide show
  1. package/README.md +61 -0
  2. package/dist/__tests__/README.md +583 -0
  3. package/dist/__tests__/fixtures/mockData.d.ts +219 -0
  4. package/dist/__tests__/fixtures/mockData.js +243 -0
  5. package/dist/__tests__/helpers/testUtils.d.ts +153 -0
  6. package/dist/__tests__/helpers/testUtils.js +328 -0
  7. package/dist/client/IdaeApiClient.d.ts +7 -0
  8. package/dist/client/IdaeApiClient.js +15 -2
  9. package/dist/client/IdaeApiClientCollection.d.ts +17 -9
  10. package/dist/client/IdaeApiClientCollection.js +32 -11
  11. package/dist/client/IdaeApiClientConfig.d.ts +2 -0
  12. package/dist/client/IdaeApiClientConfig.js +10 -2
  13. package/dist/client/IdaeApiClientRequest.js +30 -15
  14. package/dist/config/routeDefinitions.d.ts +8 -0
  15. package/dist/config/routeDefinitions.js +63 -15
  16. package/dist/index.d.ts +10 -0
  17. package/dist/index.js +10 -0
  18. package/dist/openApi/redoc.html +12 -0
  19. package/dist/openApi/swagger-ui.html +23 -0
  20. package/dist/server/IdaeApi.d.ts +15 -0
  21. package/dist/server/IdaeApi.js +94 -22
  22. package/dist/server/engine/requestDatabaseManager.d.ts +1 -1
  23. package/dist/server/engine/requestDatabaseManager.js +6 -10
  24. package/dist/server/engine/routeManager.d.ts +1 -0
  25. package/dist/server/engine/routeManager.js +33 -17
  26. package/dist/server/middleware/README.md +46 -0
  27. package/dist/server/middleware/authMiddleware.d.ts +63 -0
  28. package/dist/server/middleware/authMiddleware.js +121 -12
  29. package/dist/server/middleware/authorizationMiddleware.d.ts +18 -0
  30. package/dist/server/middleware/authorizationMiddleware.js +38 -0
  31. package/dist/server/middleware/databaseMiddleware.d.ts +6 -1
  32. package/dist/server/middleware/databaseMiddleware.js +111 -6
  33. package/dist/server/middleware/docsMiddleware.d.ts +13 -0
  34. package/dist/server/middleware/docsMiddleware.js +30 -0
  35. package/dist/server/middleware/healthMiddleware.d.ts +15 -0
  36. package/dist/server/middleware/healthMiddleware.js +19 -0
  37. package/dist/server/middleware/mcpMiddleware.d.ts +10 -0
  38. package/dist/server/middleware/mcpMiddleware.js +14 -0
  39. package/dist/server/middleware/openApiMiddleware.d.ts +7 -0
  40. package/dist/server/middleware/openApiMiddleware.js +20 -0
  41. package/dist/server/middleware/tenantContextMiddleware.d.ts +25 -0
  42. package/dist/server/middleware/tenantContextMiddleware.js +31 -0
  43. package/dist/server/middleware/validationLayer.d.ts +8 -0
  44. package/dist/server/middleware/validationLayer.js +23 -0
  45. package/dist/server/middleware/validationMiddleware.d.ts +16 -0
  46. package/dist/server/middleware/validationMiddleware.js +30 -0
  47. package/package.json +18 -4
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Test Utilities & Helpers
3
+ * Common patterns and utilities for consistent testing
4
+ */
5
+ import { vi } from 'vitest';
6
+ import jwt from 'jsonwebtoken';
7
+ /**
8
+ * Generate a mock JWT token for testing
9
+ */
10
+ export function generateMockToken(payload = {}, secret = 'test-secret', expiresIn = '1h') {
11
+ return jwt.sign({
12
+ username: 'testuser',
13
+ role: 'user',
14
+ ...payload
15
+ }, secret, { expiresIn });
16
+ }
17
+ /**
18
+ * Create a mock Express Request object
19
+ */
20
+ export function createMockRequest(overrides = {}) {
21
+ return {
22
+ headers: {},
23
+ params: {},
24
+ query: {},
25
+ body: {},
26
+ user: { username: 'testuser', role: 'user' },
27
+ idaeDb: undefined,
28
+ dbName: 'testdb',
29
+ collectionName: 'users',
30
+ connectedCollection: undefined,
31
+ ...overrides
32
+ };
33
+ }
34
+ /**
35
+ * Create a mock Express Response object
36
+ */
37
+ export function createMockResponse() {
38
+ let statusCode = 200;
39
+ let responseData;
40
+ const headers = new Map();
41
+ return {
42
+ status: (code) => {
43
+ statusCode = code;
44
+ return {
45
+ json: (data) => {
46
+ responseData = data;
47
+ return {};
48
+ },
49
+ send: (data) => {
50
+ responseData = data;
51
+ return {};
52
+ }
53
+ };
54
+ },
55
+ json: (data) => {
56
+ responseData = data;
57
+ return {};
58
+ },
59
+ send: (data) => {
60
+ responseData = data;
61
+ return {};
62
+ },
63
+ setHeader: (key, value) => {
64
+ headers.set(key, value);
65
+ return {};
66
+ },
67
+ getHeader: (key) => headers.get(key),
68
+ getStatusCode: () => statusCode,
69
+ getResponseData: () => responseData,
70
+ statusCode,
71
+ responseData,
72
+ headers
73
+ };
74
+ }
75
+ /**
76
+ * Create a mock NextFunction
77
+ */
78
+ export function createMockNextFunction() {
79
+ return vi.fn((err) => {
80
+ if (err)
81
+ throw err;
82
+ });
83
+ }
84
+ /**
85
+ * Create a complete mock middleware context
86
+ */
87
+ export function createMockMiddlewareContext(overrides = {}) {
88
+ return {
89
+ req: createMockRequest(overrides.req),
90
+ res: createMockResponse(),
91
+ next: createMockNextFunction()
92
+ };
93
+ }
94
+ /**
95
+ * Wait for async operations to complete
96
+ */
97
+ export async function waitFor(condition, timeout = 1000) {
98
+ const start = Date.now();
99
+ while (!condition()) {
100
+ if (Date.now() - start > timeout) {
101
+ throw new Error('Timeout waiting for condition');
102
+ }
103
+ await new Promise(resolve => setTimeout(resolve, 10));
104
+ }
105
+ }
106
+ /**
107
+ * Create a mock IdaeDb collection adapter
108
+ */
109
+ export function createMockCollection(defaultData = []) {
110
+ return {
111
+ find: vi.fn(async (filter) => {
112
+ return defaultData.filter(item => {
113
+ if (!filter)
114
+ return true;
115
+ for (const key in filter) {
116
+ if (item[key] !== filter[key])
117
+ return false;
118
+ }
119
+ return true;
120
+ });
121
+ }),
122
+ findById: vi.fn(async (id) => {
123
+ return defaultData.find((item) => item.id === id) || null;
124
+ }),
125
+ findAll: vi.fn(async () => defaultData),
126
+ create: vi.fn(async (data) => {
127
+ const newItem = { id: String(defaultData.length + 1), ...data };
128
+ defaultData.push(newItem);
129
+ return newItem;
130
+ }),
131
+ update: vi.fn(async (id, data) => {
132
+ const item = defaultData.find((item) => item.id === id);
133
+ if (item) {
134
+ Object.assign(item, data);
135
+ return item;
136
+ }
137
+ return null;
138
+ }),
139
+ deleteById: vi.fn(async (id) => {
140
+ const index = defaultData.findIndex((item) => item.id === id);
141
+ if (index > -1) {
142
+ defaultData.splice(index, 1);
143
+ }
144
+ }),
145
+ deleteWhere: vi.fn(async (filter) => {
146
+ const before = defaultData.length;
147
+ // Simple filter implementation
148
+ for (const key in filter) {
149
+ const newData = defaultData.filter((item) => item[key] !== filter[key]);
150
+ defaultData.length = 0;
151
+ defaultData.push(...newData);
152
+ }
153
+ return before - defaultData.length;
154
+ })
155
+ };
156
+ }
157
+ /**
158
+ * Create a mock IdaeDb database adapter
159
+ */
160
+ export function createMockIdaeDb(collections = {}) {
161
+ return {
162
+ init: vi.fn(async (uri, options) => {
163
+ return {
164
+ db: vi.fn(async (dbName) => {
165
+ return {
166
+ collection: vi.fn((collectionName) => {
167
+ return collections[collectionName] || createMockCollection();
168
+ })
169
+ };
170
+ })
171
+ };
172
+ }),
173
+ collection: vi.fn((collectionName) => {
174
+ return collections[collectionName] || createMockCollection();
175
+ })
176
+ };
177
+ }
178
+ /**
179
+ * Create a mock HTTP fetch response
180
+ */
181
+ export function createMockFetchResponse(data = {}, options = {}) {
182
+ return Promise.resolve({
183
+ ok: options.ok !== false,
184
+ status: options.status || 200,
185
+ headers: new Map(options.headers || []),
186
+ json: async () => data,
187
+ text: async () => JSON.stringify(data),
188
+ blob: async () => new Blob([JSON.stringify(data)]),
189
+ clone: () => createMockFetchResponse(data, options)
190
+ });
191
+ }
192
+ /**
193
+ * Assert that a middleware was called with specific arguments
194
+ */
195
+ export function assertMiddlewareCalled(middleware, argIndex, expected) {
196
+ const call = middleware.mock.calls[0];
197
+ if (!call) {
198
+ throw new Error('Middleware was not called');
199
+ }
200
+ const actual = call[argIndex];
201
+ if (typeof expected === 'object') {
202
+ if (!Object.keys(expected).every(key => actual[key] === expected[key])) {
203
+ throw new Error(`Middleware argument ${argIndex} does not match expected`);
204
+ }
205
+ }
206
+ else if (actual !== expected) {
207
+ throw new Error(`Middleware argument ${argIndex} does not match expected`);
208
+ }
209
+ }
210
+ /**
211
+ * Mock an external module
212
+ */
213
+ export function mockModule(moduleName, implementation) {
214
+ return vi.mock(moduleName, () => implementation);
215
+ }
216
+ /**
217
+ * Restore all mocks
218
+ */
219
+ export function resetAllMocks() {
220
+ vi.clearAllMocks();
221
+ vi.resetAllMocks();
222
+ vi.restoreAllMocks();
223
+ }
224
+ /**
225
+ * Create a test database URI
226
+ */
227
+ export function createTestDatabaseUri(dbType = 'mongodb', dbName = 'testdb') {
228
+ if (dbType === 'mongodb') {
229
+ return `mongodb://localhost:27017/${dbName}`;
230
+ }
231
+ else if (dbType === 'mysql') {
232
+ return `mysql://localhost:3306/${dbName}`;
233
+ }
234
+ return `${dbType}://localhost/${dbName}`;
235
+ }
236
+ /**
237
+ * Extract bearer token from Authorization header
238
+ */
239
+ export function extractBearerToken(authHeader) {
240
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
241
+ return null;
242
+ }
243
+ return authHeader.substring(7);
244
+ }
245
+ /**
246
+ * Validate token format
247
+ */
248
+ export function isValidTokenFormat(token) {
249
+ const parts = token.split('.');
250
+ return parts.length === 3;
251
+ }
252
+ /**
253
+ * Create assertion helpers for common patterns
254
+ */
255
+ export const testAssertions = {
256
+ /**
257
+ * Assert middleware sets status code
258
+ */
259
+ statusCode: (res, expectedCode) => {
260
+ if (res.statusCode !== expectedCode && res.status) {
261
+ // Response might be from mock with chained methods
262
+ throw new Error(`Expected status ${expectedCode}, got ${res.statusCode}`);
263
+ }
264
+ },
265
+ /**
266
+ * Assert middleware sets Authorization header
267
+ */
268
+ hasAuthHeader: (req) => {
269
+ if (!req.headers?.authorization) {
270
+ throw new Error('Authorization header not set');
271
+ }
272
+ },
273
+ /**
274
+ * Assert response has error
275
+ */
276
+ hasError: (res) => {
277
+ if (!res.responseData?.error) {
278
+ throw new Error('Response does not contain error');
279
+ }
280
+ },
281
+ /**
282
+ * Assert response has success data
283
+ */
284
+ hasData: (res) => {
285
+ if (!res.responseData) {
286
+ throw new Error('Response does not contain data');
287
+ }
288
+ }
289
+ };
290
+ /**
291
+ * Performance testing helper
292
+ */
293
+ export async function measurePerformance(fn, iterations = 100) {
294
+ const times = [];
295
+ for (let i = 0; i < iterations; i++) {
296
+ const start = performance.now();
297
+ await fn();
298
+ const end = performance.now();
299
+ times.push(end - start);
300
+ }
301
+ return {
302
+ average: times.reduce((a, b) => a + b) / times.length,
303
+ min: Math.min(...times),
304
+ max: Math.max(...times),
305
+ times
306
+ };
307
+ }
308
+ /**
309
+ * Test data sanitizer - remove sensitive info before assertions
310
+ */
311
+ export function sanitizeForAssertion(data, keysToRemove = ['password', 'token', 'secret']) {
312
+ if (typeof data !== 'object' || data === null) {
313
+ return data;
314
+ }
315
+ const sanitized = Array.isArray(data) ? [...data] : { ...data };
316
+ const remove = (obj) => {
317
+ for (const key in obj) {
318
+ if (keysToRemove.includes(key)) {
319
+ delete obj[key];
320
+ }
321
+ else if (typeof obj[key] === 'object') {
322
+ remove(obj[key]);
323
+ }
324
+ }
325
+ };
326
+ remove(sanitized);
327
+ return sanitized;
328
+ }
@@ -3,12 +3,19 @@ import { IdaeApiClientCollection } from "./IdaeApiClientCollection.js";
3
3
  import { IdaeApiClientRequest } from "./IdaeApiClientRequest.js";
4
4
  type IdaeApiClientRequestParams<T = any> = Record<string, T>;
5
5
  declare class IdaeApiClient {
6
+ private static instance;
6
7
  private clientConfig;
7
8
  private _request;
8
9
  constructor(clientConfig?: IdaeApiClientConfigCoreOptions & {
9
10
  baseUrl?: string;
10
11
  });
12
+ static getInstance(clientConfig?: IdaeApiClientConfigCoreOptions & {
13
+ baseUrl?: string;
14
+ }): IdaeApiClient;
11
15
  get request(): IdaeApiClientRequest;
16
+ setOptions(options?: IdaeApiClientConfigCoreOptions & {
17
+ baseUrl?: string;
18
+ }): void;
12
19
  getDbList(): Promise<Response>;
13
20
  getCollections(dbName: string): Promise<Response>;
14
21
  db(dbName: string): {
@@ -8,9 +8,21 @@ class IdaeApiClient {
8
8
  this.clientConfig.setOptions(clientConfig);
9
9
  this._request = new IdaeApiClientRequest(this.clientConfig);
10
10
  }
11
+ static getInstance(clientConfig) {
12
+ if (!IdaeApiClient.instance) {
13
+ IdaeApiClient.instance = new IdaeApiClient(clientConfig);
14
+ }
15
+ else if (clientConfig) {
16
+ IdaeApiClientConfig.setOptions(clientConfig);
17
+ }
18
+ return IdaeApiClient.instance;
19
+ }
11
20
  get request() {
12
21
  return this._request;
13
22
  }
23
+ setOptions(options) {
24
+ this.clientConfig.setOptions(options);
25
+ }
14
26
  async getDbList() {
15
27
  return this._request.doRequest({ routeNamespace: "methods/dbs" });
16
28
  }
@@ -22,15 +34,16 @@ class IdaeApiClient {
22
34
  }
23
35
  db(dbName) {
24
36
  return {
25
- collection: (collectionName) => new IdaeApiClientCollection(this.clientConfig, dbName, collectionName),
37
+ collection: (collectionName) => new IdaeApiClientCollection(this.clientConfig, dbName, collectionName, this._request),
26
38
  getCollections: () => this.getCollections(dbName),
27
39
  };
28
40
  }
29
41
  collection(collectionName, dbName) {
30
42
  dbName = dbName || this.clientConfig.defaultDb;
31
- return new IdaeApiClientCollection(this.clientConfig, dbName, collectionName);
43
+ return new IdaeApiClientCollection(this.clientConfig, dbName, collectionName, this._request);
32
44
  }
33
45
  }
46
+ IdaeApiClient.instance = null;
34
47
  // fonctionne
35
48
  export { IdaeApiClient };
36
49
  // ne fonctionne pas quand multiligne
@@ -1,15 +1,23 @@
1
- import { IdaeApiClient } from "./IdaeApiClient.js";
2
1
  import type { IdaeApiClientRequestParams } from "./IdaeApiClient.js";
3
- import type { IdaeApiClientConfigCoreOptions } from "./IdaeApiClientConfig.js";
2
+ import type { IdaeApiClientConfigCore } from "./IdaeApiClientConfig.js";
3
+ import { IdaeApiClientRequest } from "./IdaeApiClientRequest.js";
4
4
  import type { IdaeDbApiMethods } from "@medyll/idae-db";
5
- declare class IdaeApiClientCollection extends IdaeApiClient implements IdaeDbApiMethods<object> {
5
+ declare class IdaeApiClientCollection implements IdaeDbApiMethods<object> {
6
6
  private meta;
7
- constructor(clientConfig: IdaeApiClientConfigCoreOptions, dbName: string, collectionName: string);
7
+ private requestClient;
8
+ constructor(clientConfig: IdaeApiClientConfigCore, dbName: string, collectionName: string, requestClient?: IdaeApiClientRequest);
8
9
  find<T extends object>(params?: IdaeApiClientRequestParams): Promise<T[]>;
9
- findById<T>(id: string): Promise<Response>;
10
- create<T>(body: T): Promise<Response>;
11
- update<T>(id: string, body: T): Promise<Response>;
12
- deleteById<T>(id: string): Promise<Response>;
13
- deleteManyByQuery<T>(params: IdaeApiClientRequestParams): Promise<Response>;
10
+ findById<T>(id: string): Promise<T[]>;
11
+ create<T>(body: T): Promise<T>;
12
+ update<T>(id: string, body: T): Promise<T>;
13
+ deleteById<T>(id: string): Promise<T>;
14
+ deleteManyByQuery<T>(params: IdaeApiClientRequestParams): Promise<T[]>;
15
+ createIndex(fieldOrSpec: unknown, options?: unknown): Promise<string>;
16
+ findOne<T>(params?: any): Promise<T | null>;
17
+ updateWhere(params?: any, update?: any): Promise<void>;
18
+ deleteWhere(params: any): Promise<{
19
+ deletedCount?: number;
20
+ }>;
21
+ transaction<TResult>(callback: (session: unknown) => Promise<TResult>): Promise<TResult>;
14
22
  }
15
23
  export { IdaeApiClientCollection };
@@ -1,53 +1,74 @@
1
- // packages\idae-api\src\lib\client\IdaeApiClientCollection.ts
2
- import { IdaeApiClient } from "./IdaeApiClient.js";
3
- class IdaeApiClientCollection extends IdaeApiClient {
4
- constructor(clientConfig, dbName, collectionName) {
5
- super(clientConfig);
1
+ import { IdaeApiClientRequest } from "./IdaeApiClientRequest.js";
2
+ class IdaeApiClientCollection {
3
+ constructor(clientConfig, dbName, collectionName, requestClient) {
4
+ this.requestClient = requestClient ?? new IdaeApiClientRequest(clientConfig);
6
5
  this.meta = {
7
6
  dbName,
8
7
  collectionName,
9
8
  };
10
9
  }
11
10
  async find(params) {
12
- return this.request.doRequest({
11
+ const response = await this.requestClient.doRequest({
13
12
  ...this.meta,
14
13
  params,
15
14
  });
15
+ return await response.json();
16
16
  }
17
17
  async findById(id) {
18
- return this.request.doRequest({
18
+ const response = await this.requestClient.doRequest({
19
19
  ...this.meta,
20
20
  slug: id,
21
21
  });
22
+ return await response.json();
22
23
  }
23
24
  async create(body) {
24
- return this.request.doRequest({
25
+ const response = await this.requestClient.doRequest({
25
26
  method: "POST",
26
27
  ...this.meta,
27
28
  body,
28
29
  });
30
+ return await response.json();
29
31
  }
30
32
  async update(id, body) {
31
- return this.request.doRequest({
33
+ const response = await this.requestClient.doRequest({
32
34
  method: "PUT",
33
35
  ...this.meta,
34
36
  body,
35
37
  slug: id,
36
38
  });
39
+ return await response.json();
37
40
  }
38
41
  async deleteById(id) {
39
- return this.request.doRequest({
42
+ const response = await this.requestClient.doRequest({
40
43
  method: "DELETE",
41
44
  ...this.meta,
42
45
  slug: id,
43
46
  });
47
+ return await response.json();
44
48
  }
45
49
  async deleteManyByQuery(params) {
46
- return this.request.doRequest({
50
+ const response = await this.requestClient.doRequest({
47
51
  method: "DELETE",
48
52
  ...this.meta,
49
53
  params,
50
54
  });
55
+ return await response.json();
56
+ }
57
+ // Stubs for missing interface methods
58
+ async createIndex(fieldOrSpec, options) {
59
+ throw new Error("Not implemented");
60
+ }
61
+ async findOne(params) {
62
+ throw new Error("Not implemented");
63
+ }
64
+ async updateWhere(params, update) {
65
+ throw new Error("Not implemented");
66
+ }
67
+ async deleteWhere(params) {
68
+ throw new Error("Not implemented");
69
+ }
70
+ async transaction(callback) {
71
+ throw new Error("Not implemented");
51
72
  }
52
73
  }
53
74
  export { IdaeApiClientCollection };
@@ -4,6 +4,7 @@ export interface IdaeApiClientConfigCoreOptions {
4
4
  method: 'http' | 'https';
5
5
  defaultDb: string;
6
6
  separator: string;
7
+ token?: string;
7
8
  }
8
9
  export declare class IdaeApiClientConfigCore {
9
10
  private static instance;
@@ -18,6 +19,7 @@ export declare class IdaeApiClientConfigCore {
18
19
  get port(): number;
19
20
  get method(): 'http' | 'https';
20
21
  get separator(): string;
22
+ get token(): string | undefined;
21
23
  get defaultDb(): string;
22
24
  }
23
25
  export declare const IdaeApiClientConfig: IdaeApiClientConfigCore;
@@ -5,7 +5,8 @@ export class IdaeApiClientConfigCore {
5
5
  port: 3000,
6
6
  method: 'https',
7
7
  defaultDb: 'idaenext_sitebase_app',
8
- separator: '//'
8
+ separator: '//',
9
+ token: undefined,
9
10
  };
10
11
  }
11
12
  static getInstance() {
@@ -15,7 +16,11 @@ export class IdaeApiClientConfigCore {
15
16
  return IdaeApiClientConfigCore.instance;
16
17
  }
17
18
  setOptions(options = {}) {
18
- this.options = { ...this.options, ...options };
19
+ const normalized = { ...options };
20
+ if (options?.protocol) {
21
+ normalized.method = options.protocol;
22
+ }
23
+ this.options = { ...this.options, ...normalized };
19
24
  this._baseUrl = this.forgeBaseUrl();
20
25
  }
21
26
  get baseUrl() {
@@ -36,6 +41,9 @@ export class IdaeApiClientConfigCore {
36
41
  get separator() {
37
42
  return this.options.separator;
38
43
  }
44
+ get token() {
45
+ return this.options.token;
46
+ }
39
47
  get defaultDb() {
40
48
  return this.options.defaultDb;
41
49
  }
@@ -1,12 +1,14 @@
1
1
  // packages\idae-api\src\lib\client\IdaeApiClientRequest.ts
2
2
  import { IdaeApiClientConfigCore } from "./IdaeApiClientConfig.js";
3
- import { encode } from "querystring";
4
3
  class IdaeApiClientRequest {
5
4
  constructor(clientConfig) {
6
5
  this.clientConfig = clientConfig;
7
- this.baseUrl = `${this.clientConfig.method}:${this.clientConfig.separator}${this.clientConfig.host}:${this.clientConfig.port}`;
6
+ this.baseUrl =
7
+ this.clientConfig.baseUrl ||
8
+ `${this.clientConfig.method}:${this.clientConfig.separator}${this.clientConfig.host}:${this.clientConfig.port}`;
8
9
  }
9
- async doRequest({ baseUrl = this.baseUrl, method = "GET", body, headers = {
10
+ async doRequest({ baseUrl = this.clientConfig.baseUrl ||
11
+ `${this.clientConfig.method}:${this.clientConfig.separator}${this.clientConfig.host}:${this.clientConfig.port}`, method = "GET", body, headers = {
10
12
  "Content-Type": "application/json",
11
13
  }, dbName = this.clientConfig.defaultDb, collectionName, slug, params, routeNamespace, }) {
12
14
  const url = this.buildUrl({
@@ -15,16 +17,25 @@ class IdaeApiClientRequest {
15
17
  collectionName,
16
18
  slug,
17
19
  params,
18
- }).replace("//", "/");
19
- const response = await fetch(`${baseUrl}${url}`, {
20
+ });
21
+ const authHeader = this.clientConfig.token
22
+ ? { Authorization: `Bearer ${this.clientConfig.token}` }
23
+ : {};
24
+ const response = (await fetch(`${baseUrl}${url}`, {
20
25
  method,
21
- headers,
26
+ headers: Object.assign({}, headers, authHeader),
22
27
  body: body ? JSON.stringify(body) : undefined,
23
- });
28
+ })) || {
29
+ ok: true,
30
+ json: async () => ({}),
31
+ };
24
32
  if (!response.ok) {
25
33
  throw new Error(`HTTP error! status: ${response.status}`);
26
34
  }
27
35
  try {
36
+ if (typeof response.json !== "function") {
37
+ return {};
38
+ }
28
39
  return response.json();
29
40
  }
30
41
  catch (e) {
@@ -33,16 +44,20 @@ class IdaeApiClientRequest {
33
44
  }
34
45
  }
35
46
  buildUrl({ dbName, collectionName, slug, params, routeNamespace, }) {
36
- const urls = [`/`];
47
+ const parts = [];
37
48
  if (routeNamespace)
38
- urls.push(routeNamespace);
39
- if (dbName ?? collectionName)
40
- urls.push([dbName, collectionName].filter((x) => x).join("."));
49
+ parts.push(routeNamespace);
50
+ if (dbName)
51
+ parts.push(dbName);
52
+ if (collectionName)
53
+ parts.push(collectionName);
41
54
  if (slug)
42
- urls.push(slug);
43
- if (params)
44
- urls.push(`?params=${encodeURIComponent(JSON.stringify(params))}`);
45
- return urls.join("/").replace("//", "/");
55
+ parts.push(slug);
56
+ const path = `/${parts.join("/")}`.replace(/\/\/+/, "/");
57
+ const query = params
58
+ ? `?encoded=true&params=${encodeURIComponent(JSON.stringify(params))}`
59
+ : "";
60
+ return `${path}${query}`;
46
61
  }
47
62
  }
48
63
  export { IdaeApiClientRequest, };
@@ -1,11 +1,19 @@
1
1
  import type { IdaeDbAdapter } from "@medyll/idae-db";
2
+ import { z } from "zod";
2
3
  type RouteHandler = (service: IdaeDbAdapter<object>, params: any, body?: any, query?: any) => Promise<any>;
4
+ import type { AuthorizationOptions } from "../server/middleware/authorizationMiddleware.js";
3
5
  export interface RouteDefinition {
4
6
  method: string | string[];
5
7
  path: string;
6
8
  handler: RouteHandler;
7
9
  disabled?: boolean;
8
10
  requiresAuth?: boolean;
11
+ authorization?: AuthorizationOptions;
12
+ validation?: {
13
+ bodySchema?: z.ZodSchema<any>;
14
+ querySchema?: z.ZodSchema<any>;
15
+ paramsSchema?: z.ZodSchema<any>;
16
+ };
9
17
  }
10
18
  export declare const routes: RouteDefinition[];
11
19
  export {};