@internetderdinge/api 1.229.0 → 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 (167) 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 +13 -3
  103. package/scripts/release-and-sync-paperless.mjs +135 -0
  104. package/src/accounts/accounts.controller.ts +1 -0
  105. package/src/accounts/accounts.service.ts +1 -0
  106. package/src/accounts/accounts.validation.ts +6 -3
  107. package/src/accounts/auth0.service.ts +55 -28
  108. package/src/config/config.ts +6 -0
  109. package/src/config/logger.ts +15 -9
  110. package/src/devices/devices.controller.ts +7 -1
  111. package/src/devices/devices.model.ts +4 -1
  112. package/src/devices/devices.schemas.ts +10 -8
  113. package/src/devices/devices.service.ts +1 -0
  114. package/src/devices/devices.types.ts +1 -0
  115. package/src/devices/devices.validation.ts +85 -23
  116. package/src/devicesNotifications/devicesNotifications.controller.ts +57 -28
  117. package/src/devicesNotifications/devicesNotifications.model.ts +20 -12
  118. package/src/devicesNotifications/devicesNotifications.service.ts +35 -17
  119. package/src/files/upload.service.ts +52 -28
  120. package/src/i18n/i18n.ts +1 -1
  121. package/src/i18n/types.ts +1 -0
  122. package/src/index.ts +47 -0
  123. package/src/iotdevice/iotdevice.controller.ts +1 -0
  124. package/src/iotdevice/iotdevice.model.ts +6 -3
  125. package/src/iotdevice/iotdevice.route.ts +85 -76
  126. package/src/iotdevice/iotdevice.service.ts +4 -3
  127. package/src/iotdevice/iotdevice.types.ts +6 -0
  128. package/src/middlewares/auth.ts +2 -8
  129. package/src/middlewares/error.ts +26 -12
  130. package/src/middlewares/mongooseValidations/ensureSameOrganization.ts +4 -3
  131. package/src/middlewares/validateAi.ts +17 -9
  132. package/src/middlewares/validateDevice.ts +1 -0
  133. package/src/middlewares/validateDeviceUserOrganization.ts +1 -0
  134. package/src/middlewares/validateOrganization.ts +1 -1
  135. package/src/middlewares/validateQuerySearchUserAndOrganization.ts +1 -0
  136. package/src/middlewares/validateTokens.ts +2 -1
  137. package/src/middlewares/validateUser.ts +1 -0
  138. package/src/models/plugins/index.ts +5 -4
  139. package/src/models/plugins/paginate.plugin.ts +26 -16
  140. package/src/models/plugins/paginateNew.plugin.ts +33 -21
  141. package/src/models/plugins/simplePopulate.ts +8 -3
  142. package/src/models/plugins/toJSON.plugin.ts +12 -5
  143. package/src/organizations/organizations.controller.ts +1 -2
  144. package/src/organizations/organizations.model.ts +4 -4
  145. package/src/organizations/organizations.route.ts +1 -1
  146. package/src/organizations/organizations.service.ts +15 -6
  147. package/src/pdf/pdf.controller.ts +18 -1
  148. package/src/pdf/pdf.service.ts +25 -16
  149. package/src/tokens/tokens.controller.ts +6 -8
  150. package/src/tokens/tokens.model.ts +3 -1
  151. package/src/tokens/tokens.service.ts +3 -2
  152. package/src/types/express.d.ts +17 -0
  153. package/src/types/mongoose.d.ts +22 -0
  154. package/src/users/users.controller.ts +8 -9
  155. package/src/users/users.model.ts +6 -5
  156. package/src/users/users.route.ts +0 -1
  157. package/src/users/users.service.ts +16 -0
  158. package/src/users/users.types.ts +1 -0
  159. package/src/users/users.validation.ts +6 -2
  160. package/src/utils/ApiError.ts +8 -1
  161. package/src/utils/buildRouterAndDocs.ts +56 -21
  162. package/src/utils/catchAsync.ts +27 -3
  163. package/src/utils/medicationName.ts +5 -4
  164. package/src/utils/pick.ts +5 -1
  165. package/src/utils/userName.ts +1 -0
  166. package/src/utils/zValidations.ts +78 -26
  167. package/tsconfig.json +13 -4
@@ -1,7 +1,8 @@
1
- import { AuthenticationClient, ManagementClient } from 'auth0';
2
- import type { ManagementClientOptions, User } from 'auth0';
3
- import { promises as fs, readFileSync } from 'fs';
4
- import { config } from 'process';
1
+ // @ts-nocheck
2
+ import { AuthenticationClient, ManagementClient } from "auth0";
3
+ import type { ManagementClientOptions, User } from "auth0";
4
+ import { promises as fs, readFileSync } from "fs";
5
+ import { config } from "process";
5
6
 
6
7
  interface TokenManagementClient {
7
8
  clientId?: string;
@@ -21,12 +22,12 @@ let tokenManagementClient: TokenManagementClient = {
21
22
 
22
23
  //if (config.env !== 'production') {
23
24
  try {
24
- console.warn('Auth0 client: use local token from cache try');
25
- const token = readFileSync('./token.txt', 'utf8');
26
- console.warn('Auth0 client: use local token from cache');
25
+ console.warn("Auth0 client: use local token from cache try");
26
+ const token = readFileSync("./token.txt", "utf8");
27
+ console.warn("Auth0 client: use local token from cache");
27
28
  tokenManagementClient = { token };
28
29
  } catch (error) {
29
- console.log('Auth0 Client: use new token');
30
+ console.log("Auth0 Client: use new token");
30
31
  }
31
32
  //}
32
33
 
@@ -56,14 +57,16 @@ let cachedManagementToken: string | null = null;
56
57
  let managementTokenExpiresAt: number | null = null;
57
58
  let pendingManagementTokenPromise: Promise<string> | null = null;
58
59
 
59
- const TOKEN_FILE_PATH = './token.txt';
60
- const MANAGEMENT_TOKEN_FILE_PATH = './token.management.txt';
60
+ const TOKEN_FILE_PATH = "./token.txt";
61
+ const MANAGEMENT_TOKEN_FILE_PATH = "./token.management.txt";
61
62
  const TOKEN_BUFFER_SECONDS = 60; // refresh a minute before expiry
62
63
  const TOKEN_FALLBACK_TTL_SECONDS = 3300; // ~55 minutes when no expiry metadata exists
63
64
 
64
- const loadTokenFromFile = async (filePath: string): Promise<CachedToken | null> => {
65
+ const loadTokenFromFile = async (
66
+ filePath: string,
67
+ ): Promise<CachedToken | null> => {
65
68
  try {
66
- const raw = await fs.readFile(filePath, 'utf8');
69
+ const raw = await fs.readFile(filePath, "utf8");
67
70
  try {
68
71
  const parsed = JSON.parse(raw);
69
72
  if (parsed?.token && parsed?.expiresAt) {
@@ -80,22 +83,34 @@ const loadTokenFromFile = async (filePath: string): Promise<CachedToken | null>
80
83
  return null;
81
84
  };
82
85
 
83
- const writeTokenFile = async (filePath: string, token: string, expiresAt: number): Promise<void> => {
86
+ const writeTokenFile = async (
87
+ filePath: string,
88
+ token: string,
89
+ expiresAt: number,
90
+ ): Promise<void> => {
84
91
  const payload = JSON.stringify({ token, expiresAt });
85
- await fs.writeFile(filePath, payload, 'utf8');
92
+ await fs.writeFile(filePath, payload, "utf8");
86
93
  };
87
94
 
88
- const tokenIsValid = (token: string | null, expiresAt: number | null, now: number): boolean => {
95
+ const tokenIsValid = (
96
+ token: string | null,
97
+ expiresAt: number | null,
98
+ now: number,
99
+ ): boolean => {
89
100
  if (!token || !expiresAt) return false;
90
101
  return now < expiresAt - TOKEN_BUFFER_SECONDS;
91
102
  };
92
103
 
93
104
  export const getAuth0Token = async (): Promise<string> => {
94
- const audience = process.env.AUTH0_AUDIENCE || process.env.AUTH0_MANAGEMENT_AUDIENCE || 'localhost:3000/';
105
+ const audience =
106
+ process.env.AUTH0_AUDIENCE ||
107
+ process.env.AUTH0_MANAGEMENT_AUDIENCE ||
108
+ "localhost:3000/";
95
109
  const grantOpts = { audience };
96
110
 
97
111
  const now = Math.floor(Date.now() / 1000);
98
- if (tokenIsValid(cachedToken, tokenExpiresAt, now)) return cachedToken as string;
112
+ if (tokenIsValid(cachedToken, tokenExpiresAt, now))
113
+ return cachedToken as string;
99
114
  if (pendingTokenPromise) return pendingTokenPromise;
100
115
 
101
116
  pendingTokenPromise = (async () => {
@@ -110,7 +125,8 @@ export const getAuth0Token = async (): Promise<string> => {
110
125
  }
111
126
  //}
112
127
 
113
- const tokenResponse = await auth0AuthClient.oauth.clientCredentialsGrant(grantOpts);
128
+ const tokenResponse =
129
+ await auth0AuthClient.oauth.clientCredentialsGrant(grantOpts);
114
130
  const expiresIn = tokenResponse.data.expires_in || 3600;
115
131
  cachedToken = tokenResponse.data.access_token;
116
132
  tokenExpiresAt = now + expiresIn;
@@ -129,13 +145,16 @@ export const getAuth0Token = async (): Promise<string> => {
129
145
  export const getAuth0ManagementToken = async (): Promise<string> => {
130
146
  const audience = process.env.AUTH0_MANAGEMENT_AUDIENCE;
131
147
  if (!audience) {
132
- throw new Error('Missing AUTH0_MANAGEMENT_AUDIENCE; cannot mint Management API token');
148
+ throw new Error(
149
+ "Missing AUTH0_MANAGEMENT_AUDIENCE; cannot mint Management API token",
150
+ );
133
151
  }
134
152
 
135
153
  const grantOpts = { audience };
136
154
  const now = Math.floor(Date.now() / 1000);
137
155
 
138
- if (tokenIsValid(cachedManagementToken, managementTokenExpiresAt, now)) return cachedManagementToken as string;
156
+ if (tokenIsValid(cachedManagementToken, managementTokenExpiresAt, now))
157
+ return cachedManagementToken as string;
139
158
  if (pendingManagementTokenPromise) return pendingManagementTokenPromise;
140
159
 
141
160
  pendingManagementTokenPromise = (async () => {
@@ -147,12 +166,17 @@ export const getAuth0ManagementToken = async (): Promise<string> => {
147
166
  return cachedManagementToken;
148
167
  }
149
168
 
150
- const tokenResponse = await auth0AuthClient.oauth.clientCredentialsGrant(grantOpts);
169
+ const tokenResponse =
170
+ await auth0AuthClient.oauth.clientCredentialsGrant(grantOpts);
151
171
  const expiresIn = tokenResponse.data.expires_in || 3600;
152
172
  cachedManagementToken = tokenResponse.data.access_token;
153
173
  managementTokenExpiresAt = now + expiresIn;
154
174
 
155
- await writeTokenFile(MANAGEMENT_TOKEN_FILE_PATH, cachedManagementToken, managementTokenExpiresAt);
175
+ await writeTokenFile(
176
+ MANAGEMENT_TOKEN_FILE_PATH,
177
+ cachedManagementToken,
178
+ managementTokenExpiresAt,
179
+ );
156
180
 
157
181
  pendingManagementTokenPromise = null;
158
182
  return cachedManagementToken;
@@ -172,8 +196,8 @@ export const getUserIdByEmail = async (email: string): Promise<User[]> => {
172
196
  return auth0.usersByEmail.getByEmail({ email });
173
197
  };
174
198
 
175
- export const sendVerificationEmail = async (userID: string): Promise<void> => {
176
- await auth0.jobs.verifyEmail({ user_id: userID });
199
+ export const sendVerificationEmail = async (userID: string): Promise<any> => {
200
+ return auth0.jobs.verifyEmail({ user_id: userID });
177
201
  };
178
202
 
179
203
  export const getUserById = async (userId: string): Promise<User> => {
@@ -184,7 +208,10 @@ export const avatar = async (userId: string): Promise<User> => {
184
208
  return auth0.users.get({ id: userId });
185
209
  };
186
210
 
187
- export const mfaEnrollAccount = async (userId: string, mfaToken: string): Promise<any> => {
211
+ export const mfaEnrollAccount = async (
212
+ userId: string,
213
+ mfaToken: string,
214
+ ): Promise<any> => {
188
215
  const ticketResponse = await auth0.guardian.createEnrollmentTicket({
189
216
  user_id: userId,
190
217
  send_mail: false,
@@ -199,13 +226,13 @@ export const mfaDisableAccount = async (userId: string): Promise<any> => {
199
226
  };
200
227
 
201
228
  export const getUsersByIds = async (postIDs: string[]): Promise<User[]> => {
202
- let q = '';
229
+ let q = "";
203
230
  postIDs.forEach((e, i) => {
204
- if (e) q = `${q} ${i >= 2 ? ' OR ' : ''} user_id:"${e}"`;
231
+ if (e) q = `${q} ${i >= 2 ? " OR " : ""} user_id:"${e}"`;
205
232
  });
206
233
 
207
234
  const params = {
208
- search_engine: 'v3',
235
+ search_engine: "v3",
209
236
  q,
210
237
  per_page: 100,
211
238
  page: 0,
@@ -3,6 +3,12 @@ import dotenv from "dotenv";
3
3
  // Load env from the current working directory
4
4
  dotenv.config();
5
5
 
6
+ console.log("Current working directory:", process.cwd());
7
+ console.log("Loaded environment variables:", {
8
+ NODE_ENV: process.env.NODE_ENV,
9
+ PORT: process.env.PORT,
10
+ MONGODB_URL: process.env.MONGODB_URL,
11
+ });
6
12
  import Joi from "joi";
7
13
 
8
14
  const envVarsSchema = Joi.object()
@@ -1,6 +1,7 @@
1
- import winston from 'winston';
2
- import type { Format } from 'logform';
3
- import config from './config';
1
+ // @ts-nocheck
2
+ import winston from "winston";
3
+ import type { Format } from "logform";
4
+ import config from "./config";
4
5
 
5
6
  const enumerateErrorFormat: Format = winston.format((info) => {
6
7
  if (info instanceof Error) {
@@ -10,22 +11,27 @@ const enumerateErrorFormat: Format = winston.format((info) => {
10
11
  });
11
12
 
12
13
  const logger = winston.createLogger({
13
- level: config.env === 'development' ? 'debug' : 'info',
14
+ level: config.env === "development" ? "debug" : "info",
14
15
  format: winston.format.combine(
15
16
  enumerateErrorFormat(),
16
- config.env === 'development' ? winston.format.colorize() : winston.format.uncolorize(),
17
+ config.env === "development"
18
+ ? winston.format.colorize()
19
+ : winston.format.uncolorize(),
17
20
  winston.format.splat(),
18
21
  winston.format.printf((info) => {
19
- const { level, message, stack, ...rest } = info as Record<string, unknown>;
22
+ const { level, message, stack, ...rest } = info as Record<
23
+ string,
24
+ unknown
25
+ >;
20
26
  const restKeys = Object.keys(rest);
21
- const restText = restKeys.length ? ` ${JSON.stringify(rest)}` : '';
22
- const stackText = stack ? `\n${stack}` : '';
27
+ const restText = restKeys.length ? ` ${JSON.stringify(rest)}` : "";
28
+ const stackText = stack ? `\n${stack}` : "";
23
29
  return `${level}: ${message}${stackText}${restText}`;
24
30
  }),
25
31
  ),
26
32
  transports: [
27
33
  new winston.transports.Console({
28
- stderrLevels: ['error'],
34
+ stderrLevels: ["error"],
29
35
  }),
30
36
  ],
31
37
  });
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import httpStatus from "http-status";
2
3
  import mongoose from "mongoose";
3
4
  import multer from "multer";
@@ -247,9 +248,14 @@ const uploadSingleImage = catchAsync(
247
248
  async (req: Request, res: Response): Promise<void> => {
248
249
  const device = await devicesService.getById(req.params.deviceId);
249
250
 
251
+ const files = req.files as Array<{ buffer: Buffer }> | undefined;
252
+ if (!files || files.length === 0) {
253
+ throw new ApiError(httpStatus.BAD_REQUEST, "No image file uploaded");
254
+ }
255
+
250
256
  const iotUpload = await iotDevicesService.uploadSingleImage({
251
257
  deviceName: device.deviceId,
252
- buffer: req.files[0].buffer,
258
+ buffer: files[0].buffer,
253
259
  deviceId: req.params.deviceId,
254
260
  uuid: req.body.uuid,
255
261
  });
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import mongoose, { Schema, Document, Model, Types } from "mongoose";
2
3
  import { toJSON, paginate } from "../models/plugins/index.js";
3
4
  import { ensureSameOrganization } from "../middlewares/mongooseValidations/ensureSameOrganization.js";
@@ -121,6 +122,8 @@ addIotDevice(deviceSchema);
121
122
  deviceSchema.plugin((schema: Schema) => toJSON(schema, true));
122
123
  deviceSchema.plugin(paginate);
123
124
 
124
- const Devices: Model<IDevice> = mongoose.model<IDevice>("Device", deviceSchema);
125
+ const Devices: Model<IDevice> =
126
+ (mongoose.models.Device as Model<IDevice>) ||
127
+ mongoose.model<IDevice>("Device", deviceSchema);
125
128
 
126
129
  export default Devices;
@@ -22,9 +22,9 @@ export const eventResponseSchema = z.object({
22
22
  // ...other event fields...
23
23
  });
24
24
 
25
- export const genericResponseSchema = z.object({
26
- message: z.string(),
27
- });
25
+ export const genericResponseSchema = z
26
+ .record(z.any())
27
+ .openapi({ description: "Generic response payload" });
28
28
 
29
29
  export const imageResponseSchema = z.object({
30
30
  uuid: z.string(),
@@ -64,11 +64,13 @@ export const subscriptionResponseSchema = z.object({
64
64
  // ...other subscription fields...
65
65
  });
66
66
 
67
- export const uploadResponseSchema = z.object({
68
- filenames: z.array(z.string()),
69
- urls: z.array(z.string().url()),
70
- // ...other upload result fields...
71
- });
67
+ export const uploadResponseSchema = z
68
+ .object({
69
+ key: z.string().optional(),
70
+ similarityPercentage: z.number().nullable().optional(),
71
+ skippedUpload: z.boolean().optional(),
72
+ })
73
+ .openapi({ description: "Upload response payload" });
72
74
 
73
75
  export const pingDeviceSchema = {
74
76
  params: z.object({
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  import httpStatus from "http-status";
2
3
  import Device from "./devices.model.js";
3
4
  import ApiError from "../utils/ApiError.js";
@@ -0,0 +1 @@
1
+ export type Device = any;
@@ -4,6 +4,7 @@ import { objectId } from "../validations/custom.validation.js";
4
4
  import {
5
5
  zGet,
6
6
  zObjectId,
7
+ zObjectIdFor,
7
8
  zPatchBody,
8
9
  zUpdate,
9
10
  zDelete,
@@ -66,6 +67,11 @@ export const updateEntrySchema = {
66
67
  };
67
68
 
68
69
  export const getEventsSchema = {
70
+ params: z.object({
71
+ deviceId: zObjectIdFor("deviceId").openapi({
72
+ description: "Device ObjectId",
73
+ }),
74
+ }),
69
75
  query: z
70
76
  .object({
71
77
  DateStart: z.string(),
@@ -92,14 +98,29 @@ export const createCustomerPortalSessionSchema = {
92
98
  export const createDeviceSchema = {
93
99
  body: z.object({
94
100
  kind: z.string().optional(),
95
- patient: zObjectId.optional().nullable(),
96
- paper: zObjectId.optional().nullable(),
97
- organization: zObjectId.openapi({ description: "Organization ObjectId" }),
101
+ patient: zObjectIdFor("patient")
102
+ .optional()
103
+ .nullable()
104
+ .openapi({ description: "Patient ObjectId", example: null }),
105
+ paper: zObjectIdFor("paper")
106
+ .optional()
107
+ .nullable()
108
+ .openapi({ description: "Paper ObjectId", example: null }),
109
+ organization: zObjectIdFor("organization").openapi({
110
+ description: "Organization ObjectId",
111
+ }),
98
112
  }),
99
113
  };
100
114
  export const deleteDeviceSchema = zDelete("deviceId");
101
115
  export const getDeviceSchema = zGet("deviceId");
102
- export const getImageSchema = zGet("deviceId");
116
+ export const getImageSchema = {
117
+ params: z.object({
118
+ deviceId: zObjectIdFor("deviceId").openapi({
119
+ description: "Device ObjectId",
120
+ }),
121
+ uuid: z.string().openapi({ description: "Image UUID" }),
122
+ }),
123
+ };
103
124
  export const ledLightSchema = {
104
125
  params: z.object({
105
126
  deviceId: zObjectId.openapi({ description: "Device ObjectId" }),
@@ -149,7 +170,9 @@ export const ledLightSchema = {
149
170
  };
150
171
  export const pingDeviceSchema = {
151
172
  params: z.object({
152
- deviceId: zObjectId.openapi({ description: "Device ObjectId" }),
173
+ deviceId: zObjectIdFor("deviceId").openapi({
174
+ description: "Device ObjectId",
175
+ }),
153
176
  }),
154
177
  query: z.object({
155
178
  dataResponse: z
@@ -160,34 +183,49 @@ export const pingDeviceSchema = {
160
183
 
161
184
  export const resetDeviceSchema = {
162
185
  params: z.object({
163
- deviceId: zObjectId.openapi({ description: "Device ObjectId" }),
186
+ deviceId: zObjectIdFor("deviceId").openapi({
187
+ description: "Device ObjectId",
188
+ }),
164
189
  }),
165
190
  };
166
191
 
167
192
  export const rebootDeviceSchema = zGet("deviceId");
168
193
 
169
194
  export const registerDeviceSchema = {
170
- ...zPagination,
171
- body: z.object({
172
- enable: z.boolean(),
173
- organization: zObjectId,
174
- patient: zObjectId.optional().nullable(),
175
- paper: zObjectId.optional().nullable(),
176
- }),
195
+ body: z
196
+ .object({
197
+ enable: z.boolean(),
198
+ organization: zObjectIdFor("organization"),
199
+ patient: zObjectId.optional().nullable(),
200
+ paper: zObjectId.optional().nullable(),
201
+ })
202
+ .openapi({
203
+ example: {
204
+ enable: true,
205
+ organization:
206
+ process.env.SCHEMA_EXAMPLE_ORGANIZATION_ID || "682fd0d7d4a6325d9d45b86d",
207
+ patient: process.env.SCHEMA_EXAMPLE_USER_ID || "682fd0d7d4a6325d9d45b86d",
208
+ paper: process.env.SCHEMA_EXAMPLE_PAPER_ID || null,
209
+ },
210
+ }),
177
211
  params: z.object({
178
- deviceId: z.string(),
179
- }),
180
- query: zPagination.query.extend({
181
- patient: zObjectId.optional(),
182
- organization: zObjectId.optional(),
212
+ deviceId: (
213
+ process.env.SCHEMA_STRICT_EXAMPLES === "true" &&
214
+ process.env.SCHEMA_EXAMPLE_DEVICE_SERIAL
215
+ ? z.literal(process.env.SCHEMA_EXAMPLE_DEVICE_SERIAL)
216
+ : z.string()
217
+ ).openapi({
218
+ description: "Device serial",
219
+ example: process.env.SCHEMA_EXAMPLE_DEVICE_SERIAL || "DEVICE-EXAMPLE",
220
+ }),
183
221
  }),
184
222
  };
185
223
 
186
224
  export const queryDevicesSchema = {
187
225
  ...zPagination,
188
226
  query: zPagination.query.extend({
189
- patient: zObjectId.optional(),
190
- organization: zObjectId.optional(),
227
+ patient: zObjectIdFor("patient").optional(),
228
+ organization: zObjectIdFor("organization"),
191
229
  }),
192
230
  };
193
231
  export const subscriptionSchema = {
@@ -213,9 +251,33 @@ export const updateDeviceSchema = {
213
251
  }),
214
252
  };
215
253
 
216
- export const updateSingleImageMetaSchema = {};
254
+ export const updateSingleImageMetaSchema = {
255
+ params: z.object({
256
+ deviceId: zObjectIdFor("deviceId").openapi({
257
+ description: "Device ObjectId",
258
+ }),
259
+ }),
260
+ body: z
261
+ .object({
262
+ meta: z.record(z.any()).optional(),
263
+ })
264
+ .openapi({ description: "Image metadata updates" }),
265
+ };
217
266
  export const uploadSingleImageSchema = {
218
- body: z.object({
219
- file: z.instanceof(File).openapi({ description: "File to upload" }),
267
+ params: z.object({
268
+ deviceId: zObjectIdFor("deviceId").openapi({
269
+ description: "Device ObjectId",
270
+ }),
220
271
  }),
272
+ body: z
273
+ .object({
274
+ uuid: z
275
+ .string()
276
+ .optional()
277
+ .openapi({ description: "Optional image UUID", example: "mock-uuid" }),
278
+ })
279
+ .openapi({
280
+ description: "Multipart body is mocked during tests.",
281
+ example: { uuid: "mock-uuid" },
282
+ }),
221
283
  };
@@ -1,56 +1,85 @@
1
- import httpStatus from 'http-status';
1
+ // @ts-nocheck
2
+ import httpStatus from "http-status";
2
3
 
3
- import pick from '../../src/utils/pick';
4
- import ApiError from '../../src/utils/ApiError';
5
- import catchAsync from '../../src/utils/catchAsync';
6
- import devicesNotificationsService from './devicesNotifications.service';
4
+ import pick from "../../src/utils/pick";
5
+ import ApiError from "../../src/utils/ApiError";
6
+ import catchAsync from "../../src/utils/catchAsync";
7
+ import devicesNotificationsService from "./devicesNotifications.service";
7
8
 
8
- import type { Request, Response } from 'express';
9
+ import type { Request, Response } from "express";
9
10
 
10
11
  export const createEntry = catchAsync(async (req: Request, res: Response) => {
11
- const user = await devicesNotificationsService.createNotification({ user: res.req.auth.sub, token: req.body.token });
12
+ const user = await devicesNotificationsService.createNotification({
13
+ user: res.req.auth.sub,
14
+ token: req.body.token,
15
+ });
12
16
  res.status(httpStatus.CREATED).send(user);
13
17
  });
14
18
 
15
- export const setDeviceToken = catchAsync(async (req: Request, res: Response) => {
16
- const user = await devicesNotificationsService.setDeviceToken({ user: res.req.auth.sub, body: req.body });
17
- res.status(httpStatus.CREATED).send(user);
18
- });
19
+ export const setDeviceToken = catchAsync(
20
+ async (req: Request, res: Response) => {
21
+ const user = await devicesNotificationsService.setDeviceToken({
22
+ user: res.req.auth.sub,
23
+ body: req.body,
24
+ });
25
+ res.status(httpStatus.CREATED).send(user);
26
+ },
27
+ );
19
28
 
20
- export const removeDeviceToken = catchAsync(async (req: Request, res: Response) => {
21
- const user = await devicesNotificationsService.removeDeviceToken({ user: res.req.auth.sub, body: req.body });
22
- res.status(httpStatus.CREATED).send(user);
23
- });
29
+ export const removeDeviceToken = catchAsync(
30
+ async (req: Request, res: Response) => {
31
+ const user = await devicesNotificationsService.removeDeviceToken({
32
+ user: res.req.auth.sub,
33
+ body: req.body,
34
+ });
35
+ res.status(httpStatus.CREATED).send(user);
36
+ },
37
+ );
24
38
 
25
39
  export const getEntries = catchAsync(async (req: Request, res: Response) => {
26
- const filter = pick(req.query, ['name', 'role']);
27
- const options = pick(req.query, ['sortBy', 'limit', 'page']);
28
- const result = await devicesNotificationsService.queryNotifications(filter, options);
40
+ const filter = pick(req.query, ["name", "role"]);
41
+ const options = pick(req.query, ["sortBy", "limit", "page"]);
42
+ const result = await devicesNotificationsService.queryNotifications(
43
+ filter,
44
+ options,
45
+ );
29
46
  res.send(result);
30
47
  });
31
48
 
32
- export const queryNotificationsByUser = catchAsync(async (req: Request, res: Response) => {
33
- const filter = pick({ user: res.req.auth.sub }, ['user']);
34
- const options = pick(req.query, ['sortBy', 'limit', 'page']);
35
- const result = await devicesNotificationsService.queryNotificationsByUser(filter, options);
36
- res.send(result);
37
- });
49
+ export const queryNotificationsByUser = catchAsync(
50
+ async (req: Request, res: Response) => {
51
+ const filter = pick({ user: res.req.auth.sub }, ["user"]);
52
+ const options = pick(req.query, ["sortBy", "limit", "page"]);
53
+ const result = await devicesNotificationsService.queryNotificationsByUser(
54
+ filter,
55
+ options,
56
+ );
57
+ res.send(result);
58
+ },
59
+ );
38
60
 
39
61
  export const getEntry = catchAsync(async (req: Request, res: Response) => {
40
- const notification = await devicesNotificationsService.getById(req.params.notificationId);
62
+ const notification = await devicesNotificationsService.getById(
63
+ req.params.notificationId,
64
+ );
41
65
  if (!notification) {
42
- throw new ApiError(httpStatus.NOT_FOUND, 'Notification not found');
66
+ throw new ApiError(httpStatus.NOT_FOUND, "Notification not found");
43
67
  }
44
68
  res.send(notification);
45
69
  });
46
70
 
47
71
  export const updateEntry = catchAsync(async (req: Request, res: Response) => {
48
- const user = await devicesNotificationsService.updateById(req.params.notificationId, req.body);
72
+ const user = await devicesNotificationsService.updateById(
73
+ req.params.notificationId,
74
+ req.body,
75
+ );
49
76
  res.send(user);
50
77
  });
51
78
 
52
79
  export const deleteEntry = catchAsync(async (req: Request, res: Response) => {
53
- const entry = await devicesNotificationsService.deleteById(req.params.notificationId);
80
+ const entry = await devicesNotificationsService.deleteById(
81
+ req.params.notificationId,
82
+ );
54
83
  res.send(entry);
55
84
  });
56
85
 
@@ -1,6 +1,7 @@
1
- import mongoose, { Schema, Document, Model } from 'mongoose';
2
- import type { PaginateModel } from 'mongoose';
3
- import { toJSON, paginate } from '../../src/models/plugins/index';
1
+ // @ts-nocheck
2
+ import mongoose, { Schema, Document, Model } from "mongoose";
3
+ import type { PaginateModel } from "mongoose";
4
+ import { toJSON, paginate } from "../../src/models/plugins/index";
4
5
 
5
6
  interface Token {
6
7
  token: string;
@@ -11,7 +12,7 @@ interface Token {
11
12
 
12
13
  interface Settings {
13
14
  intake: { email: boolean; push: boolean };
14
- 'intake-reminder': { email: boolean; push: boolean };
15
+ "intake-reminder": { email: boolean; push: boolean };
15
16
  battery: { email: boolean; push: boolean };
16
17
  }
17
18
 
@@ -24,7 +25,8 @@ export interface DeviceNotificationDocument extends Document {
24
25
  updatedAt: Date;
25
26
  }
26
27
 
27
- export type DeviceNotificationModel = Model<DeviceNotificationDocument> & PaginateModel<DeviceNotificationDocument>;
28
+ export type DeviceNotificationModel = Model<DeviceNotificationDocument> &
29
+ PaginateModel<DeviceNotificationDocument>;
28
30
 
29
31
  const deviceNotificationSchema = new Schema<DeviceNotificationDocument>(
30
32
  {
@@ -42,12 +44,18 @@ const deviceNotificationSchema = new Schema<DeviceNotificationDocument>(
42
44
  ],
43
45
  bounceEmail: { type: String },
44
46
  settings: {
45
- intake: { email: { type: Boolean, default: true }, push: { type: Boolean, default: true } },
46
- 'intake-reminder': {
47
+ intake: {
48
+ email: { type: Boolean, default: true },
49
+ push: { type: Boolean, default: true },
50
+ },
51
+ "intake-reminder": {
52
+ email: { type: Boolean, default: true },
53
+ push: { type: Boolean, default: true },
54
+ },
55
+ battery: {
47
56
  email: { type: Boolean, default: true },
48
57
  push: { type: Boolean, default: true },
49
58
  },
50
- battery: { email: { type: Boolean, default: true }, push: { type: Boolean, default: true } },
51
59
  },
52
60
  },
53
61
  {
@@ -59,9 +67,9 @@ const deviceNotificationSchema = new Schema<DeviceNotificationDocument>(
59
67
  deviceNotificationSchema.plugin(toJSON);
60
68
  deviceNotificationSchema.plugin(paginate);
61
69
 
62
- const DeviceNotifications = mongoose.model<DeviceNotificationDocument, DeviceNotificationModel>(
63
- 'DeviceNotification',
64
- deviceNotificationSchema,
65
- );
70
+ const DeviceNotifications = mongoose.model<
71
+ DeviceNotificationDocument,
72
+ DeviceNotificationModel
73
+ >("DeviceNotification", deviceNotificationSchema);
66
74
 
67
75
  export default DeviceNotifications;