@internetderdinge/api 1.224.2 → 1.229.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/dist/src/accounts/accounts.controller.js +89 -0
  2. package/dist/src/accounts/accounts.route.js +101 -0
  3. package/dist/src/accounts/accounts.schemas.js +12 -0
  4. package/dist/src/accounts/accounts.service.js +65 -0
  5. package/dist/src/accounts/accounts.validation.js +99 -0
  6. package/dist/src/accounts/auth0.service.js +188 -0
  7. package/dist/src/config/config.js +48 -0
  8. package/dist/src/config/logger.js +27 -0
  9. package/dist/src/config/morgan.js +16 -0
  10. package/dist/src/config/passport.cjs +28 -0
  11. package/dist/src/config/roles.js +11 -0
  12. package/dist/src/config/tokens.cjs +10 -0
  13. package/dist/src/devices/devices.controller.js +172 -0
  14. package/dist/src/devices/devices.model.js +94 -0
  15. package/dist/src/devices/devices.route.js +153 -0
  16. package/dist/src/devices/devices.schemas.js +84 -0
  17. package/dist/src/devices/devices.service.js +198 -0
  18. package/dist/src/devices/devices.types.js +1 -0
  19. package/dist/src/devices/devices.validation.js +257 -0
  20. package/dist/src/devicesNotifications/devicesNotifications.controller.js +69 -0
  21. package/dist/src/devicesNotifications/devicesNotifications.model.js +39 -0
  22. package/dist/src/devicesNotifications/devicesNotifications.route.js +124 -0
  23. package/dist/src/devicesNotifications/devicesNotifications.schemas.js +10 -0
  24. package/dist/src/devicesNotifications/devicesNotifications.service.js +181 -0
  25. package/dist/src/devicesNotifications/devicesNotifications.validation.js +46 -0
  26. package/dist/src/email/email.service.js +580 -0
  27. package/dist/src/files/upload.service.js +124 -0
  28. package/dist/src/i18n/i18n.js +38 -0
  29. package/dist/src/i18n/saveMissingLocalJsonBackend.js +53 -0
  30. package/dist/src/i18n/types.js +1 -0
  31. package/dist/src/index.js +48 -0
  32. package/dist/src/iotdevice/iotdevice.controller.js +96 -0
  33. package/dist/src/iotdevice/iotdevice.model.js +17 -0
  34. package/dist/src/iotdevice/iotdevice.route.js +143 -0
  35. package/dist/src/iotdevice/iotdevice.schemas.js +60 -0
  36. package/dist/src/iotdevice/iotdevice.service.js +579 -0
  37. package/dist/src/iotdevice/iotdevice.types.js +1 -0
  38. package/dist/src/iotdevice/iotdevice.validation.js +54 -0
  39. package/dist/src/middlewares/auth.js +75 -0
  40. package/dist/src/middlewares/checkJwt.cjs +17 -0
  41. package/dist/src/middlewares/error.js +36 -0
  42. package/dist/src/middlewares/mongooseValidations/ensureSameOrganization.js +13 -0
  43. package/dist/src/middlewares/rateLimiter.js +7 -0
  44. package/dist/src/middlewares/validate.js +18 -0
  45. package/dist/src/middlewares/validateAction.js +35 -0
  46. package/dist/src/middlewares/validateAdmin.js +18 -0
  47. package/dist/src/middlewares/validateAi.js +16 -0
  48. package/dist/src/middlewares/validateCurrentAuthUser.js +17 -0
  49. package/dist/src/middlewares/validateCurrentUser.js +20 -0
  50. package/dist/src/middlewares/validateDevice.js +98 -0
  51. package/dist/src/middlewares/validateDeviceUserOrganization.js +26 -0
  52. package/dist/src/middlewares/validateOrganization.js +63 -0
  53. package/dist/src/middlewares/validateQuerySearchUserAndOrganization.js +44 -0
  54. package/dist/src/middlewares/validateTokens.js +23 -0
  55. package/dist/src/middlewares/validateUser.js +38 -0
  56. package/dist/src/middlewares/validateZod.js +33 -0
  57. package/dist/src/models/plugins/index.js +4 -0
  58. package/dist/src/models/plugins/paginate.plugin.js +117 -0
  59. package/dist/src/models/plugins/paginateNew.plugin.js +185 -0
  60. package/dist/src/models/plugins/simplePopulate.js +16 -0
  61. package/dist/src/models/plugins/toJSON.plugin.js +35 -0
  62. package/dist/src/organizations/organizations.controller.js +64 -0
  63. package/dist/src/organizations/organizations.model.js +41 -0
  64. package/dist/src/organizations/organizations.route.js +98 -0
  65. package/dist/src/organizations/organizations.schemas.js +7 -0
  66. package/dist/src/organizations/organizations.service.js +59 -0
  67. package/dist/src/organizations/organizations.validation.js +62 -0
  68. package/dist/src/pdf/pdf.controller.js +24 -0
  69. package/dist/src/pdf/pdf.route.js +22 -0
  70. package/dist/src/pdf/pdf.schemas.js +6 -0
  71. package/dist/src/pdf/pdf.service.js +65 -0
  72. package/dist/src/pdf/pdf.validation.js +27 -0
  73. package/dist/src/tokens/tokens.controller.js +60 -0
  74. package/dist/src/tokens/tokens.model.js +18 -0
  75. package/dist/src/tokens/tokens.route.js +52 -0
  76. package/dist/src/tokens/tokens.schemas.js +14 -0
  77. package/dist/src/tokens/tokens.service.js +30 -0
  78. package/dist/src/tokens/tokens.validation.js +9 -0
  79. package/dist/src/types/routeSpec.js +1 -0
  80. package/dist/src/users/users.controller.js +147 -0
  81. package/dist/src/users/users.model.js +50 -0
  82. package/dist/src/users/users.route.js +137 -0
  83. package/dist/src/users/users.schemas.js +69 -0
  84. package/dist/src/users/users.service.js +295 -0
  85. package/dist/src/users/users.types.js +1 -0
  86. package/dist/src/users/users.validation.js +144 -0
  87. package/dist/src/utils/ApiError.js +16 -0
  88. package/dist/src/utils/buildRouterAndDocs.js +72 -0
  89. package/dist/src/utils/catchAsync.js +4 -0
  90. package/dist/src/utils/comparePapers.service.js +32 -0
  91. package/dist/src/utils/deviceUtils.js +63 -0
  92. package/dist/src/utils/filterOptions.js +24 -0
  93. package/dist/src/utils/medicationName.js +10 -0
  94. package/dist/src/utils/pick.js +16 -0
  95. package/dist/src/utils/registerOpenApi.js +28 -0
  96. package/dist/src/utils/urlUtils.js +15 -0
  97. package/dist/src/utils/userName.js +22 -0
  98. package/dist/src/utils/zValidations.js +124 -0
  99. package/dist/src/validations/auth.validation.cjs +53 -0
  100. package/dist/src/validations/custom.validation.js +19 -0
  101. package/dist/src/validations/index.cjs +3 -0
  102. package/package.json +15 -6
  103. package/scripts/release-and-sync-paperless.mjs +135 -0
  104. package/scripts/release-version.mjs +145 -0
  105. package/src/accounts/accounts.controller.ts +1 -0
  106. package/src/accounts/accounts.service.ts +1 -0
  107. package/src/accounts/accounts.validation.ts +6 -3
  108. package/src/accounts/auth0.service.ts +55 -28
  109. package/src/config/config.ts +6 -0
  110. package/src/config/logger.ts +15 -9
  111. package/src/devices/devices.controller.ts +7 -1
  112. package/src/devices/devices.model.ts +4 -1
  113. package/src/devices/devices.schemas.ts +10 -8
  114. package/src/devices/devices.service.ts +2 -1
  115. package/src/devices/devices.types.ts +1 -0
  116. package/src/devices/devices.validation.ts +85 -23
  117. package/src/devicesNotifications/devicesNotifications.controller.ts +57 -28
  118. package/src/devicesNotifications/devicesNotifications.model.ts +20 -12
  119. package/src/devicesNotifications/devicesNotifications.service.ts +35 -17
  120. package/src/files/upload.service.ts +52 -28
  121. package/src/i18n/i18n.ts +2 -2
  122. package/src/i18n/types.ts +1 -0
  123. package/src/index.ts +47 -0
  124. package/src/iotdevice/iotdevice.controller.ts +1 -0
  125. package/src/iotdevice/iotdevice.model.ts +6 -3
  126. package/src/iotdevice/iotdevice.route.ts +85 -76
  127. package/src/iotdevice/iotdevice.service.ts +5 -4
  128. package/src/iotdevice/iotdevice.types.ts +6 -0
  129. package/src/middlewares/auth.ts +2 -8
  130. package/src/middlewares/error.ts +26 -12
  131. package/src/middlewares/mongooseValidations/ensureSameOrganization.ts +4 -3
  132. package/src/middlewares/validateAi.ts +17 -9
  133. package/src/middlewares/validateDevice.ts +1 -0
  134. package/src/middlewares/validateDeviceUserOrganization.ts +1 -0
  135. package/src/middlewares/validateOrganization.ts +1 -1
  136. package/src/middlewares/validateQuerySearchUserAndOrganization.ts +1 -0
  137. package/src/middlewares/validateTokens.ts +2 -1
  138. package/src/middlewares/validateUser.ts +1 -0
  139. package/src/models/plugins/index.ts +5 -4
  140. package/src/models/plugins/paginate.plugin.ts +26 -16
  141. package/src/models/plugins/paginateNew.plugin.ts +33 -21
  142. package/src/models/plugins/simplePopulate.ts +8 -3
  143. package/src/models/plugins/toJSON.plugin.ts +12 -5
  144. package/src/organizations/organizations.controller.ts +1 -2
  145. package/src/organizations/organizations.model.ts +4 -4
  146. package/src/organizations/organizations.route.ts +1 -1
  147. package/src/organizations/organizations.service.ts +15 -6
  148. package/src/pdf/pdf.controller.ts +18 -1
  149. package/src/pdf/pdf.service.ts +25 -16
  150. package/src/tokens/tokens.controller.ts +6 -8
  151. package/src/tokens/tokens.model.ts +3 -1
  152. package/src/tokens/tokens.service.ts +3 -2
  153. package/src/types/express.d.ts +17 -0
  154. package/src/types/mongoose.d.ts +22 -0
  155. package/src/users/users.controller.ts +8 -9
  156. package/src/users/users.model.ts +6 -5
  157. package/src/users/users.route.ts +0 -1
  158. package/src/users/users.service.ts +16 -0
  159. package/src/users/users.types.ts +1 -0
  160. package/src/users/users.validation.ts +6 -2
  161. package/src/utils/ApiError.ts +8 -1
  162. package/src/utils/buildRouterAndDocs.ts +56 -21
  163. package/src/utils/catchAsync.ts +27 -3
  164. package/src/utils/deviceUtils.ts +109 -0
  165. package/src/utils/medicationName.ts +5 -4
  166. package/src/utils/pick.ts +5 -1
  167. package/src/utils/userName.ts +1 -0
  168. package/src/utils/zValidations.ts +78 -26
  169. package/tsconfig.json +13 -4
@@ -1,8 +1,15 @@
1
+ // @ts-nocheck
1
2
  export class ApiError extends Error {
2
3
  statusCode: number;
3
4
  isOperational: boolean;
4
5
 
5
- constructor(statusCode: number, message: string, isOperational = true, stack = '', raw: any = null) {
6
+ constructor(
7
+ statusCode: number,
8
+ message: string,
9
+ isOperational = true,
10
+ stack = "",
11
+ raw: any = null,
12
+ ) {
6
13
  super(message);
7
14
  this.statusCode = statusCode;
8
15
  this.isOperational = isOperational;
@@ -1,28 +1,40 @@
1
- import { registry } from '../utils/registerOpenApi';
1
+ import type { RequestHandler, Router } from "express";
2
+ import { registry } from "../utils/registerOpenApi";
2
3
 
3
- import { validateZod } from '../middlewares/validateZod';
4
- import { bearerAuth, xApiKey } from '../utils/registerOpenApi';
4
+ import { validateZod } from "../middlewares/validateZod";
5
+ import { bearerAuth, xApiKey } from "../utils/registerOpenApi";
5
6
 
6
- import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';
7
- import { z } from 'zod';
7
+ import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
8
+ import { z } from "zod";
9
+ import type { ZodTypeAny } from "zod";
8
10
 
9
11
  extendZodWithOpenApi(z);
10
12
 
11
- const roleValidatorNames = ['validateAiRole', 'validateAdmin'];
13
+ const roleValidatorNames = ["validateAiRole", "validateAdmin"];
12
14
  function hasRoleValidation(validators: Function[] = []): boolean {
13
15
  return validators.some((fn) => roleValidatorNames.includes(fn.name));
14
16
  }
15
17
 
16
18
  export type RouteSpec = {
17
- method: 'post';
19
+ method: "get" | "post" | "put" | "patch" | "delete" | "options" | "head";
18
20
  path: string;
19
- requestBody: AnyZodObject;
20
- responseSchema?: AnyZodObject;
21
- handler: RequestHandler;
21
+ validate?: RequestHandler<any, any, any, any, any>[];
22
+ validateWithRequestSchema?: RequestHandler<any, any, any, any, any>[];
23
+ requestSchema?: Partial<Record<string, ZodTypeAny>>;
24
+ responseSchema?: ZodTypeAny;
25
+ handler: RequestHandler<any, any, any, any, any>;
22
26
  summary: string;
27
+ description?: string;
28
+ privateDocs?: boolean;
29
+ memoOnly?: boolean;
23
30
  };
24
31
 
25
- export default function buildAiRouterAndDocs(router: Router, routeSpecs: any, basePath = '/', tags: string[] = []) {
32
+ export default function buildAiRouterAndDocs(
33
+ router: Router,
34
+ routeSpecs: any,
35
+ basePath = "/",
36
+ tags: string[] = [],
37
+ ) {
26
38
  routeSpecs.forEach((spec) => {
27
39
  // mount Express
28
40
 
@@ -31,11 +43,18 @@ export default function buildAiRouterAndDocs(router: Router, routeSpecs: any, ba
31
43
  }
32
44
 
33
45
  if (spec.requestSchema) {
34
- spec.validateWithRequestSchema = [validateZod(spec.requestSchema), ...spec.validate];
46
+ spec.validateWithRequestSchema = [
47
+ validateZod(spec.requestSchema),
48
+ ...spec.validate,
49
+ ];
35
50
  }
36
51
 
37
52
  if (spec.validateWithRequestSchema) {
38
- router[spec.method](spec.path, ...spec.validateWithRequestSchema, spec.handler);
53
+ router[spec.method](
54
+ spec.path,
55
+ ...spec.validateWithRequestSchema,
56
+ spec.handler,
57
+ );
39
58
  }
40
59
 
41
60
  var { body, ...rest } = spec.requestSchema || {};
@@ -43,7 +62,7 @@ export default function buildAiRouterAndDocs(router: Router, routeSpecs: any, ba
43
62
  if (body) {
44
63
  rest.body = {
45
64
  content: {
46
- 'application/json': {
65
+ "application/json": {
47
66
  schema: body,
48
67
  },
49
68
  },
@@ -52,28 +71,44 @@ export default function buildAiRouterAndDocs(router: Router, routeSpecs: any, ba
52
71
 
53
72
  // console.log('spec.requestSchema', body);
54
73
 
55
- if (spec.responseSchema && !hasRoleValidation(spec.validate) && spec.privateDocs !== true && spec.memoOnly !== true) {
74
+ if (
75
+ spec.responseSchema &&
76
+ !hasRoleValidation(spec.validate) &&
77
+ spec.privateDocs !== true &&
78
+ spec.memoOnly !== true
79
+ ) {
56
80
  // collect all middleware fn names (falls back to '<anonymous>' if unnamed)
57
- const middlewareNames = (spec.validate || []).map((fn) => `\`${fn.name}\`` || '<anonymous>');
81
+ const middlewareNames = (spec.validate || []).map(
82
+ (fn) => `\`${fn.name}\`` || "<anonymous>",
83
+ );
84
+ const openApiPath = (basePath + spec.path).replace(
85
+ /:([A-Za-z0-9_]+)/g,
86
+ "{$1}",
87
+ );
58
88
 
59
89
  registry.registerPath({
60
90
  method: spec.method,
61
- path: basePath + spec.path,
91
+ path: openApiPath,
62
92
  summary: spec.summary,
63
93
  request: rest,
64
94
 
65
95
  // append middleware names to the description
66
- description: [spec.description, `\n\nMiddlewares: ${middlewareNames.join(', ')}`].filter(Boolean).join('\n'),
96
+ description: [
97
+ spec.description,
98
+ `\n\nMiddlewares: ${middlewareNames.join(", ")}`,
99
+ ]
100
+ .filter(Boolean)
101
+ .join("\n"),
67
102
 
68
103
  // (optionally) expose them as a custom extension instead:
69
- 'x-middlewares': middlewareNames,
104
+ "x-middlewares": middlewareNames,
70
105
 
71
106
  security: [{ [bearerAuth.name]: [] }, { [xApiKey.name]: [] }],
72
107
  responses: {
73
108
  200: {
74
- description: 'Object with user data.',
109
+ description: "Object with user data.",
75
110
  content: {
76
- 'application/json': { schema: spec.responseSchema },
111
+ "application/json": { schema: spec.responseSchema },
77
112
  },
78
113
  },
79
114
  },
@@ -1,8 +1,32 @@
1
- import type { Request, Response, NextFunction } from 'express';
1
+ import type { Request, Response, NextFunction } from "express";
2
+
3
+ type AsyncRequestHandler<
4
+ P = any,
5
+ ResBody = any,
6
+ ReqBody = any,
7
+ ReqQuery = any,
8
+ Locals extends Record<string, any> = Record<string, any>,
9
+ > = (
10
+ req: Request<P, ResBody, ReqBody, ReqQuery, Locals>,
11
+ res: Response<ResBody, Locals>,
12
+ next: NextFunction,
13
+ ) => Promise<any>;
2
14
 
3
15
  const catchAsync =
4
- (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) =>
5
- (req: Request, res: Response, next: NextFunction): void => {
16
+ <
17
+ P = any,
18
+ ResBody = any,
19
+ ReqBody = any,
20
+ ReqQuery = any,
21
+ Locals extends Record<string, any> = Record<string, any>,
22
+ >(
23
+ fn: AsyncRequestHandler<P, ResBody, ReqBody, ReqQuery, Locals>,
24
+ ) =>
25
+ (
26
+ req: Request<P, ResBody, ReqBody, ReqQuery, Locals>,
27
+ res: Response<ResBody, Locals>,
28
+ next: NextFunction,
29
+ ): void => {
6
30
  Promise.resolve(fn(req, res, next)).catch((err) => next(err));
7
31
  };
8
32
 
@@ -0,0 +1,109 @@
1
+ import { readFileSync } from "fs";
2
+ import path from "path";
3
+
4
+ export type DeviceListEntry = {
5
+ id: string;
6
+ features: string[];
7
+ deviceNameDetection?: string;
8
+ [key: string]: any;
9
+ };
10
+
11
+ export interface InitDeviceListOptions {
12
+ list?: DeviceListEntry[];
13
+ listPath?: string;
14
+ }
15
+
16
+ let deviceList: DeviceListEntry[] | null = null;
17
+
18
+ const parseDeviceList = (value: unknown): DeviceListEntry[] => {
19
+ if (!Array.isArray(value)) {
20
+ throw new Error("Device list must be an array.");
21
+ }
22
+ return value as DeviceListEntry[];
23
+ };
24
+
25
+ const loadDeviceListFromFile = (listPath: string): DeviceListEntry[] => {
26
+ const absolutePath = path.resolve(listPath);
27
+ const raw = readFileSync(absolutePath, "utf8");
28
+ const parsed = JSON.parse(raw) as unknown;
29
+ return parseDeviceList(parsed);
30
+ };
31
+
32
+ export const initDeviceList = (
33
+ options: InitDeviceListOptions = {},
34
+ ): DeviceListEntry[] => {
35
+ if (options.list) {
36
+ deviceList = options.list;
37
+ return deviceList;
38
+ }
39
+ if (options.listPath) {
40
+ deviceList = loadDeviceListFromFile(options.listPath);
41
+ return deviceList;
42
+ }
43
+ throw new Error("initDeviceList requires list or listPath.");
44
+ };
45
+
46
+ const ensureDeviceList = (): DeviceListEntry[] => {
47
+ if (!deviceList) {
48
+ throw new Error(
49
+ "deviceList is not initialized. Call initDeviceList(...) before using device utilities.",
50
+ );
51
+ }
52
+ return deviceList;
53
+ };
54
+
55
+ export { deviceList as default };
56
+
57
+ export function deviceByKind(device): any {
58
+ const list = ensureDeviceList();
59
+ const result = list.find((e) => e.id === device);
60
+ return result;
61
+ }
62
+
63
+ export function deviceByDeviceName(deviceName): any {
64
+ if (!deviceName) return false;
65
+ const list = ensureDeviceList();
66
+ const result = list.find((e) => {
67
+ if (!e.deviceNameDetection) return false;
68
+
69
+ return deviceName.startsWith(e.deviceNameDetection);
70
+ });
71
+ if (!result) return false;
72
+ return result;
73
+ }
74
+
75
+ /**
76
+ * Returns true if the device kind has the given feature
77
+ */
78
+ export function deviceKindHasFeature(
79
+ feature:
80
+ | "analog"
81
+ | "wifi"
82
+ | "epaper"
83
+ | "nbiot"
84
+ | "nouser"
85
+ | "battery-offline"
86
+ | "code7"
87
+ | "sensor"
88
+ | "payment"
89
+ | "anabox-smart"
90
+ | "intakes1"
91
+ | "intakes3"
92
+ | "intakes4"
93
+ | "intakes5"
94
+ | "intakes7"
95
+ | "stationaer"
96
+ | "tray-colors"
97
+ | "nuechtern-bedarf"
98
+ | "week-colors"
99
+ | "day-colors"
100
+ | "alt-device"
101
+ | "battery-level",
102
+ kind?: DeviceListEntry["id"],
103
+ ): boolean {
104
+ if (!kind) return false;
105
+ const list = ensureDeviceList();
106
+ const result = list.find((e) => e.id === kind);
107
+ if (!result) return false;
108
+ return result.features.includes(feature);
109
+ }
@@ -1,12 +1,13 @@
1
- import i18n from '../i18n/i18n';
2
- import type { MedicationEntry } from '../types/MedicationEntry';
1
+ // @ts-nocheck
2
+ import i18n from "../i18n/i18n";
3
+ import type { MedicationEntry } from "../types/MedicationEntry";
3
4
 
4
5
  export const medicationName = (entry: MedicationEntry, lng: string): string => {
5
6
  const name = entry.medicationData?.Kurzname
6
7
  ? entry.medicationData.Kurzname
7
8
  : entry.localMedicationData?.meta?.name
8
- ? entry.localMedicationData.meta.name.replace(/ .*/, '')
9
- : i18n.t('A medication', { lng });
9
+ ? entry.localMedicationData.meta.name.replace(/ .*/, "")
10
+ : i18n.t("A medication", { lng });
10
11
 
11
12
  return name;
12
13
  };
package/src/utils/pick.ts CHANGED
@@ -4,7 +4,11 @@
4
4
  * @param {string[]} keys - The keys to pick
5
5
  * @returns {Partial<Record<string, any>>} - The new object with picked properties
6
6
  */
7
- const pick = <T extends Record<string, any>>(object: T, keys: (keyof T)[]): Partial<T> => {
7
+ // @ts-nocheck
8
+ const pick = <T extends Record<string, any>>(
9
+ object: T,
10
+ keys: string[],
11
+ ): Partial<T> => {
8
12
  return keys.reduce((obj, key) => {
9
13
  if (object && Object.prototype.hasOwnProperty.call(object, key)) {
10
14
  obj[key] = object[key];
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import { getUserById } from "../accounts/auth0.service";
2
3
  import type { Patient } from "../types/patient"; // Assuming a `Patient` type exists in your project
3
4
 
@@ -1,45 +1,52 @@
1
- import { z } from 'zod';
2
- import { objectId } from '../validations/custom.validation';
3
- import mongoose from 'mongoose';
1
+ // @ts-nocheck
2
+ import { z } from "zod";
3
+ import { objectId } from "../validations/custom.validation";
4
+ import mongoose from "mongoose";
4
5
 
5
6
  export const zPagination = {
6
7
  query: z.object({
7
8
  name: z.string().optional(),
8
- role: z.string().openapi({ example: 'admin', description: 'Role to filter by' }).optional(),
9
- sortBy: z.string().openapi({ example: 'createdAt', description: 'Field to sort by' }).optional(),
9
+ role: z
10
+ .string()
11
+ .openapi({ example: "admin", description: "Role to filter by" })
12
+ .optional(),
13
+ sortBy: z
14
+ .string()
15
+ .openapi({ example: "createdAt", description: "Field to sort by" })
16
+ .optional(),
10
17
  search: z
11
18
  .string()
12
19
  .openapi({
13
- example: 'search term',
14
- description: 'Search term to filter results',
20
+ example: process.env.SCHEMA_EXAMPLE_SEARCH || "",
21
+ description: "Search term to filter results",
15
22
  })
16
23
  .optional(),
17
24
  limit: z.coerce
18
25
  .number()
19
26
  .openapi({
20
27
  example: 10,
21
- description: 'Number of items per page',
28
+ description: "Number of items per page",
22
29
  })
23
30
  .int()
24
31
  .min(1)
25
32
  .max(100000)
26
33
  .optional(),
27
- offset: z
34
+ offset: z.coerce
28
35
  .number() // was z.int()
29
36
  .openapi({
30
37
  example: 0,
31
- description: 'Offset for pagination, used to skip a number of items',
38
+ description: "Offset for pagination, used to skip a number of items",
32
39
  })
33
40
  .int()
34
41
  .min(0)
35
42
  .max(100000)
36
43
  .optional(),
37
- page: z
44
+ page: z.coerce
38
45
  .number()
39
46
  .int()
40
47
  .openapi({
41
48
  example: 1,
42
- description: 'Page number for pagination',
49
+ description: "Page number for pagination",
43
50
  })
44
51
  .min(1)
45
52
  .max(100000)
@@ -50,40 +57,85 @@ export const zPagination = {
50
57
  export const zPaginationResponse = () =>
51
58
  z.object({
52
59
  results: z.array(z.unknown()), // Replace with your specific item schema
53
- totalResults: z.number().openapi({ example: 100, description: 'Total number of items' }),
54
- totalPages: z.number().openapi({ example: 10, description: 'Total number of pages' }),
55
- page: z.number().openapi({ example: 1, description: 'Current page number' }),
56
- limit: z.number().openapi({ example: 10, description: 'Number of items per page' }),
60
+ totalResults: z
61
+ .number()
62
+ .openapi({ example: 100, description: "Total number of items" }),
63
+ totalPages: z
64
+ .number()
65
+ .openapi({ example: 10, description: "Total number of pages" }),
66
+ page: z
67
+ .number()
68
+ .openapi({ example: 1, description: "Current page number" }),
69
+ limit: z
70
+ .number()
71
+ .openapi({ example: 10, description: "Number of items per page" }),
57
72
  });
58
73
 
74
+ const defaultObjectIdExample = "682fd0d7d4a6325d9d45b86d";
75
+ const exampleDefaults = {
76
+ organization: "682fd0d7d4a6325d9d45b86e",
77
+ user: defaultObjectIdExample,
78
+ device: "682fd0d7d4a6325d9d45b86f",
79
+ paper: "682fd0d7d4a6325d9d45b870",
80
+ };
81
+ const objectIdExampleOverrides: Record<string, string | undefined> = {
82
+ organizationId:
83
+ process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID || exampleDefaults.organization,
84
+ organization:
85
+ process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID || exampleDefaults.organization,
86
+ userId: process.env.SCHEMA_EXAMPLE_USER_ID || exampleDefaults.user,
87
+ deviceId: process.env.SCHEMA_EXAMPLE_DEVICE_ID || exampleDefaults.device,
88
+ device: process.env.SCHEMA_EXAMPLE_DEVICE_ID || exampleDefaults.device,
89
+ paperId: process.env.SCHEMA_EXAMPLE_PAPER_ID || exampleDefaults.paper,
90
+ paper: process.env.SCHEMA_EXAMPLE_PAPER_ID || exampleDefaults.paper,
91
+ patient: process.env.SCHEMA_EXAMPLE_USER_ID || exampleDefaults.user,
92
+ accountId: process.env.SCHEMA_EXAMPLE_ACCOUNT_ID,
93
+ tokenId: process.env.SCHEMA_EXAMPLE_TOKEN_ID,
94
+ };
95
+
96
+ export const zObjectIdFor = (paramName?: string) => {
97
+ const example = paramName ? objectIdExampleOverrides[paramName] : undefined;
98
+ const exampleValue = example || defaultObjectIdExample;
99
+ return z
100
+ .string()
101
+ .refine((val) => {
102
+ if (process.env.SCHEMA_STRICT_EXAMPLES === "true" && example) {
103
+ return val === example;
104
+ }
105
+ return mongoose.Types.ObjectId.isValid(val);
106
+ })
107
+ .openapi({
108
+ example: exampleValue,
109
+ description: "A valid MongoDB ObjectId",
110
+ });
111
+ };
112
+
59
113
  export const zGet = (id: string) => ({
60
114
  params: z.object({
61
- [id]: zObjectId /* .openapi({ example: '682fd0d7d4a6325d9d45b86d' }) */,
115
+ [id]: zObjectIdFor(id),
62
116
  }),
63
117
  });
64
118
 
65
- export function zPatchBody<T extends ZodRawShape>(shape: T, message = 'At least one field must be provided for update') {
119
+ export function zPatchBody<T extends ZodRawShape>(
120
+ shape: T,
121
+ message = "At least one field must be provided for update",
122
+ ) {
66
123
  // assume user passed in already-optional vals
67
124
  return z.object(shape); // .refine((o) => Object.keys(o).length > 0, { message });
68
125
  }
69
126
 
70
127
  export const zUpdate = (id: string) => ({
71
128
  params: z.object({
72
- [id]: zObjectId,
129
+ [id]: zObjectIdFor(id),
73
130
  }),
74
131
  });
75
132
 
76
133
  export const zDelete = (id: string) => ({
77
134
  params: z.object({
78
- [id]: zObjectId,
135
+ [id]: zObjectIdFor(id),
79
136
  }),
80
137
  });
81
138
 
82
- export const zObjectId = z
83
- .string()
84
- .refine((val) => {
85
- return mongoose.Types.ObjectId.isValid(val);
86
- })
87
- .openapi({ example: '682fd0d7d4a6325d9d45b86d', description: 'A valid MongoDB ObjectId' });
139
+ export const zObjectId = zObjectIdFor();
88
140
 
89
141
  export const zDate = () => z.string().pipe(z.coerce.date());
package/tsconfig.json CHANGED
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
- "module": "NodeNext",
4
+ "module": "ES2020",
5
5
  "baseUrl": ".",
6
6
  "rootDir": ".",
7
7
  "outDir": "./dist",
8
8
  "esModuleInterop": true,
9
- "strict": true,
10
- "moduleResolution": "NodeNext",
9
+ "strict": false,
10
+ "noImplicitAny": false,
11
+ "noImplicitThis": false,
12
+ "useUnknownInCatchVariables": false,
13
+ "noUncheckedIndexedAccess": false,
14
+ "exactOptionalPropertyTypes": false,
15
+ "moduleResolution": "Bundler",
11
16
  "resolveJsonModule": true,
12
17
  "forceConsistentCasingInFileNames": true,
13
18
  "skipLibCheck": true,
@@ -17,6 +22,10 @@
17
22
  "esm": true,
18
23
  "experimentalSpecifierResolution": "node"
19
24
  },
20
- "include": ["src/**/*", "common.legac, "../memo-api/src/middlewares/validateMessage.ts"y/**/*"],
25
+ "include": [
26
+ "src/**/*",
27
+ "common.legacy/**/*",
28
+ "../memo-api/src/middlewares/validateMessage.ts"
29
+ ],
21
30
  "exclude": ["node_modules", "dist"]
22
31
  }