@friggframework/core 2.0.0-next.12 → 2.0.0-next.120

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 (410) hide show
  1. package/.eslintrc.json +18 -1
  2. package/CLAUDE.md +830 -0
  3. package/README.md +996 -50
  4. package/admin-scripts/index.js +52 -0
  5. package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
  6. package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
  7. package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
  8. package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
  9. package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
  10. package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
  11. package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
  12. package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
  13. package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
  14. package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
  15. package/application/commands/README.md +451 -0
  16. package/application/commands/admin-script-commands.js +359 -0
  17. package/application/commands/credential-commands.js +262 -0
  18. package/application/commands/entity-commands.js +294 -0
  19. package/application/commands/integration-commands.js +419 -0
  20. package/application/commands/integration-mapping-commands.js +25 -0
  21. package/application/commands/process-commands.js +135 -0
  22. package/application/commands/report-commands.js +188 -0
  23. package/application/commands/scheduler-commands.js +263 -0
  24. package/application/commands/usage-commands.js +56 -0
  25. package/application/commands/user-commands.js +312 -0
  26. package/application/index.js +83 -0
  27. package/artifacts/repositories/artifact-repository-factory.js +19 -0
  28. package/artifacts/repositories/artifact-repository-interface.js +27 -0
  29. package/artifacts/repositories/artifact-repository-local.js +42 -0
  30. package/artifacts/repositories/artifact-repository-s3.js +61 -0
  31. package/assertions/index.js +0 -3
  32. package/core/CLAUDE.md +715 -0
  33. package/core/Worker.js +55 -24
  34. package/core/create-handler.js +121 -38
  35. package/core/index.js +8 -1
  36. package/core/invocation-scope.js +225 -0
  37. package/core/parameters-to-env.js +257 -0
  38. package/core/secrets-to-env.js +7 -6
  39. package/core/ssm-preload.mjs +34 -0
  40. package/credential/repositories/credential-active-type.js +32 -0
  41. package/credential/repositories/credential-repository-documentdb.js +355 -0
  42. package/credential/repositories/credential-repository-factory.js +54 -0
  43. package/credential/repositories/credential-repository-interface.js +113 -0
  44. package/credential/repositories/credential-repository-mongo.js +294 -0
  45. package/credential/repositories/credential-repository-postgres.js +312 -0
  46. package/credential/repositories/credential-repository.js +300 -0
  47. package/credential/use-cases/get-credential-for-user.js +25 -0
  48. package/credential/use-cases/update-authentication-status.js +15 -0
  49. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  50. package/database/adapters/lambda-invoker.js +97 -0
  51. package/database/config.js +147 -0
  52. package/database/documentdb-encryption-service.js +334 -0
  53. package/database/documentdb-utils.js +196 -0
  54. package/database/encryption/README.md +863 -0
  55. package/database/encryption/documentdb-encryption-service.md +3575 -0
  56. package/database/encryption/encryption-schema-registry.js +404 -0
  57. package/database/encryption/field-encryption-service.js +254 -0
  58. package/database/encryption/integration-mapping-encryption.js +97 -0
  59. package/database/encryption/logger.js +82 -0
  60. package/database/encryption/prisma-encryption-extension.js +241 -0
  61. package/database/index.js +21 -21
  62. package/database/prisma.js +182 -0
  63. package/database/repositories/health-check-repository-documentdb.js +138 -0
  64. package/database/repositories/health-check-repository-factory.js +48 -0
  65. package/database/repositories/health-check-repository-interface.js +82 -0
  66. package/database/repositories/health-check-repository-mongodb.js +89 -0
  67. package/database/repositories/health-check-repository-postgres.js +82 -0
  68. package/database/repositories/migration-status-repository-s3.js +137 -0
  69. package/database/use-cases/check-database-health-use-case.js +29 -0
  70. package/database/use-cases/check-database-state-use-case.js +81 -0
  71. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  72. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  73. package/database/use-cases/get-migration-status-use-case.js +93 -0
  74. package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
  75. package/database/use-cases/run-database-migration-use-case.js +139 -0
  76. package/database/use-cases/test-encryption-use-case.js +253 -0
  77. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  78. package/database/utils/mongodb-collection-utils.js +94 -0
  79. package/database/utils/mongodb-schema-init.js +108 -0
  80. package/database/utils/prisma-runner.js +491 -0
  81. package/database/utils/prisma-schema-parser.js +182 -0
  82. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  83. package/encrypt/Cryptor.js +34 -168
  84. package/encrypt/index.js +1 -2
  85. package/errors/client-safe-error.js +26 -0
  86. package/errors/fetch-error.js +59 -57
  87. package/errors/index.js +6 -0
  88. package/errors/mapping-already-exists-error.js +14 -0
  89. package/generated/prisma-mongodb/client.d.ts +1 -0
  90. package/generated/prisma-mongodb/client.js +5 -0
  91. package/generated/prisma-mongodb/default.d.ts +1 -0
  92. package/generated/prisma-mongodb/default.js +5 -0
  93. package/generated/prisma-mongodb/edge.d.ts +1 -0
  94. package/generated/prisma-mongodb/edge.js +386 -0
  95. package/generated/prisma-mongodb/index-browser.js +368 -0
  96. package/generated/prisma-mongodb/index.d.ts +27065 -0
  97. package/generated/prisma-mongodb/index.js +411 -0
  98. package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  99. package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  100. package/generated/prisma-mongodb/package.json +183 -0
  101. package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
  102. package/generated/prisma-mongodb/runtime/edge.js +35 -0
  103. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  104. package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
  105. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  106. package/generated/prisma-mongodb/runtime/library.js +147 -0
  107. package/generated/prisma-mongodb/runtime/react-native.js +84 -0
  108. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
  109. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
  110. package/generated/prisma-mongodb/schema.prisma +455 -0
  111. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
  112. package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
  113. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  114. package/generated/prisma-mongodb/wasm.js +393 -0
  115. package/generated/prisma-postgresql/client.d.ts +1 -0
  116. package/generated/prisma-postgresql/client.js +5 -0
  117. package/generated/prisma-postgresql/default.d.ts +1 -0
  118. package/generated/prisma-postgresql/default.js +5 -0
  119. package/generated/prisma-postgresql/edge.d.ts +1 -0
  120. package/generated/prisma-postgresql/edge.js +407 -0
  121. package/generated/prisma-postgresql/index-browser.js +389 -0
  122. package/generated/prisma-postgresql/index.d.ts +29904 -0
  123. package/generated/prisma-postgresql/index.js +432 -0
  124. package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
  125. package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
  126. package/generated/prisma-postgresql/package.json +183 -0
  127. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  128. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  129. package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
  130. package/generated/prisma-postgresql/runtime/edge.js +35 -0
  131. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  132. package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
  133. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  134. package/generated/prisma-postgresql/runtime/library.js +147 -0
  135. package/generated/prisma-postgresql/runtime/react-native.js +84 -0
  136. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
  137. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
  138. package/generated/prisma-postgresql/schema.prisma +436 -0
  139. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
  140. package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
  141. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  142. package/generated/prisma-postgresql/wasm.js +414 -0
  143. package/handlers/WEBHOOKS.md +682 -0
  144. package/handlers/app-definition-loader.js +103 -0
  145. package/handlers/app-handler-helpers.js +20 -6
  146. package/handlers/backend-utils.js +272 -46
  147. package/handlers/database-migration-handler.js +236 -0
  148. package/handlers/integration-event-dispatcher.js +68 -0
  149. package/handlers/middleware/admin-auth.js +73 -0
  150. package/handlers/routers/HEALTHCHECK.md +342 -0
  151. package/handlers/routers/auth.js +4 -15
  152. package/handlers/routers/db-migration.handler.js +29 -0
  153. package/handlers/routers/db-migration.js +329 -0
  154. package/handlers/routers/health.js +518 -0
  155. package/handlers/routers/integration-defined-routers.js +85 -10
  156. package/handlers/routers/integration-webhook-routers.js +87 -0
  157. package/handlers/routers/user.js +27 -5
  158. package/handlers/routers/websocket.js +31 -9
  159. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  160. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  161. package/handlers/workers/db-migration.js +438 -0
  162. package/handlers/workers/dlq-processor.js +89 -0
  163. package/handlers/workers/integration-defined-workers.js +13 -7
  164. package/index.js +123 -47
  165. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -0
  166. package/infrastructure/scheduler/index.js +33 -0
  167. package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
  168. package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
  169. package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
  170. package/integrations/EXTENSIONS.md +240 -0
  171. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  172. package/integrations/extension.js +254 -0
  173. package/integrations/index.js +20 -10
  174. package/integrations/integration-base.js +777 -74
  175. package/integrations/integration-router.js +399 -180
  176. package/integrations/options.js +1 -1
  177. package/integrations/repositories/config-patch-shared.js +43 -0
  178. package/integrations/repositories/integration-mapping-query-pipeline.js +152 -0
  179. package/integrations/repositories/integration-mapping-query.js +193 -0
  180. package/integrations/repositories/integration-mapping-repository-documentdb.js +406 -0
  181. package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
  182. package/integrations/repositories/integration-mapping-repository-interface.js +183 -0
  183. package/integrations/repositories/integration-mapping-repository-mongo.js +284 -0
  184. package/integrations/repositories/integration-mapping-repository-postgres.js +403 -0
  185. package/integrations/repositories/integration-mapping-repository.js +185 -0
  186. package/integrations/repositories/integration-repository-documentdb.js +354 -0
  187. package/integrations/repositories/integration-repository-factory.js +51 -0
  188. package/integrations/repositories/integration-repository-interface.js +219 -0
  189. package/integrations/repositories/integration-repository-mongo.js +502 -0
  190. package/integrations/repositories/integration-repository-postgres.js +550 -0
  191. package/integrations/repositories/process-repository-documentdb.js +311 -0
  192. package/integrations/repositories/process-repository-factory.js +53 -0
  193. package/integrations/repositories/process-repository-interface.js +136 -0
  194. package/integrations/repositories/process-repository-mongo.js +262 -0
  195. package/integrations/repositories/process-repository-postgres.js +380 -0
  196. package/integrations/repositories/process-update-ops-shared.js +112 -0
  197. package/integrations/repositories/report-id.js +13 -0
  198. package/integrations/tests/doubles/config-capturing-integration.js +81 -0
  199. package/integrations/tests/doubles/dummy-integration-class.js +113 -0
  200. package/integrations/tests/doubles/test-integration-repository.js +146 -0
  201. package/integrations/use-cases/add-entities-to-integration.js +92 -0
  202. package/integrations/use-cases/create-integration.js +253 -0
  203. package/integrations/use-cases/create-process.js +130 -0
  204. package/integrations/use-cases/delete-integration-for-user.js +130 -0
  205. package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
  206. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
  207. package/integrations/use-cases/get-integration-for-user.js +78 -0
  208. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  209. package/integrations/use-cases/get-integration-instance.js +83 -0
  210. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  211. package/integrations/use-cases/get-possible-integrations.js +27 -0
  212. package/integrations/use-cases/get-process.js +89 -0
  213. package/integrations/use-cases/index.js +19 -0
  214. package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
  215. package/integrations/use-cases/load-integration-context.js +71 -0
  216. package/integrations/use-cases/patch-integration-config.js +39 -0
  217. package/integrations/use-cases/process-errors.js +28 -0
  218. package/integrations/use-cases/remove-entities-from-integration.js +70 -0
  219. package/integrations/use-cases/update-integration-config.js +32 -0
  220. package/integrations/use-cases/update-integration-messages.js +44 -0
  221. package/integrations/use-cases/update-integration-status.js +32 -0
  222. package/integrations/use-cases/update-integration.js +92 -0
  223. package/integrations/use-cases/update-process-metrics.js +222 -0
  224. package/integrations/use-cases/update-process-state.js +163 -0
  225. package/integrations/utils/assert-entity-ids-input.js +42 -0
  226. package/integrations/utils/map-integration-dto.js +37 -0
  227. package/jest-global-setup-noop.js +3 -0
  228. package/jest-global-teardown-noop.js +3 -0
  229. package/jest.config.js +2 -0
  230. package/logs/.eslintrc.json +26 -1
  231. package/logs/__fixtures__/events.js +82 -0
  232. package/logs/__fixtures__/matchers.js +45 -0
  233. package/logs/__fixtures__/secrets.js +59 -0
  234. package/logs/__fixtures__/vectors.js +329 -0
  235. package/logs/__fixtures__/with-env.js +45 -0
  236. package/logs/context.js +109 -0
  237. package/logs/contract-keys.js +67 -0
  238. package/logs/debug-shims.js +46 -0
  239. package/logs/denied-keys.js +21 -0
  240. package/logs/index.js +14 -3
  241. package/logs/jest-logger-setup.js +25 -0
  242. package/logs/levels.js +71 -0
  243. package/logs/logger-runtime.js +137 -0
  244. package/logs/logger.js +134 -46
  245. package/logs/record.js +276 -0
  246. package/logs/redact.js +328 -0
  247. package/logs/serialize.js +329 -0
  248. package/logs/sinks.js +93 -0
  249. package/logs/summarize-event.js +163 -0
  250. package/{module-plugin → modules}/index.js +0 -10
  251. package/modules/module-factory.js +56 -0
  252. package/modules/module.js +320 -0
  253. package/modules/repositories/module-repository-documentdb.js +350 -0
  254. package/modules/repositories/module-repository-factory.js +40 -0
  255. package/modules/repositories/module-repository-interface.js +145 -0
  256. package/modules/repositories/module-repository-mongo.js +436 -0
  257. package/modules/repositories/module-repository-postgres.js +481 -0
  258. package/modules/repositories/module-repository.js +369 -0
  259. package/modules/requester/api-key.js +52 -0
  260. package/modules/requester/oauth-2.js +561 -0
  261. package/modules/requester/requester.js +605 -0
  262. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  263. package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
  264. package/modules/tests/doubles/test-module-factory.js +16 -0
  265. package/modules/tests/doubles/test-module-repository.js +39 -0
  266. package/modules/use-cases/get-entities-for-user.js +32 -0
  267. package/modules/use-cases/get-entity-options-by-id.js +71 -0
  268. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  269. package/modules/use-cases/get-module-instance-from-type.js +34 -0
  270. package/modules/use-cases/get-module.js +74 -0
  271. package/modules/use-cases/process-authorization-callback.js +294 -0
  272. package/modules/use-cases/refresh-entity-options.js +72 -0
  273. package/modules/use-cases/test-module-auth.js +72 -0
  274. package/modules/utils/map-module-dto.js +20 -0
  275. package/modules/utils/to-credential-id.js +14 -0
  276. package/package.json +91 -52
  277. package/prisma-mongodb/schema.prisma +455 -0
  278. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  279. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  280. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  281. package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
  282. package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
  283. package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
  284. package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
  285. package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
  286. package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
  287. package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
  288. package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
  289. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  290. package/prisma-postgresql/schema.prisma +436 -0
  291. package/queues/queue-delivery.js +41 -0
  292. package/queues/queuer-util.js +89 -21
  293. package/reporting/README.md +154 -0
  294. package/reporting/builtin-reports.js +6 -0
  295. package/reporting/index.js +13 -0
  296. package/reporting/report-base.js +49 -0
  297. package/reporting/reports/integrations-report.js +221 -0
  298. package/syncs/manager.js +468 -443
  299. package/syncs/repositories/sync-repository-documentdb.js +240 -0
  300. package/syncs/repositories/sync-repository-factory.js +43 -0
  301. package/syncs/repositories/sync-repository-interface.js +109 -0
  302. package/syncs/repositories/sync-repository-mongo.js +239 -0
  303. package/syncs/repositories/sync-repository-postgres.js +319 -0
  304. package/syncs/sync.js +0 -1
  305. package/telemetry/README.md +331 -0
  306. package/telemetry/bind-telemetry-context.js +77 -0
  307. package/telemetry/canonical-counters.js +52 -0
  308. package/telemetry/exporters.js +85 -0
  309. package/telemetry/index.js +26 -0
  310. package/telemetry/instrument-handler.js +104 -0
  311. package/telemetry/no-op-telemetry.js +71 -0
  312. package/telemetry/north-star.js +103 -0
  313. package/telemetry/otel-telemetry.js +232 -0
  314. package/telemetry/plugin-subscribers.js +77 -0
  315. package/telemetry/telemetry-config.js +120 -0
  316. package/telemetry/telemetry-context.js +51 -0
  317. package/telemetry/telemetry-event-bus.js +58 -0
  318. package/telemetry/telemetry-runtime.js +164 -0
  319. package/telemetry/telemetry-service.js +52 -0
  320. package/telemetry/usage-rollup-subscriber.js +116 -0
  321. package/token/repositories/token-repository-documentdb.js +137 -0
  322. package/token/repositories/token-repository-factory.js +40 -0
  323. package/token/repositories/token-repository-interface.js +131 -0
  324. package/token/repositories/token-repository-mongo.js +219 -0
  325. package/token/repositories/token-repository-postgres.js +264 -0
  326. package/token/repositories/token-repository.js +219 -0
  327. package/types/associations/index.d.ts +0 -17
  328. package/types/core/index.d.ts +12 -4
  329. package/types/database/index.d.ts +10 -2
  330. package/types/encrypt/index.d.ts +5 -3
  331. package/types/errors/index.d.ts +24 -10
  332. package/types/integrations/index.d.ts +3 -8
  333. package/types/logs/index.d.ts +61 -2
  334. package/types/module-plugin/index.d.ts +20 -69
  335. package/types/syncs/index.d.ts +0 -17
  336. package/usage/README.md +54 -0
  337. package/usage/index.js +17 -0
  338. package/usage/repositories/usage-repository-documentdb.js +194 -0
  339. package/usage/repositories/usage-repository-factory.js +25 -0
  340. package/usage/repositories/usage-repository-interface.js +37 -0
  341. package/usage/repositories/usage-repository-prisma.js +146 -0
  342. package/usage/tracked-metrics.js +38 -0
  343. package/usage/usage-windows.js +24 -0
  344. package/user/repositories/user-repository-documentdb.js +426 -0
  345. package/user/repositories/user-repository-factory.js +52 -0
  346. package/user/repositories/user-repository-interface.js +214 -0
  347. package/user/repositories/user-repository-mongo.js +323 -0
  348. package/user/repositories/user-repository-postgres.js +377 -0
  349. package/user/tests/doubles/test-user-repository.js +72 -0
  350. package/user/use-cases/authenticate-user.js +143 -0
  351. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  352. package/user/use-cases/create-individual-user.js +61 -0
  353. package/user/use-cases/create-organization-user.js +47 -0
  354. package/user/use-cases/create-token-for-user-id.js +30 -0
  355. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  356. package/user/use-cases/get-user-from-bearer-token.js +82 -0
  357. package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
  358. package/user/use-cases/login-user.js +122 -0
  359. package/user/user.js +125 -0
  360. package/utils/backend-path.js +38 -0
  361. package/utils/index.js +6 -0
  362. package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
  363. package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
  364. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  365. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  366. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  367. package/websocket/repositories/websocket-connection-repository.js +161 -0
  368. package/assertions/is-equal.js +0 -17
  369. package/associations/model.js +0 -54
  370. package/database/models/IndividualUser.js +0 -76
  371. package/database/models/OrganizationUser.js +0 -29
  372. package/database/models/State.js +0 -9
  373. package/database/models/Token.js +0 -70
  374. package/database/models/UserModel.js +0 -7
  375. package/database/models/WebsocketConnection.js +0 -49
  376. package/database/mongo.js +0 -45
  377. package/database/mongoose.js +0 -5
  378. package/encrypt/Cryptor.test.js +0 -32
  379. package/encrypt/encrypt.js +0 -132
  380. package/encrypt/encrypt.test.js +0 -1069
  381. package/encrypt/test-encrypt.js +0 -107
  382. package/errors/base-error.test.js +0 -32
  383. package/errors/fetch-error.test.js +0 -79
  384. package/errors/halt-error.test.js +0 -11
  385. package/errors/validation-errors.test.js +0 -120
  386. package/handlers/routers/middleware/loadUser.js +0 -15
  387. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  388. package/integrations/create-frigg-backend.js +0 -31
  389. package/integrations/integration-factory.js +0 -251
  390. package/integrations/integration-mapping.js +0 -43
  391. package/integrations/integration-model.js +0 -46
  392. package/integrations/integration-user.js +0 -144
  393. package/integrations/test/integration-base.test.js +0 -144
  394. package/lambda/TimeoutCatcher.test.js +0 -68
  395. package/logs/logger.test.js +0 -76
  396. package/module-plugin/auther.js +0 -393
  397. package/module-plugin/credential.js +0 -22
  398. package/module-plugin/entity-manager.js +0 -70
  399. package/module-plugin/entity.js +0 -46
  400. package/module-plugin/manager.js +0 -169
  401. package/module-plugin/module-factory.js +0 -61
  402. package/module-plugin/requester/api-key.js +0 -36
  403. package/module-plugin/requester/oauth-2.js +0 -219
  404. package/module-plugin/requester/requester.js +0 -165
  405. package/module-plugin/requester/requester.test.js +0 -28
  406. package/module-plugin/test/auther.test.js +0 -97
  407. package/syncs/model.js +0 -62
  408. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  409. /package/{module-plugin → modules}/requester/basic.js +0 -0
  410. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -1,61 +0,0 @@
1
- const { Entity } = require('./entity');
2
- const { Auther } = require('./auther');
3
-
4
- class ModuleFactory {
5
- constructor(...params) {
6
- this.moduleDefinitions = params;
7
- this.moduleTypes = this.moduleDefinitions.map((def) => def.moduleName);
8
- }
9
-
10
- async getEntitiesForUser(userId) {
11
- let results = [];
12
- for (const moduleDefinition of this.moduleDefinitions) {
13
- const moduleInstance = await Auther.getInstance({
14
- userId,
15
- definition: moduleDefinition,
16
- });
17
- const list = await moduleInstance.getEntitiesForUserId(userId);
18
- results.push(...list);
19
- }
20
- return results;
21
- }
22
-
23
- checkIsValidType(entityType) {
24
- return this.moduleTypes.includes(entityType);
25
- }
26
-
27
- getModuleDefinitionFromTypeName(typeName) {
28
- return;
29
- }
30
-
31
- async getModuleInstanceFromEntityId(entityId, userId) {
32
- const entity = await Entity.findById(entityId);
33
- const moduleDefinition = this.moduleDefinitions.find(
34
- (def) =>
35
- entity.toJSON()['__t'] ===
36
- Auther.getEntityModelFromDefinition(def).modelName
37
- );
38
- if (!moduleDefinition) {
39
- throw new Error(
40
- 'Module definition not found for entity type: ' + entity['__t']
41
- );
42
- }
43
- return await Auther.getInstance({
44
- userId,
45
- entityId,
46
- definition: moduleDefinition,
47
- });
48
- }
49
-
50
- async getInstanceFromTypeName(typeName, userId) {
51
- const moduleDefinition = this.moduleDefinitions.find(
52
- (def) => def.getName() === typeName
53
- );
54
- return await Auther.getInstance({
55
- userId,
56
- definition: moduleDefinition,
57
- });
58
- }
59
- }
60
-
61
- module.exports = { ModuleFactory };
@@ -1,36 +0,0 @@
1
- const { Requester } = require('./requester');
2
- const { ModuleConstants } = require('../ModuleConstants');
3
-
4
-
5
- class ApiKeyRequester extends Requester {
6
-
7
- static requesterType = ModuleConstants.authType.apiKey;
8
-
9
- constructor(params) {
10
- super(params);
11
- this.requesterType = 'apiKey';
12
- this.API_KEY_NAME = 'key';
13
- this.API_KEY_VALUE = null;
14
- }
15
-
16
- async addAuthHeaders(headers) {
17
- if (this.API_KEY_VALUE) {
18
- headers[this.API_KEY_NAME] = this.API_KEY_VALUE;
19
- }
20
- return headers;
21
- }
22
-
23
- isAuthenticated() {
24
- return (
25
- this.API_KEY_VALUE !== null &&
26
- this.API_KEY_VALUE !== undefined &&
27
- this.API_KEY_VALUE.trim().length() > 0
28
- );
29
- }
30
-
31
- setApiKey(api_key) {
32
- this.API_KEY_VALUE = api_key;
33
- }
34
- }
35
-
36
- module.exports = { ApiKeyRequester };
@@ -1,219 +0,0 @@
1
- const { Requester } = require('./requester');
2
- const { get } = require('../../assertions');
3
- const { ModuleConstants } = require('../ModuleConstants');
4
-
5
- class OAuth2Requester extends Requester {
6
-
7
- static requesterType = ModuleConstants.authType.oauth2;
8
-
9
- constructor(params) {
10
- super(params);
11
- this.DLGT_TOKEN_UPDATE = 'TOKEN_UPDATE';
12
- this.DLGT_TOKEN_DEAUTHORIZED = 'TOKEN_DEAUTHORIZED';
13
-
14
- this.delegateTypes.push(this.DLGT_TOKEN_UPDATE);
15
- this.delegateTypes.push(this.DLGT_TOKEN_DEAUTHORIZED);
16
-
17
- this.grant_type = get(params, 'grant_type', 'authorization_code');
18
- this.client_id = get(params, 'client_id', null);
19
- this.client_secret = get(params, 'client_secret', null);
20
- this.redirect_uri = get(params, 'redirect_uri', null);
21
- this.scope = get(params, 'scope', null);
22
- this.authorizationUri = get(params, 'authorizationUri', null);
23
- this.baseURL = get(params, 'baseURL', null);
24
- this.access_token = get(params, 'access_token', null);
25
- this.refresh_token = get(params, 'refresh_token', null);
26
- this.accessTokenExpire = get(params, 'accessTokenExpire', null);
27
- this.refreshTokenExpire = get(params, 'refreshTokenExpire', null);
28
- this.audience = get(params, 'audience', null);
29
- this.username = get(params, 'username', null);
30
- this.password = get(params, 'password', null);
31
- this.state = get(params, 'state', null);
32
-
33
- this.isRefreshable = true;
34
- }
35
-
36
- async setTokens(params) {
37
- this.access_token = get(params, 'access_token');
38
- this.refresh_token = get(params, 'refresh_token', null);
39
- const accessExpiresIn = get(params, 'expires_in', null);
40
- const refreshExpiresIn = get(
41
- params,
42
- 'x_refresh_token_expires_in',
43
- null
44
- );
45
-
46
- this.accessTokenExpire = new Date(Date.now() + accessExpiresIn * 1000);
47
- this.refreshTokenExpire = new Date(Date.now() + refreshExpiresIn * 1000);
48
-
49
- await this.notify(this.DLGT_TOKEN_UPDATE);
50
- }
51
-
52
- getAuthorizationUri() {
53
- return this.authorizationUri;
54
- }
55
-
56
- getAuthorizationRequirements() {
57
- return {
58
- url: this.getAuthorizationUri(),
59
- type: 'oauth2',
60
- };
61
- }
62
-
63
- // this.client_id, this.client_secret, this.redirect_uri, and this.tokenUri
64
- // will need to be defined in the child class before super(params)
65
- async getTokenFromCode(code) {
66
- const params = new URLSearchParams();
67
- params.append('grant_type', 'authorization_code');
68
- params.append('client_id', this.client_id);
69
- params.append('client_secret', this.client_secret);
70
- params.append('redirect_uri', this.redirect_uri);
71
- params.append('scope', this.scope);
72
- params.append('code', code);
73
- const options = {
74
- body: params,
75
- headers: {
76
- 'Content-Type': 'application/x-www-form-urlencoded',
77
- },
78
- url: this.tokenUri,
79
- };
80
- const response = await this._post(options, false);
81
- await this.setTokens(response);
82
- return response;
83
- }
84
-
85
- // REPLACE getTokenFromCode IN THE CHILD IF NEEDED
86
- // this.client_id, this.client_secret, this.redirect_uri, and this.tokenUri
87
- // will need to be defined in the child class before super(params)
88
- async getTokenFromCodeBasicAuthHeader(code) {
89
- const params = new URLSearchParams();
90
- params.append('grant_type', 'authorization_code');
91
- params.append('client_id', this.client_id);
92
- params.append('redirect_uri', this.redirect_uri);
93
- params.append('code', code);
94
-
95
- const options = {
96
- body: params,
97
- headers: {
98
- 'Content-Type': 'application/x-www-form-urlencoded',
99
- Authorization: `Basic ${Buffer.from(
100
- `${this.client_id}:${this.client_secret}`
101
- ).toString('base64')}`,
102
- },
103
- url: this.tokenUri,
104
- };
105
-
106
- const response = await this._post(options, false);
107
- await this.setTokens(response);
108
- return response;
109
- }
110
-
111
- // this.client_id, this.client_secret, this.redirect_uri, and this.tokenUri
112
- // will need to be defined in the child class before super(params)
113
- async refreshAccessToken(refreshTokenObject) {
114
- this.access_token = undefined;
115
- const params = new URLSearchParams();
116
- params.append('grant_type', 'refresh_token');
117
- params.append('client_id', this.client_id);
118
- params.append('client_secret', this.client_secret);
119
- params.append('refresh_token', refreshTokenObject.refresh_token);
120
- params.append('redirect_uri', this.redirect_uri);
121
-
122
- const options = {
123
- body: params,
124
- url: this.tokenUri,
125
- headers: {
126
- 'Content-Type': 'application/x-www-form-urlencoded',
127
- },
128
- };
129
- const response = await this._post(options, false);
130
- await this.setTokens(response);
131
- return response;
132
- }
133
-
134
- async addAuthHeaders(headers) {
135
- if (this.access_token) {
136
- headers.Authorization = `Bearer ${this.access_token}`;
137
- }
138
-
139
- return headers;
140
- }
141
-
142
- isAuthenticated() {
143
- return (
144
- this.accessToken !== null &&
145
- this.refreshToken !== null &&
146
- this.accessTokenExpire &&
147
- this.refreshTokenExpire
148
- );
149
- }
150
-
151
- async refreshAuth() {
152
- try {
153
- if (this.grantType !== 'client_credentials') {
154
- await this.refreshAccessToken({
155
- refresh_token: this.refresh_token,
156
- });
157
- } else {
158
- await this.getTokenFromClientCredentials();
159
- }
160
- } catch {
161
- await this.notify(this.DLGT_INVALID_AUTH);
162
- }
163
- }
164
-
165
- async getTokenFromUsernamePassword() {
166
- try {
167
- const url = this.tokenUri;
168
-
169
- const body = {
170
- username: this.username,
171
- password: this.password,
172
- grant_type: 'password',
173
- };
174
- const headers = {
175
- 'Content-Type': 'application/json',
176
- };
177
-
178
- const tokenRes = await this._post({
179
- url,
180
- body,
181
- headers,
182
- });
183
-
184
- await this.setTokens(tokenRes);
185
- return tokenRes;
186
- } catch {
187
- await this.notify(this.DLGT_INVALID_AUTH);
188
- }
189
- }
190
-
191
- async getTokenFromClientCredentials() {
192
- try {
193
- const url = this.tokenUri;
194
-
195
- const body = {
196
- audience: this.audience,
197
- client_id: this.client_id,
198
- client_secret: this.client_secret,
199
- grant_type: 'client_credentials',
200
- };
201
- const headers = {
202
- 'Content-Type': 'application/json',
203
- };
204
-
205
- const tokenRes = await this._post({
206
- url,
207
- body,
208
- headers,
209
- });
210
-
211
- await this.setTokens(tokenRes);
212
- return tokenRes;
213
- } catch {
214
- await this.notify(this.DLGT_INVALID_AUTH);
215
- }
216
- }
217
- }
218
-
219
- module.exports = { OAuth2Requester };
@@ -1,165 +0,0 @@
1
- const fetch = require('node-fetch');
2
- const { Delegate } = require('../../core');
3
- const { FetchError } = require('../../errors');
4
- const { get } = require('../../assertions');
5
-
6
- class Requester extends Delegate {
7
- constructor(params) {
8
- super(params);
9
- this.backOff = get(params, 'backOff', [1, 3, 10, 30, 60, 180]);
10
- this.isRefreshable = false;
11
- this.refreshCount = 0;
12
- this.DLGT_INVALID_AUTH = 'INVALID_AUTH';
13
- this.delegateTypes.push(this.DLGT_INVALID_AUTH);
14
- this.agent = get(params, 'agent', null);
15
-
16
- // Allow passing in the fetch function
17
- // Instance methods can use this.fetch without differentiating
18
- this.fetch = get(params, 'fetch', fetch);
19
- }
20
-
21
- parsedBody = async (resp) => {
22
- const contentType = resp.headers.get('Content-Type') || '';
23
-
24
- if (
25
- contentType.match(/^application\/json/) ||
26
- contentType.match(/^application\/vnd.api\+json/) ||
27
- contentType.match(/^application\/hal\+json/)
28
- ) {
29
- return resp.json();
30
- }
31
-
32
- return resp.text();
33
- };
34
-
35
- async _request(url, options, i = 0) {
36
- let encodedUrl = encodeURI(url);
37
- if (options.query) {
38
- let queryBuild = '?';
39
- for (const key in options.query) {
40
- queryBuild += `${encodeURIComponent(key)}=${encodeURIComponent(
41
- options.query[key]
42
- )}&`;
43
- }
44
- encodedUrl += queryBuild.slice(0, -1);
45
- }
46
-
47
- options.headers = await this.addAuthHeaders(options.headers);
48
-
49
- if (this.agent) options.agent = this.agent;
50
-
51
- let response;
52
- try {
53
- response = await this.fetch(encodedUrl, options);
54
- } catch (e) {
55
- if (e.code === 'ECONNRESET' && i < this.backOff.length) {
56
- const delay = this.backOff[i] * 1000;
57
- await new Promise((resolve) => setTimeout(resolve, delay));
58
- return this._request(url, options, i + 1);
59
- }
60
- throw await FetchError.create({
61
- resource: encodedUrl,
62
- init: options,
63
- responseBody: e,
64
- });
65
- }
66
- const { status } = response;
67
-
68
- // If the status is retriable and there are back off requests left, retry the request
69
- if ((status === 429 || status >= 500) && i < this.backOff.length) {
70
- const delay = this.backOff[i] * 1000;
71
- await new Promise((resolve) => setTimeout(resolve, delay));
72
- return this._request(url, options, i + 1);
73
- } else if (status === 401) {
74
- if (!this.isRefreshable || this.refreshCount > 0) {
75
- await this.notify(this.DLGT_INVALID_AUTH);
76
- } else {
77
- this.refreshCount++;
78
- await this.refreshAuth();
79
- return this._request(url, options, i + 1); // Retries
80
- }
81
- }
82
-
83
- // If the error wasn't retried, throw.
84
- if (status >= 400) {
85
- throw await FetchError.create({
86
- resource: encodedUrl,
87
- init: options,
88
- response,
89
- });
90
- }
91
-
92
- return options.returnFullRes
93
- ? response
94
- : await this.parsedBody(response);
95
- }
96
-
97
- async _get(options) {
98
- const fetchOptions = {
99
- method: 'GET',
100
- credentials: 'include',
101
- headers: options.headers || {},
102
- query: options.query || {},
103
- returnFullRes: options.returnFullRes || false,
104
- };
105
-
106
- const res = await this._request(options.url, fetchOptions);
107
- return res;
108
- }
109
-
110
- async _post(options, stringify = true) {
111
- const fetchOptions = {
112
- method: 'POST',
113
- credentials: 'include',
114
- headers: options.headers || {},
115
- query: options.query || {},
116
- body: stringify ? JSON.stringify(options.body) : options.body,
117
- returnFullRes: options.returnFullRes || false,
118
- };
119
- const res = await this._request(options.url, fetchOptions);
120
- return res;
121
- }
122
-
123
- async _patch(options, stringify = true) {
124
- const fetchOptions = {
125
- method: 'PATCH',
126
- credentials: 'include',
127
- headers: options.headers || {},
128
- query: options.query || {},
129
- body: stringify ? JSON.stringify(options.body) : options.body,
130
- returnFullRes: options.returnFullRes || false,
131
- };
132
- const res = await this._request(options.url, fetchOptions);
133
- return res;
134
- }
135
-
136
- async _put(options, stringify = true) {
137
- const fetchOptions = {
138
- method: 'PUT',
139
- credentials: 'include',
140
- headers: options.headers || {},
141
- query: options.query || {},
142
- body: stringify ? JSON.stringify(options.body) : options.body,
143
- returnFullRes: options.returnFullRes || false,
144
- };
145
- const res = await this._request(options.url, fetchOptions);
146
- return res;
147
- }
148
-
149
- async _delete(options) {
150
- const fetchOptions = {
151
- method: 'DELETE',
152
- credentials: 'include',
153
- headers: options.headers || {},
154
- query: options.query || {},
155
- returnFullRes: options.returnFullRes || true,
156
- };
157
- return this._request(options.url, fetchOptions);
158
- }
159
-
160
- async refreshAuth() {
161
- throw new Error('refreshAuth not yet defined in child of Requester');
162
- }
163
- }
164
-
165
- module.exports = { Requester };
@@ -1,28 +0,0 @@
1
- const { Requester } = require('./requester');
2
-
3
- describe('429 and 5xx testing', () => {
4
- let backOffArray = [1, 1, 1];
5
- let requester = new Requester({ backOff: backOffArray });
6
- let sum = backOffArray.reduce((a, b) => {
7
- return a + b;
8
- }, 0);
9
- it.skip("should retry with 'exponential' back off due to 429", async () => {
10
- let startTime = await Date.now();
11
- let res = await requester._get({
12
- url: 'https://70e18ff0-1967-4fb5-8f96-10477ab6bb9e.mock.pstmn.io//429',
13
- });
14
- let endTime = await Date.now();
15
- let difference = endTime - startTime;
16
- expect(difference).toBeGreaterThan(sum * 1000);
17
- });
18
-
19
- it.skip("should retry with 'exponential' back off due to 500", async () => {
20
- let startTime = await Date.now();
21
- let res = await requester._get({
22
- url: 'https://70e18ff0-1967-4fb5-8f96-10477ab6bb9e.mock.pstmn.io//5xx',
23
- });
24
- let endTime = await Date.now();
25
- let difference = endTime - startTime;
26
- expect(difference).toBeGreaterThan(sum * 1000);
27
- });
28
- });
@@ -1,97 +0,0 @@
1
- const {Api} = require('./mock-api/api');
2
- const hubspotMocks = require('./mock-api/mocks/hubspot');
3
-
4
- const { Definition } = require('./mock-api/definition');
5
- const { Auther } = require('../auther');
6
- const { mongoose } = require('../../database/mongoose');
7
-
8
-
9
-
10
- const getModule = async (params) => {
11
- const module = await Auther.getInstance({
12
- definition: Definition,
13
- userId: new mongoose.Types.ObjectId(),
14
- ...params,
15
- });
16
- module.api.getTokenFromCode = async function(code) {
17
- await this.setTokens(hubspotMocks.tokenResponse);
18
- return hubspotMocks.tokenResponse;
19
- }
20
- module.api.getUserDetails = async function() {
21
- return hubspotMocks.userDetailsResponse;
22
- }
23
- return module
24
- }
25
-
26
-
27
- describe('HubSpot Module Tests', () => {
28
- let module, authUrl;
29
- beforeAll(async () => {
30
- await mongoose.connect(process.env.MONGO_URI);
31
- module = await getModule();
32
- });
33
-
34
- afterAll(async () => {
35
- await mongoose.disconnect();
36
- });
37
-
38
- describe('getAuthorizationRequirements() test', () => {
39
- it('should return auth requirements', async () => {
40
- const requirements = module.getAuthorizationRequirements();
41
- expect(requirements).toBeDefined();
42
- expect(requirements.type).toEqual('oauth2');
43
- expect(requirements.url).toBeDefined();
44
- authUrl = requirements.url;
45
- });
46
- });
47
-
48
- describe('Authorization requests', () => {
49
- let firstRes;
50
- it('processAuthorizationCallback()', async () => {
51
- const response = hubspotMocks.authorizeResponse;
52
- firstRes = await module.processAuthorizationCallback({
53
- data: {
54
- code: response.data.code,
55
- },
56
- });
57
- expect(firstRes).toBeDefined();
58
- expect(firstRes.entity_id).toBeDefined();
59
- expect(firstRes.credential_id).toBeDefined();
60
- });
61
- it('retrieves existing entity on subsequent calls', async () =>{
62
- const response = hubspotMocks.authorizeResponse;
63
- const res = await module.processAuthorizationCallback({
64
- data: {
65
- code: response.data.code,
66
- },
67
- });
68
- expect(res).toEqual(firstRes);
69
- });
70
- });
71
- describe('Test credential retrieval and module instantiation', () => {
72
- it('retrieve by entity id', async () => {
73
- const newModule = await getModule({
74
- userId: module.userId,
75
- entityId: module.entity.id,
76
- definition: Definition,
77
- });
78
- expect(newModule).toBeDefined();
79
- expect(newModule.entity).toBeDefined();
80
- expect(newModule.credential).toBeDefined();
81
- expect(await newModule.testAuth()).toBeTruthy();
82
-
83
- });
84
-
85
- it('retrieve by credential id', async () => {
86
- const newModule = await getModule({
87
- userId: module.userId,
88
- credentialId: module.credential.id,
89
- definition: Definition,
90
- });
91
- expect(newModule).toBeDefined();
92
- expect(newModule.credential).toBeDefined();
93
- expect(await newModule.testAuth()).toBeTruthy();
94
-
95
- });
96
- });
97
- });
package/syncs/model.js DELETED
@@ -1,62 +0,0 @@
1
- const mongoose = require("mongoose");
2
-
3
- const schema = new mongoose.Schema({
4
- entities: [
5
- { type: mongoose.Schema.Types.ObjectId, ref: "Entity", required: true },
6
- ],
7
- hash: { type: String, required: true },
8
- name: { type: String, required: true },
9
- dataIdentifiers: [
10
- {
11
- entity: {
12
- type: mongoose.Schema.Types.ObjectId,
13
- ref: "Entity",
14
- required: true,
15
- },
16
- id: { type: Object, required: true },
17
- hash: { type: String, required: true },
18
- },
19
- ],
20
- });
21
-
22
- schema.statics({
23
- getSyncObject: async function (name, dataIdentifier, entity) {
24
- // const syncList = await this.list({name:name,entities: {"$in": entities}, "entityIds.idHash":entityIdHash });
25
- const syncList = await this.find({
26
- name: name,
27
- dataIdentifiers: { $elemMatch: { id: dataIdentifier, entity } },
28
- });
29
-
30
- if (syncList.length === 1) {
31
- return syncList[0];
32
- } else if (syncList.length === 0) {
33
- return null;
34
- } else {
35
- throw new Error(
36
- `There are multiple sync objects with the name ${name}, for entities [${syncList[0].entities}] [${syncList[1].entities}]`
37
- );
38
- }
39
- },
40
-
41
- addDataIdentifier: async function (id, dataIdentifier) {
42
- return await this.update(
43
- { _id: id },
44
- {},
45
- { dataIdentifiers: dataIdentifier }
46
- );
47
- },
48
-
49
- getEntityObjIdForEntityIdFromObject: function (syncObj, entityId) {
50
- for (let dataIdentifier of syncObj.dataIdentifiers) {
51
- if (dataIdentifier.entity.toString() === entityId) {
52
- return dataIdentifier.id;
53
- }
54
- }
55
- throw new Error(
56
- `Sync object does not have DataIdentifier for entityId: ${entityId}`
57
- );
58
- },
59
- });
60
-
61
- const Sync = mongoose.models.Sync || mongoose.model("Sync", schema);
62
- module.exports = { Sync };
File without changes
File without changes