@yrpri/api 9.0.220 → 9.0.222

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 (55) hide show
  1. package/agents/managers/subscriptionManager.js +2 -2
  2. package/app.js +11 -8
  3. package/controllers/communities.cjs +3 -1
  4. package/controllers/groups.cjs +1 -1
  5. package/controllers/images.cjs +12 -1
  6. package/models/domain.cjs +1 -1
  7. package/models/image.cjs +90 -24
  8. package/package.json +83 -63
  9. package/scripts/cloning/clearUsersForCommunitiesFromUrl.js +1 -1
  10. package/scripts/cloning/cloneFromUrlScript.js +1 -1
  11. package/scripts/cloning/cloneWBFromUrlScriptAndCreateLinks.js +1 -1
  12. package/scripts/cloning/cloneWBFromUrlScriptNoUsersOrPoints.js +1 -1
  13. package/scripts/cloning/cloneWBSerbianFromUrlScriptAndCreateLinks.js +1 -1
  14. package/scripts/cloning/copyCommunityConfigAndTranslationsFromURL.js +1 -1
  15. package/scripts/cloning/copyGroupConfigAndTranslationsFromURL.js +1 -1
  16. package/scripts/cloning/copyPostVideosFromURL.js +1 -1
  17. package/scripts/cloning/deepCloneSerbianWBFromUrlScriptAndCreateLinks.js +1 -1
  18. package/scripts/cloning/deepCloneWBFromUrlScriptAndCreateLinks.js +1 -1
  19. package/scripts/cloning/setAdminsFromURL.js +1 -1
  20. package/scripts/cloning/setExternalIdsFromURL.js +1 -1
  21. package/scripts/endorsementFraudDetection/bulkDeleteDuplicateEndorsmentsFromUrl.js +1 -1
  22. package/scripts/landUseGame/export3Ddata.js +1 -1
  23. package/scripts/movePostsToGroupsRecountGroupFromUrl.js +1 -1
  24. package/scripts/recountALLCommunityGroupCounts.js +1 -1
  25. package/scripts/recountCommunitesFromUrl.js +1 -1
  26. package/scripts/recountCommunity.js +1 -1
  27. package/scripts/setLanguageOnGroupCommunitesFromUrl.js +1 -1
  28. package/services/engine/allOurIdeas/aiHelper.d.ts +1 -2
  29. package/services/engine/analytics/manager.cjs +1 -1
  30. package/services/engine/analytics/plausible/manager.cjs +1 -1
  31. package/services/engine/analytics/utils.cjs +1 -1
  32. package/services/engine/notifications/emails_utils.cjs +10 -1
  33. package/services/engine/recommendations/events_manager.cjs +1 -1
  34. package/services/engine/reports/common_utils.cjs +1 -1
  35. package/services/llms/baseChatBot.d.ts +1 -2
  36. package/services/llms/imageGeneration/s3Service.js +72 -11
  37. package/services/scripts/translation_replace_text_from_url.js +1 -1
  38. package/services/utils/redisConnection.cjs +2 -3
  39. package/services/utils/translation_cloning.cjs +1 -1
  40. package/services/utils/translation_helpers.cjs +1 -1
  41. package/tests/emails_utils.test.cjs +130 -0
  42. package/tests/emails_utils.test.d.cts +1 -0
  43. package/tests/imageModel.test.cjs +373 -0
  44. package/tests/imageModel.test.d.cts +1 -0
  45. package/tests/multerSharpS3Compat.test.cjs +229 -0
  46. package/tests/multerSharpS3Compat.test.d.cts +1 -0
  47. package/tests/requestCompat.test.cjs +288 -0
  48. package/tests/requestCompat.test.d.cts +1 -0
  49. package/utils/multerSharpS3Compat.cjs +230 -0
  50. package/utils/multerSharpS3Compat.d.cts +22 -0
  51. package/utils/passportSsoCompat.cjs +15 -0
  52. package/utils/passportSsoCompat.d.cts +2 -0
  53. package/utils/recount_utils.cjs +1 -1
  54. package/utils/requestCompat.cjs +180 -0
  55. package/utils/requestCompat.d.cts +9 -0
@@ -322,7 +322,7 @@ export class SubscriptionManager {
322
322
  return { freeSubscription: true };
323
323
  }
324
324
  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
325
- apiVersion: "2025-04-30.basil",
325
+ apiVersion: "2026-03-25.dahlia",
326
326
  });
327
327
  // Create a PaymentIntent with Stripe
328
328
  const paymentIntent = await stripe.paymentIntents.create({
@@ -360,7 +360,7 @@ export class SubscriptionManager {
360
360
  async handleSuccessfulPayment(paymentIntentId) {
361
361
  try {
362
362
  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
363
- apiVersion: "2025-04-30.basil",
363
+ apiVersion: "2026-03-25.dahlia",
364
364
  });
365
365
  const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
366
366
  if (paymentIntent.status !== "succeeded") {
package/app.js CHANGED
@@ -3,7 +3,7 @@ import session from "express-session";
3
3
  import path from "path";
4
4
  import bodyParser from "body-parser";
5
5
  import { RedisStore } from "connect-redis";
6
- import useragent from "express-useragent";
6
+ import { express as useragentExpress } from "express-useragent";
7
7
  import requestIp from "request-ip";
8
8
  import compression from "compression";
9
9
  import { isbot } from "isbot";
@@ -306,17 +306,20 @@ export class YourPrioritiesApi {
306
306
  redisUrl = redisUrl.replace("redis://h:", "redis://:");
307
307
  }
308
308
  this.redisClient = createClient({
309
- legacyMode: false,
310
309
  url: redisUrl,
311
310
  pingInterval: 10000,
312
- socket: {
313
- tls: redisUrl.startsWith("rediss://"),
314
- rejectUnauthorized: false,
315
- },
311
+ ...(redisUrl.startsWith("rediss://")
312
+ ? {
313
+ socket: {
314
+ tls: true,
315
+ rejectUnauthorized: false,
316
+ },
317
+ }
318
+ : {}),
316
319
  });
317
320
  }
318
321
  else {
319
- this.redisClient = createClient({ legacyMode: false });
322
+ this.redisClient = createClient();
320
323
  }
321
324
  this.redisClient.on("error", (err) => {
322
325
  log.error("App Redis client error", err);
@@ -558,7 +561,7 @@ export class YourPrioritiesApi {
558
561
  }
559
562
  initializeMiddlewares() {
560
563
  this.app.use(this.setupExpresLogger);
561
- this.app.use(useragent.express());
564
+ this.app.use(useragentExpress());
562
565
  this.app.use(requestIp.mw());
563
566
  this.app.use(bodyParser.json({ limit: "150mb", strict: false }));
564
567
  this.app.use(bodyParser.urlencoded({ limit: "150mb", extended: true }));
@@ -667,7 +667,9 @@ const getCommunity = function (req, done) {
667
667
  }
668
668
  },
669
669
  ], function (error) {
670
- log.error("getCommunity", { error: error });
670
+ if (error) {
671
+ log.error("getCommunity", { error: error });
672
+ }
671
673
  done(error, community);
672
674
  });
673
675
  };
@@ -21,7 +21,7 @@ var sanitizeFilename = require("sanitize-filename");
21
21
  var queue = require("../services/workers/queue.cjs");
22
22
  const getAllModeratedItemsByGroup = require("../services/engine/moderation/get_moderation_items.cjs").getAllModeratedItemsByGroup;
23
23
  const performSingleModerationAction = require("../services/engine/moderation/process_moderation_items.cjs").performSingleModerationAction;
24
- const request = require("request");
24
+ const request = require("../utils/requestCompat.cjs");
25
25
  const { updateAnswerTranslation, } = require("../services/utils/translation_helpers.cjs");
26
26
  const { updateSurveyTranslation, } = require("../services/utils/translation_helpers.cjs");
27
27
  const { plausibleStatsProxy, getPlausibleStats, } = require("../services/engine/analytics/plausible/manager.cjs");
@@ -7,7 +7,7 @@ var multerMultipartResolver = multer({ dest: "uploads/" }).single("file");
7
7
  var auth = require("../authorization.cjs");
8
8
  var log = require("../utils/logger.cjs");
9
9
  var toJson = require("../utils/to_json.cjs");
10
- const s3Storage = require("multer-sharp-s3");
10
+ const s3Storage = require("../utils/multerSharpS3Compat.cjs");
11
11
  const crypto = require("crypto");
12
12
  var queue = require("../services/workers/queue.cjs");
13
13
  const aws = require("aws-sdk");
@@ -137,6 +137,9 @@ router.delete("/:groupId/:imageId/deleteImageFromGroup", auth.can("edit group"),
137
137
  imageId: req.params.imageId,
138
138
  });
139
139
  });
140
+ router.delete("/:postId/:imageId/deleteImageFromPost", auth.can("edit post"), (req, res) => {
141
+ models.Image.removeImageFromCollection(req, res);
142
+ });
140
143
  // TODO: Pagination
141
144
  router.get("/:imageId/comments", auth.can("view image"), function (req, res) {
142
145
  models.Point.findAll({
@@ -317,6 +320,14 @@ router.post("/", isAuthenticated, async function (req, res) {
317
320
  }
318
321
  catch (err) {
319
322
  log.error("Error saving image record:", err);
323
+ if (req.file) {
324
+ return storage._removeFile(req, req.file, (cleanupError) => {
325
+ if (cleanupError) {
326
+ log.error("Error cleaning up uploaded image variants:", cleanupError);
327
+ }
328
+ return res.status(500).json({ error: "Failed to save image record" });
329
+ });
330
+ }
320
331
  return res.status(500).json({ error: "Failed to save image record" });
321
332
  }
322
333
  });
package/models/domain.cjs CHANGED
@@ -257,7 +257,7 @@ module.exports = (sequelize, DataTypes) => {
257
257
  provider: "saml",
258
258
  protocol: "saml",
259
259
  strategyObject: "Strategy",
260
- strategyPackage: "passport-saml",
260
+ strategyPackage: "@node-saml/passport-saml",
261
261
  certInPemFormat: true,
262
262
  audience: req.hostname,
263
263
  issuer: domain.secret_api_keys.saml.issuer
package/models/image.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const request = require("request").defaults({ encoding: null });
2
+ const request = require("../utils/requestCompat.cjs").defaults({ encoding: null });
3
3
  const fs = require("fs");
4
4
  const randomstring = require("randomstring");
5
5
  const log = require("../utils/logger.cjs");
@@ -192,6 +192,29 @@ module.exports = (sequelize, DataTypes) => {
192
192
  });
193
193
  return formats;
194
194
  };
195
+ const getBelongsToManyAssociations = () => {
196
+ return Object.entries(Image.associations || {}).filter(([, association]) => association.associationType === "BelongsToMany");
197
+ };
198
+ const hasRemainingCollectionAssociations = async (imageId) => {
199
+ const includes = getBelongsToManyAssociations().map(([associationName]) => ({
200
+ association: associationName,
201
+ required: false,
202
+ through: { attributes: [] },
203
+ }));
204
+ if (!includes.length) {
205
+ return false;
206
+ }
207
+ const imageWithAssociations = await Image.findByPk(imageId, {
208
+ include: includes,
209
+ });
210
+ if (!imageWithAssociations) {
211
+ return false;
212
+ }
213
+ return includes.some(({ association }) => {
214
+ const associatedRecords = imageWithAssociations[association];
215
+ return Array.isArray(associatedRecords) && associatedRecords.length > 0;
216
+ });
217
+ };
195
218
  Image.removeImageFromCollection = async (req, res) => {
196
219
  const imageId = req.params.imageId;
197
220
  const groupId = req.params.groupId;
@@ -199,14 +222,17 @@ module.exports = (sequelize, DataTypes) => {
199
222
  const domainId = req.params.domainId;
200
223
  const postId = req.params.postId;
201
224
  const image = await Image.findByPk(imageId);
225
+ const removeByUserIdOnly = Boolean(req.query.removeByUserIdOnly);
226
+ const requestUserId = req.user?.id;
227
+ const isOwnedByRequestUser = image && requestUserId !== undefined && image.user_id === requestUserId;
202
228
  let removed = false;
229
+ let remainingCollectionAssociations;
203
230
  if (image) {
204
- if (req.query.removeByUserIdOnly) {
205
- if (image.user_id === req.user.id) {
206
- image.deleted = true;
207
- await image.save();
208
- removed = true;
209
- }
231
+ if (removeByUserIdOnly && !isOwnedByRequestUser) {
232
+ log.error("Could not remove image from collection not same user", {
233
+ imageId,
234
+ userId: requestUserId,
235
+ });
210
236
  }
211
237
  else if (groupId) {
212
238
  const group = await sequelize.models.Group.findByPk(groupId);
@@ -271,40 +297,80 @@ module.exports = (sequelize, DataTypes) => {
271
297
  else if (postId) {
272
298
  const post = await sequelize.models.Post.findByPk(postId);
273
299
  if (post) {
274
- const isImageInPost = await sequelize.models.Post.findOne({
300
+ const postWithImage = await sequelize.models.Post.findOne({
275
301
  where: { id: postId },
276
302
  include: [
277
303
  {
278
304
  as: "PostImages",
279
305
  model: sequelize.models.Image,
280
306
  where: { id: imageId },
281
- required: true,
307
+ required: false,
308
+ },
309
+ {
310
+ as: "PostHeaderImages",
311
+ model: sequelize.models.Image,
312
+ where: { id: imageId },
313
+ required: false,
314
+ },
315
+ {
316
+ as: "PostUserImages",
317
+ model: sequelize.models.Image,
318
+ where: { id: imageId },
319
+ required: false,
282
320
  },
283
321
  ],
284
322
  });
285
- if (isImageInPost) {
323
+ if (postWithImage?.PostHeaderImages?.length) {
324
+ await post.removePostHeaderImage(image);
325
+ const remainingHeaderImageCount = typeof post.countPostHeaderImages === "function"
326
+ ? await post.countPostHeaderImages()
327
+ : null;
328
+ if (remainingHeaderImageCount === 0 &&
329
+ post.cover_media_type === "image") {
330
+ post.cover_media_type = "none";
331
+ await post.save();
332
+ }
333
+ removed = true;
334
+ }
335
+ else if (postWithImage?.PostImages?.length) {
286
336
  await post.removePostImage(image);
287
337
  removed = true;
288
338
  }
339
+ else if (postWithImage?.PostUserImages?.length) {
340
+ await post.removePostUserImage(image);
341
+ removed = true;
342
+ }
289
343
  }
290
344
  }
345
+ if (!removed && removeByUserIdOnly && isOwnedByRequestUser) {
346
+ remainingCollectionAssociations = await hasRemainingCollectionAssociations(image.id);
347
+ removed = !remainingCollectionAssociations;
348
+ }
291
349
  if (removed) {
350
+ if (remainingCollectionAssociations === undefined) {
351
+ remainingCollectionAssociations = await hasRemainingCollectionAssociations(image.id);
352
+ }
353
+ if (remainingCollectionAssociations) {
354
+ log.info("Detached shared image from collection", { imageId: image.id });
355
+ return res
356
+ .status(200)
357
+ .json({ message: "Image removed from collection" });
358
+ }
292
359
  image.deleted = true;
293
360
  await image.save();
294
- import("../services/llms/imageGeneration/collectionImageGenerator.js").then(async ({ CollectionImageGenerator }) => {
295
- try {
296
- const mediaManager = new CollectionImageGenerator();
297
- await mediaManager.deleteMediaFormatsUrls(image.formats ? JSON.parse(image.formats) : []);
298
- log.info("Deleted image", { imageId: image.id });
299
- res
300
- .status(200)
301
- .json({ message: "Image removed from collection" });
302
- }
303
- catch (error) {
304
- log.error("Could not delete image", { error });
305
- res.sendStatus(500);
306
- }
307
- });
361
+ try {
362
+ const { S3Service } = await import("../services/llms/imageGeneration/s3Service.js");
363
+ const mediaManager = new S3Service(process.env.CLOUDFLARE_API_KEY, process.env.CLOUDFLARE_ZONE_ID);
364
+ await mediaManager.deleteMediaFormatsUrls(image.formats ? JSON.parse(image.formats) : []);
365
+ }
366
+ catch (error) {
367
+ log.warn("Best-effort image cleanup failed", {
368
+ imageId: image.id,
369
+ error,
370
+ });
371
+ }
372
+ log.info("Deleted image", { imageId: image.id });
373
+ return res.status(200).json({ message: "Image removed from collection" });
308
374
  }
309
375
  else {
310
376
  log.error("Could not remove image from collection");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yrpri/api",
3
- "version": "9.0.220",
3
+ "version": "9.0.222",
4
4
  "license": "MIT",
5
5
  "author": "Robert Bjarnason & Citizens Foundation",
6
6
  "repository": {
@@ -17,126 +17,146 @@
17
17
  "type": "module",
18
18
  "dependencies": {
19
19
  "@airbrake/node": "^2.1.9",
20
- "@aws-sdk/client-s3": "^3.803.0",
21
- "@google-cloud/aiplatform": "^4.1.0",
22
- "@google-cloud/speech": "^7.0.1",
23
- "@google-cloud/storage": "^7.16.0",
24
- "@google-cloud/translate": "^9.0.1",
20
+ "@aws-sdk/client-s3": "^3.1029.0",
21
+ "@google-cloud/aiplatform": "^6.5.0",
22
+ "@google-cloud/speech": "^7.3.0",
23
+ "@google-cloud/storage": "^7.19.0",
24
+ "@google-cloud/translate": "^9.3.0",
25
25
  "@google-cloud/vertexai": "^1.10.0",
26
- "@google-cloud/vision": "^5.1.0",
27
- "@node-saml/passport-saml": "^5.0.1",
28
- "@policysynth/agents": "^1.3.172",
26
+ "@google-cloud/vision": "^5.3.5",
27
+ "@node-saml/passport-saml": "^5.1.0",
28
+ "@policysynth/agents": "^1.3.174",
29
29
  "async": "^3.2.6",
30
30
  "authorized": "^1.0.0",
31
- "aws-sdk": "^2.1692.0",
31
+ "aws-sdk": "^2.1693.0",
32
32
  "axios": "^1.9.0",
33
- "bcrypt": "^5.1.1",
34
- "body-parser": "^2.2.0",
33
+ "bcrypt": "^6.0.0",
34
+ "body-parser": "^2.2.2",
35
35
  "bullmq": "^5.31.0",
36
36
  "bunyan": "^1.8.15",
37
37
  "bunyan-prettystream": "git+https://github.com/rbjarnason/node-bunyan-prettystream.git",
38
38
  "cheerio": "^1.0.0",
39
39
  "color-hash": "^2.0.2",
40
- "compression": "^1.8.0",
40
+ "compression": "^1.8.1",
41
41
  "concat-stream": "^2.0.0",
42
- "connect-redis": "^8.0.3",
43
- "cors": "^2.8.5",
42
+ "connect-redis": "^9.0.0",
43
+ "cors": "^2.8.6",
44
44
  "deep-equal": "^2.2.3",
45
- "docx": "^9.5.0",
45
+ "docx": "^9.6.1",
46
46
  "download-file": "^0.1.5",
47
- "ejs": "^3.1.10",
47
+ "ejs": "^5.0.1",
48
48
  "exceljs": "^4.4.0",
49
- "express": "^5.1.0",
50
- "express-rate-limit": "^7.5.0",
49
+ "express": "^5.2.1",
50
+ "express-rate-limit": "^8.3.2",
51
51
  "express-session": "git+https://github.com/rbjarnason/session.git#upgrade-21",
52
- "express-useragent": "^1.0.15",
52
+ "express-useragent": "^2.1.0",
53
53
  "farmhash": "4.0.1",
54
+ "form-data": "^4.0.4",
54
55
  "html-to-docx": "^1.8.0",
55
- "i18next": "^25.1.1",
56
- "i18next-fs-backend": "^2.6.0",
56
+ "i18next": "^26.0.4",
57
+ "i18next-fs-backend": "^2.6.3",
57
58
  "image-size": "^2.0.2",
58
- "isbot": "^5.1.27",
59
+ "isbot": "^5.1.37",
59
60
  "iso-639-1": "^3.1.5",
60
61
  "jsonrepair": "^3.12.0",
61
62
  "knuth-shuffle-seeded": "^1.0.6",
62
- "lodash": "^4.17.21",
63
- "marked": "^15.0.11",
63
+ "lodash": "^4.18.1",
64
+ "marked": "^18.0.0",
64
65
  "moment": "^2.30.1",
65
- "morgan": "~1.10.0",
66
- "multer": "1.4.5-lts.2",
66
+ "morgan": "^1.10.1",
67
+ "multer": "^2.1.1",
67
68
  "multer-s3": "^3.0.1",
68
- "multer-sharp-s3": "^0.2.5",
69
- "newrelic": "^12.18.2",
70
- "nodemailer": "^7.0.2",
71
- "open-graph-scraper": "^6.10.0",
72
- "openai": "^4.97.0",
73
- "passport": "^0.6.0",
69
+ "newrelic": "^13.18.0",
70
+ "nodemailer": "^8.0.5",
71
+ "open-graph-scraper": "^6.11.0",
72
+ "openai": "^6.34.0",
73
+ "passport": "^0.7.0",
74
74
  "passport-facebook": "^3.0.0",
75
75
  "passport-github": "^1.1.0",
76
76
  "passport-google-oauth": "^2.0.0",
77
77
  "passport-local": "^1.0.0",
78
78
  "passport-openidconnect": "git+https://github.com/rbjarnason/passport-openidconnect.git",
79
- "passport-saml": "git+https://github.com/rbjarnason/passport-saml.git#smarternj",
80
- "passport-sso": "github:rbjarnason/passport-sso#47afa11ce3dc5a3ac7dbc7fb41946213b1100cee",
81
- "pug": "^3.0.3",
79
+ "passport-sso": "github:rbjarnason/passport-sso#a3f8aa7523fd72eb2221db72eb72a81bf1a7c148",
80
+ "pug": "^3.0.4",
82
81
  "randomstring": "^1.3.1",
83
- "rate-limit-redis": "^4.2.0",
84
- "redis": "^4.7.0",
85
- "replicate": "^1.0.1",
86
- "request": "^2.88.2",
82
+ "rate-limit-redis": "^4.3.1",
83
+ "redis": "^5.11.0",
84
+ "replicate": "^1.4.0",
87
85
  "request-ip": "^3.3.0",
88
- "sanitize-filename": "^1.6.3",
86
+ "sanitize-filename": "^1.6.4",
89
87
  "sequelize": "^6.37.7",
90
- "sharp": "^0.34.1",
91
- "sitemap": "^8.0.0",
92
- "stripe": "^18.1.0",
88
+ "sharp": "^0.34.5",
89
+ "sitemap": "^9.0.1",
90
+ "stripe": "^22.0.1",
93
91
  "striptags": "^3.2.0",
94
- "uuid": "^11.1.0",
92
+ "uuid": "^13.0.0",
95
93
  "ws": "^8.18.2"
96
94
  },
97
95
  "devDependencies": {
98
- "@maxmind/geoip2-node": "^6.1.0",
99
- "@tsconfig/node22": "^22.0.1",
100
- "@types/bcrypt": "^5.0.2",
96
+ "@maxmind/geoip2-node": "^6.3.4",
97
+ "@tsconfig/node22": "^22.0.5",
98
+ "@types/bcrypt": "^6.0.0",
101
99
  "@types/bunyan": "^1.8.11",
102
100
  "@types/bunyan-prettystream": "^0.1.35",
103
- "@types/compression": "^1.7.5",
104
- "@types/cors": "^2.8.17",
105
- "@types/express": "^5.0.1",
106
- "@types/express-session": "^1.18.1",
101
+ "@types/compression": "^1.8.1",
102
+ "@types/cors": "^2.8.19",
103
+ "@types/express": "^5.0.6",
104
+ "@types/express-session": "^1.18.2",
107
105
  "@types/express-useragent": "^1.0.5",
108
- "@types/lodash": "^4.17.16",
109
- "@types/marked": "^6.0.0",
110
- "@types/morgan": "^1.9.9",
111
- "@types/node": "^22.15.12",
106
+ "@types/lodash": "^4.17.24",
107
+ "@types/morgan": "^1.9.10",
108
+ "@types/node": "^22.19.17",
112
109
  "@types/passport": "^1.0.17",
113
110
  "@types/request-ip": "^0.0.41",
114
- "@types/sharp": "^0.32.0",
115
111
  "@types/uuid": "^10.0.0",
116
112
  "@types/ws": "^8.18.1",
117
113
  "axios": "^1.9.0",
118
114
  "copyfiles": "^2.4.1",
119
- "csv-parse": "^5.6.0",
115
+ "csv-parse": "^6.2.1",
120
116
  "diacritics": "^1.3.0",
121
- "jshint": "^2.13.6",
122
117
  "jslint": "^0.12.1",
123
118
  "ncp": "^2.0.0",
124
- "nodemon": "^3.1.10",
119
+ "nodemon": "^3.1.14",
125
120
  "random-words": "^2.0.1",
126
- "sequelize-cli": "^6.6.3",
121
+ "tar": "^7.5.13",
127
122
  "temp": "^0.9.4",
128
123
  "ts-node": "^10.9.2",
129
- "typescript": "^5.8.3",
130
- "uuid": "^11.1.0",
124
+ "typescript": "^5.9.3",
131
125
  "wordwrap": "^1.0.0",
132
126
  "ws": "^8.18.2",
133
127
  "yamljs": "^0.3.0"
134
128
  },
129
+ "overrides": {
130
+ "basic-ftp": "^5.2.2",
131
+ "@xmldom/xmldom": "0.8.12",
132
+ "validator": "13.15.35",
133
+ "path-to-regexp": "8.4.2",
134
+ "picomatch": "2.3.2",
135
+ "copyfiles": {
136
+ "minimatch": "3.1.4"
137
+ },
138
+ "readdir-glob": {
139
+ "minimatch": "5.1.9"
140
+ },
141
+ "@types/request": {
142
+ "form-data": "2.5.4"
143
+ },
144
+ "graphql-request": {
145
+ "form-data": "3.0.4"
146
+ },
147
+ "prebuild-install": {
148
+ "tar-fs": "2.1.4"
149
+ },
150
+ "prebuildify": {
151
+ "tar-fs": "2.1.4"
152
+ }
153
+ },
135
154
  "scripts": {
136
155
  "copyInLocalAgents": "cp -R ../../policy-synth/agents/ts-out/* ./node_modules/@policysynth/agents/;cp ../../policy-synth/agents/src/*.d.ts ./node_modules/@policysynth/agents/;",
137
156
  "publish_live_with_copy": "npm run build:dev;copyfiles './src/utils/**/*.d.ts' './src/controllers/**/*.d.ts' './src/agents/**/*.d.ts' './src/models/**/*.d.ts' './src/services/controllers/**/*.d.ts' './src/services/models/**/*.d.ts' 'ts-out/';npm pack && node repack && node publish.js https://registry.npmjs.org/",
138
157
  "publish_live": "npm run build:dev;npm pack && node repack && node publish.js https://registry.npmjs.org/",
139
158
  "publish_local": "npm run build;npm pack && node repack && node publish.js http://localhost:4873",
159
+ "test": "node --test ./src/tests/*.test.cjs",
140
160
  "start": "nodemon -e ts ts-out/server.js",
141
161
  "watch-start": "DEBUG=router:* tsc --outDir ./ts-out -w & nodemon -q ./ts-out/server.js",
142
162
  "dev": "nodemon --config nodemon.json ./ts-out/server.js",
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const cloneTranslationForConfig = require('../../services/utils/translation_cloning').cloneTranslationForConfig;
7
7
  const userId = process.argv[2];
8
8
  const type = process.argv[3];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const copyCommunityWithEverything = require('../../utils/copy_utils').copyCommunityWithEverything;
7
7
  const communityId = process.argv[2];
8
8
  const domainId = process.argv[3];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const copyCommunityWithEverything = require('../../utils/copy_utils').copyCommunityWithEverything;
7
7
  const updateTranslation = require('../../services/utils/translation_helpers').updateTranslation;
8
8
  const domainId = process.argv[2];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const copyCommunityNoUsersNoEndorsementsNoPoints = require('../../utils/copy_utils').copyCommunityNoUsersNoEndorsementsNoPoints;
7
7
  const updateTranslation = require('../../services/utils/translation_helpers').updateTranslation;
8
8
  const domainId = process.argv[2];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const copyCommunityWithEverything = require('../../utils/copy_utils').copyCommunityWithEverything;
7
7
  const updateTranslation = require('../../services/utils/translation_helpers').updateTranslation;
8
8
  const domainId = process.argv[2];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const cloneTranslationForConfig = require('../../services/utils/translation_cloning').cloneTranslationForConfig;
7
7
  const userId = process.argv[2];
8
8
  const type = process.argv[3];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const cloneTranslationForConfig = require('../../services/utils/translation_cloning').cloneTranslationForConfig;
7
7
  const userId = process.argv[2];
8
8
  const type = process.argv[3];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const cloneTranslationForConfig = require('../../services/utils/translation_cloning').cloneTranslationForConfig;
7
7
  const userId = process.argv[2];
8
8
  const urlToConfig = process.argv[3];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const deepCopyCommunityOnlyStructureWithAdminsAndPosts = require('../../utils/copy_utils').deepCopyCommunityOnlyStructureWithAdminsAndPosts;
7
7
  const updateTranslation = require('../../services/utils/translation_helpers').updateTranslation;
8
8
  let domainId = process.argv[2];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const deepCopyCommunityOnlyStructureWithAdminsAndPosts = require('../../utils/copy_utils').deepCopyCommunityOnlyStructureWithAdminsAndPosts;
7
7
  const updateTranslation = require('../../services/utils/translation_helpers').updateTranslation;
8
8
  let domainId = process.argv[2];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const cloneTranslationForConfig = require('../../services/utils/translation_cloning').cloneTranslationForConfig;
7
7
  const userId = process.argv[2];
8
8
  const urlToConfig = process.argv[3];
@@ -2,7 +2,7 @@ const models = require('../../models/index.cjs');
2
2
  const async = require('async');
3
3
  const _ = require('lodash');
4
4
  const fs = require('fs');
5
- const request = require('request');
5
+ const request = require("../../utils/requestCompat.cjs");
6
6
  const cloneTranslationForConfig = require('../../services/utils/translation_cloning').cloneTranslationForConfig;
7
7
  const userId = process.argv[2];
8
8
  const urlToConfig = process.argv[3];