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

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 +238 -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 +92 -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
@@ -0,0 +1,164 @@
1
+ // The process composition root for telemetry: one shared state, per-part lazy
2
+ // getters, one atomic reset — replacing three separate singleton module caches
3
+ // (telemetry / usage-rollup / plugin-subscribers) that previously had to be
4
+ // reset together in the right order. Bus identity across the parts is guaranteed
5
+ // by construction: the rollup and plugin subscribers attach to the same
6
+ // getTelemetry() instance reached through this module's own closure.
7
+
8
+ const { createTelemetry } = require('./telemetry-service');
9
+ const { NoOpTelemetry } = require('./no-op-telemetry');
10
+ const loggerRuntime = require('../logs/logger-runtime');
11
+
12
+ const UNSET = Symbol('unset');
13
+
14
+ function newState() {
15
+ return { telemetry: null, usageRollup: UNSET, pluginSubscribers: UNSET };
16
+ }
17
+ let state = newState();
18
+
19
+ function loadTelemetryConfig() {
20
+ // Lazy-required to avoid a load-time cycle with the handlers layer.
21
+ const { loadAppDefinition } = require('../handlers/app-definition-loader');
22
+ return loadAppDefinition();
23
+ }
24
+
25
+ function activeSpanContext() {
26
+ const telemetry = state.telemetry;
27
+ return telemetry && typeof telemetry.getActiveSpanContext === 'function'
28
+ ? telemetry.getActiveSpanContext()
29
+ : null;
30
+ }
31
+
32
+ // resetLoggerForTests clears the provider, so check on every call.
33
+ function ensureSpanContextProvider() {
34
+ if (loggerRuntime.getSpanContextProvider() !== activeSpanContext) {
35
+ loggerRuntime.setSpanContextProvider(activeSpanContext);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * The process telemetry service. Created lazily on first use and reused for the
41
+ * life of the Lambda container, so the OTel SDK initialises at most once per cold
42
+ * start. Never throws — any failure falls back to the no-op.
43
+ */
44
+ function getTelemetry() {
45
+ ensureSpanContextProvider();
46
+ if (state.telemetry) return state.telemetry;
47
+ try {
48
+ const { telemetry = {} } = loadTelemetryConfig();
49
+ const stage = process.env.STAGE || process.env.NODE_ENV || 'production';
50
+ state.telemetry = createTelemetry({
51
+ exporter: telemetry.exporter,
52
+ sampleRatio: telemetry.sampleRatio,
53
+ resource: { service: process.env.FRIGG_STACK || 'frigg', stage },
54
+ });
55
+ } catch (_) {
56
+ state.telemetry = new NoOpTelemetry();
57
+ }
58
+ return state.telemetry;
59
+ }
60
+
61
+ /**
62
+ * The process usage-rollup subscriber, wired to getTelemetry()'s bus. Returns
63
+ * null when usage is disabled (no Definition.usage opt-in and no North Star) or
64
+ * the app definition can't load. Never throws — the warn lets operators tell
65
+ * "usage off" from "usage broken" (e.g. unresolved DB_TYPE).
66
+ */
67
+ function getUsageRollupSubscriber() {
68
+ if (state.usageRollup !== UNSET) return state.usageRollup;
69
+ state.usageRollup = null;
70
+ try {
71
+ const { computeTrackedMetrics } = require('../usage/tracked-metrics');
72
+ const {
73
+ northStarKeys,
74
+ createNorthStarDerivationSubscriber,
75
+ } = require('./north-star');
76
+ const { integrations = [], telemetry = {} } = loadTelemetryConfig();
77
+
78
+ // Track both Definition.usage opt-ins and any North Star counter keys,
79
+ // so a derived North Star persists even without an explicit usage decl.
80
+ const trackedMetrics = computeTrackedMetrics(integrations);
81
+ for (const key of northStarKeys(telemetry.northStar)) {
82
+ trackedMetrics.add(key);
83
+ }
84
+ if (trackedMetrics.size === 0) return state.usageRollup;
85
+
86
+ const {
87
+ createUsageRepository,
88
+ } = require('../usage/repositories/usage-repository-factory');
89
+ const {
90
+ createUsageRollupSubscriber,
91
+ } = require('./usage-rollup-subscriber');
92
+ const telemetryService = getTelemetry(); // same memo → shared bus
93
+
94
+ state.usageRollup = createUsageRollupSubscriber({
95
+ telemetry: telemetryService,
96
+ usageRepository: createUsageRepository(),
97
+ trackedMetrics,
98
+ });
99
+
100
+ // North Star derived-from-trace: emits the North Star counter when a
101
+ // configured signal matches; the emission flows to the rollup above.
102
+ if (telemetry.northStar) {
103
+ createNorthStarDerivationSubscriber({
104
+ telemetry: telemetryService,
105
+ northStar: telemetry.northStar,
106
+ });
107
+ }
108
+ } catch (error) {
109
+ console.warn(
110
+ `[Frigg][usage] rollup disabled: ${error && error.message}`
111
+ );
112
+ state.usageRollup = null;
113
+ }
114
+ return state.usageRollup;
115
+ }
116
+
117
+ /**
118
+ * Adopter-declared telemetry subscribers, wired to getTelemetry()'s bus once per
119
+ * cold start. Independent of the usage rollup (adopter taps wire even when no
120
+ * integration declares Definition.usage). Never throws.
121
+ */
122
+ function getPluginTelemetrySubscribers() {
123
+ if (state.pluginSubscribers !== UNSET) return state.pluginSubscribers;
124
+ state.pluginSubscribers = [];
125
+ try {
126
+ const { wireTelemetrySubscribers } = require('./plugin-subscribers');
127
+ const { telemetry = {} } = loadTelemetryConfig();
128
+ const subscribers = telemetry.subscribers || [];
129
+ if (subscribers.length === 0) return state.pluginSubscribers;
130
+
131
+ state.pluginSubscribers = wireTelemetrySubscribers({
132
+ telemetry: getTelemetry(),
133
+ subscribers,
134
+ });
135
+ } catch (error) {
136
+ console.warn(
137
+ `[Frigg][telemetry] plugin subscribers disabled: ${
138
+ error && error.message
139
+ }`
140
+ );
141
+ state.pluginSubscribers = [];
142
+ }
143
+ return state.pluginSubscribers;
144
+ }
145
+
146
+ /** Test-only: reset the whole runtime — no stale cross-memo states possible. */
147
+ function resetTelemetryRuntimeForTests() {
148
+ state = newState();
149
+ }
150
+
151
+ /** Test-only: install a telemetry service; dependent memos clear atomically. */
152
+ function setTelemetryForTests(telemetry) {
153
+ state = newState();
154
+ state.telemetry = telemetry;
155
+ ensureSpanContextProvider();
156
+ }
157
+
158
+ module.exports = {
159
+ getTelemetry,
160
+ getUsageRollupSubscriber,
161
+ getPluginTelemetrySubscribers,
162
+ resetTelemetryRuntimeForTests,
163
+ setTelemetryForTests,
164
+ };
@@ -0,0 +1,52 @@
1
+ const { NoOpTelemetry } = require('./no-op-telemetry');
2
+ const { createTelemetryEventBus } = require('./telemetry-event-bus');
3
+
4
+ /**
5
+ * @typedef {object} TelemetryService The vendor-neutral telemetry port. Both
6
+ * NoOpTelemetry and OtelTelemetry implement it (duck-typed; the bound wrapper
7
+ * from bindTelemetryContext is a plain object that also satisfies it):
8
+ * count(name, value?, attributes?, context?) · event(name, attributes?, context?)
9
+ * span(name, fn) · startSpan(name?) · withContext(context, fn)
10
+ * on(eventType, cb) · forceFlush() · shutdown() · isEnabled()
11
+ * getActiveSpanContext() → { traceId, spanId, traceFlags } | null
12
+ */
13
+
14
+ /**
15
+ * Determine whether an exporter descriptor means "emit nothing".
16
+ * Absent config or `{ type: 'none' }` (or `'noop'`) → no-op.
17
+ */
18
+ function isNoOpExporter(exporter) {
19
+ if (!exporter) return true;
20
+ const type = exporter.type;
21
+ return !type || type === 'none' || type === 'noop';
22
+ }
23
+
24
+ /**
25
+ * Create the vendor-neutral telemetry service — the adapter selector. Integration
26
+ * code uses the returned instance (`this.telemetry`) and never imports a backend
27
+ * SDK. With no exporter configured it returns `NoOpTelemetry` (loads zero OTel);
28
+ * a real exporter lazily constructs `OtelTelemetry`.
29
+ *
30
+ * @param {object} [options]
31
+ * @param {object} [options.exporter] Exporter descriptor, e.g. `{ type: 'otlp', endpoint }`.
32
+ * @param {object} [options.resource] Resource attributes, e.g. `{ service, stage }`.
33
+ * @param {number} [options.sampleRatio] Parent-based sampling ratio (0..1).
34
+ * @param {object} [options.bus] Event bus to reuse (defaults to a fresh one).
35
+ */
36
+ function createTelemetry(options = {}) {
37
+ // The internal event stream is always on and independent of OTel export:
38
+ // the usage rollup + plugin taps must work even when
39
+ // the OTel exporter is a no-op. The bus is pure JS, so this does not load
40
+ // any OTel module on the no-op path.
41
+ const bus = options.bus || createTelemetryEventBus();
42
+
43
+ if (isNoOpExporter(options.exporter)) {
44
+ return new NoOpTelemetry({ bus });
45
+ }
46
+
47
+ // Lazy-required so the no-op path never loads the OTel SDK.
48
+ const { OtelTelemetry } = require('./otel-telemetry');
49
+ return new OtelTelemetry({ ...options, bus });
50
+ }
51
+
52
+ module.exports = { createTelemetry, isNoOpExporter };
@@ -0,0 +1,116 @@
1
+ const { computeUsageWindows } = require('../usage/usage-windows');
2
+
3
+ const WEBHOOK_EVENT_NAMES = new Set(['ON_WEBHOOK']);
4
+
5
+ /**
6
+ * Framework auto-signal metric names → the canonical usage key they feed.
7
+ * Resolvers receive (attributes, context) and may return null to
8
+ * decline. Handler invocations map by event: USER_ACTION → user_actions; the
9
+ * DB-connected `ON_WEBHOOK` queue dispatch → webhooks.received (per-integration,
10
+ * and where a durable write is actually possible — the HTTP receipt handler is
11
+ * DB-free so its buffer is discarded).
12
+ */
13
+ const METRIC_TO_CANONICAL = {
14
+ 'frigg.apimodule.requests': () => 'api.requests',
15
+ 'frigg.handler.invocations': (attrs, ctx) => {
16
+ if (attrs && attrs.event === 'USER_ACTION') return 'user_actions';
17
+ if (ctx && WEBHOOK_EVENT_NAMES.has(ctx.event_name)) {
18
+ return 'webhooks.received';
19
+ }
20
+ return null;
21
+ },
22
+ };
23
+
24
+ /**
25
+ * The built-in usage-rollup subscriber. Subscribes to the
26
+ * telemetry event bus and folds *declared* counters (canonical or custom) into
27
+ * the durable usage store. It buffers within an invocation and writes on
28
+ * `flush()` (no timers — Lambda-safe), or drops the buffer on `discard()` for an
29
+ * SQS redelivery so at-least-once delivery does not double-count (approximate
30
+ * accuracy contract).
31
+ *
32
+ * Attribution: high-cardinality ids never ride metric labels, so integrationId
33
+ * comes from the bus-only `context` (populated from the ambient handler context)
34
+ * and otherwise falls back to the bounded integration_type.
35
+ */
36
+ function createUsageRollupSubscriber({
37
+ telemetry,
38
+ usageRepository,
39
+ trackedMetrics = new Set(),
40
+ now = () => new Date(),
41
+ }) {
42
+ // Buffer key is a JSON tuple [integrationId, integrationType, metric, window]
43
+ // — collision-proof for developer-defined custom keys / names.
44
+ let buffer = new Map();
45
+
46
+ function resolveUsageKey(name, attributes, context) {
47
+ if (trackedMetrics.has(name)) return name;
48
+ const resolver = METRIC_TO_CANONICAL[name];
49
+ const canonical = resolver ? resolver(attributes || {}, context) : null;
50
+ return canonical && trackedMetrics.has(canonical) ? canonical : null;
51
+ }
52
+
53
+ function onMetric(payload) {
54
+ try {
55
+ const { name, value = 1, attributes = {}, context } = payload;
56
+ const metric = resolveUsageKey(name, attributes, context);
57
+ if (!metric) return;
58
+
59
+ const integrationType =
60
+ context?.integrationType || attributes.integration_type || null;
61
+ if (!integrationType) return; // cannot attribute — skip
62
+
63
+ const integrationId = context?.integrationId || integrationType;
64
+
65
+ for (const window of computeUsageWindows(now())) {
66
+ const key = JSON.stringify([
67
+ integrationId,
68
+ integrationType,
69
+ metric,
70
+ window,
71
+ ]);
72
+ buffer.set(key, (buffer.get(key) || 0) + value);
73
+ }
74
+ } catch (_) {
75
+ // Rollup must never break emission.
76
+ }
77
+ }
78
+
79
+ const unsubscribe = telemetry.on('metric', onMetric);
80
+
81
+ async function flush() {
82
+ if (buffer.size === 0) return;
83
+ const pending = buffer;
84
+ buffer = new Map();
85
+ for (const [key, value] of pending) {
86
+ const [integrationId, integrationType, metric, window] =
87
+ JSON.parse(key);
88
+ try {
89
+ await usageRepository.increment({
90
+ integrationId,
91
+ integrationType,
92
+ metric,
93
+ window,
94
+ value,
95
+ });
96
+ } catch (_) {
97
+ // A single failed write must not abort the rest of the flush.
98
+ }
99
+ }
100
+ }
101
+
102
+ function discard() {
103
+ buffer = new Map();
104
+ }
105
+
106
+ return {
107
+ flush,
108
+ discard,
109
+ unsubscribe,
110
+ get bufferSize() {
111
+ return buffer.size;
112
+ },
113
+ };
114
+ }
115
+
116
+ module.exports = { createUsageRollupSubscriber, METRIC_TO_CANONICAL };
@@ -0,0 +1,137 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const bcrypt = require('bcryptjs');
3
+ const {
4
+ toObjectId,
5
+ fromObjectId,
6
+ findMany,
7
+ findOne,
8
+ insertOne,
9
+ deleteOne,
10
+ deleteMany,
11
+ } = require('../../database/documentdb-utils');
12
+ const { TokenRepositoryInterface } = require('./token-repository-interface');
13
+ const { ClientSafeError } = require('../../errors');
14
+
15
+ const BCRYPT_ROUNDS = 10;
16
+
17
+ class TokenRepositoryDocumentDB extends TokenRepositoryInterface {
18
+ constructor() {
19
+ super();
20
+ this.prisma = prisma;
21
+ }
22
+
23
+ async createTokenWithExpire(userId, rawToken, minutes) {
24
+ const tokenHash = await bcrypt.hash(rawToken, BCRYPT_ROUNDS);
25
+ const expires = new Date(Date.now() + minutes * 60000);
26
+ const now = new Date();
27
+ const document = {
28
+ token: tokenHash,
29
+ expires,
30
+ userId: toObjectId(userId),
31
+ created: now,
32
+ };
33
+ const insertedId = await insertOne(this.prisma, 'Token', document);
34
+ const created = await findOne(this.prisma, 'Token', {
35
+ _id: insertedId,
36
+ });
37
+ return this._mapToken(created);
38
+ }
39
+
40
+ async validateAndGetToken(tokenObj) {
41
+ const objectId = toObjectId(tokenObj.id);
42
+ if (!objectId) {
43
+ throw new ClientSafeError(
44
+ 'Invalid Token: Token does not exist',
45
+ 401
46
+ );
47
+ }
48
+ const record = await findOne(this.prisma, 'Token', { _id: objectId });
49
+ if (!record) {
50
+ throw new ClientSafeError(
51
+ 'Invalid Token: Token does not exist',
52
+ 401
53
+ );
54
+ }
55
+ const isValid = await bcrypt.compare(tokenObj.token, record.token);
56
+ if (!isValid) {
57
+ throw new ClientSafeError(
58
+ 'Invalid Token: Token does not match',
59
+ 401
60
+ );
61
+ }
62
+ if (record.expires && new Date(record.expires) < new Date()) {
63
+ throw new ClientSafeError('Invalid Token: Token is expired', 401);
64
+ }
65
+ return this._mapToken(record);
66
+ }
67
+
68
+ async findTokenById(tokenId) {
69
+ const objectId = toObjectId(tokenId);
70
+ if (!objectId) return null;
71
+ const record = await findOne(this.prisma, 'Token', { _id: objectId });
72
+ return record ? this._mapToken(record) : null;
73
+ }
74
+
75
+ async findTokensByUserId(userId) {
76
+ const objectId = toObjectId(userId);
77
+ const filter = objectId ? { userId: objectId } : {};
78
+ const records = await findMany(this.prisma, 'Token', filter);
79
+ return records.map((record) => this._mapToken(record));
80
+ }
81
+
82
+ async deleteToken(tokenId) {
83
+ const objectId = toObjectId(tokenId);
84
+ if (!objectId) return { acknowledged: true, deletedCount: 0 };
85
+ const result = await deleteOne(this.prisma, 'Token', { _id: objectId });
86
+ const deleted = result?.n ?? 0;
87
+ return { acknowledged: true, deletedCount: deleted };
88
+ }
89
+
90
+ async deleteExpiredTokens() {
91
+ const result = await deleteMany(this.prisma, 'Token', {
92
+ expires: { $lt: new Date() },
93
+ });
94
+ const deleted = result?.n ?? 0;
95
+ return { acknowledged: true, deletedCount: deleted };
96
+ }
97
+
98
+ async deleteTokensByUserId(userId) {
99
+ const objectId = toObjectId(userId);
100
+ if (!objectId) return { acknowledged: true, deletedCount: 0 };
101
+ const result = await deleteMany(this.prisma, 'Token', {
102
+ userId: objectId,
103
+ });
104
+ const deleted = result?.n ?? 0;
105
+ return { acknowledged: true, deletedCount: deleted };
106
+ }
107
+
108
+ createJSONToken(token, rawToken) {
109
+ return JSON.stringify({
110
+ id: token.id,
111
+ token: rawToken,
112
+ });
113
+ }
114
+
115
+ createBase64BufferToken(token, rawToken) {
116
+ const jsonVal = this.createJSONToken(token, rawToken);
117
+ return Buffer.from(jsonVal).toString('base64');
118
+ }
119
+
120
+ getJSONTokenFromBase64BufferToken(buffer) {
121
+ const tokenStr = Buffer.from(buffer.trim(), 'base64').toString('ascii');
122
+ return JSON.parse(tokenStr);
123
+ }
124
+
125
+ _mapToken(record) {
126
+ if (!record) return null;
127
+ return {
128
+ id: fromObjectId(record._id),
129
+ token: record.token,
130
+ expires: record.expires ? new Date(record.expires) : null,
131
+ userId: fromObjectId(record.userId),
132
+ created: record.created ? new Date(record.created) : null,
133
+ };
134
+ }
135
+ }
136
+
137
+ module.exports = { TokenRepositoryDocumentDB };
@@ -0,0 +1,40 @@
1
+ const { TokenRepositoryMongo } = require('./token-repository-mongo');
2
+ const { TokenRepositoryPostgres } = require('./token-repository-postgres');
3
+ const {
4
+ TokenRepositoryDocumentDB,
5
+ } = require('./token-repository-documentdb');
6
+ const config = require('../../database/config');
7
+
8
+ /**
9
+ * Token Repository Factory
10
+ * Creates the appropriate repository adapter based on database type
11
+ *
12
+ * @returns {TokenRepositoryInterface} Configured repository adapter
13
+ */
14
+ function createTokenRepository() {
15
+ const dbType = config.DB_TYPE;
16
+
17
+ switch (dbType) {
18
+ case 'mongodb':
19
+ return new TokenRepositoryMongo();
20
+
21
+ case 'postgresql':
22
+ return new TokenRepositoryPostgres();
23
+
24
+ case 'documentdb':
25
+ return new TokenRepositoryDocumentDB();
26
+
27
+ default:
28
+ throw new Error(
29
+ `Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
30
+ );
31
+ }
32
+ }
33
+
34
+ module.exports = {
35
+ createTokenRepository,
36
+ // Export adapters for direct testing
37
+ TokenRepositoryMongo,
38
+ TokenRepositoryPostgres,
39
+ TokenRepositoryDocumentDB,
40
+ };
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Token Repository Interface
3
+ * Abstract base class defining the contract for token persistence adapters
4
+ *
5
+ * This follows the Port in Hexagonal Architecture:
6
+ * - Domain layer depends on this abstraction
7
+ * - Concrete adapters implement this interface
8
+ * - Use cases receive repositories via dependency injection
9
+ *
10
+ * Note: Currently, Token model has identical structure across MongoDB and PostgreSQL,
11
+ * so TokenRepository serves both. This interface exists for consistency and
12
+ * future-proofing if database-specific implementations become needed.
13
+ *
14
+ * @abstract
15
+ */
16
+ class TokenRepositoryInterface {
17
+ /**
18
+ * Create token with expiration
19
+ *
20
+ * @param {string|number} userId - User ID
21
+ * @param {string} rawToken - Raw unhashed token
22
+ * @param {number} minutes - Minutes until expiration
23
+ * @returns {Promise<Object>} Created token object
24
+ * @abstract
25
+ */
26
+ async createTokenWithExpire(userId, rawToken, minutes) {
27
+ throw new Error(
28
+ 'Method createTokenWithExpire must be implemented by subclass'
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Validate and get token
34
+ *
35
+ * @param {Object} tokenObj - Token object with id and token
36
+ * @returns {Promise<Object>} Validated token object
37
+ * @abstract
38
+ */
39
+ async validateAndGetToken(tokenObj) {
40
+ throw new Error(
41
+ 'Method validateAndGetToken must be implemented by subclass'
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Find token by ID
47
+ *
48
+ * @param {string|number} tokenId - Token ID
49
+ * @returns {Promise<Object|null>} Token object or null
50
+ * @abstract
51
+ */
52
+ async findTokenById(tokenId) {
53
+ throw new Error('Method findTokenById must be implemented by subclass');
54
+ }
55
+
56
+ /**
57
+ * Find all tokens for a user
58
+ *
59
+ * @param {string|number} userId - User ID
60
+ * @returns {Promise<Array>} Array of token objects
61
+ * @abstract
62
+ */
63
+ async findTokensByUserId(userId) {
64
+ throw new Error(
65
+ 'Method findTokensByUserId must be implemented by subclass'
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Delete token by ID
71
+ *
72
+ * @param {string|number} tokenId - Token ID
73
+ * @returns {Promise<boolean>} True if deleted
74
+ * @abstract
75
+ */
76
+ async deleteToken(tokenId) {
77
+ throw new Error('Method deleteToken must be implemented by subclass');
78
+ }
79
+
80
+ /**
81
+ * Delete expired tokens
82
+ *
83
+ * @returns {Promise<number>} Number of deleted tokens
84
+ * @abstract
85
+ */
86
+ async deleteExpiredTokens() {
87
+ throw new Error(
88
+ 'Method deleteExpiredTokens must be implemented by subclass'
89
+ );
90
+ }
91
+
92
+ /**
93
+ * Delete all tokens for a user
94
+ *
95
+ * @param {string|number} userId - User ID
96
+ * @returns {Promise<number>} Number of deleted tokens
97
+ * @abstract
98
+ */
99
+ async deleteTokensByUserId(userId) {
100
+ throw new Error(
101
+ 'Method deleteTokensByUserId must be implemented by subclass'
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Create base64 buffer token
107
+ *
108
+ * @param {Object} token - Token object
109
+ * @param {string} rawToken - Raw token
110
+ * @returns {string} Base64 encoded token
111
+ */
112
+ createBase64BufferToken(token, rawToken) {
113
+ throw new Error(
114
+ 'Method createBase64BufferToken must be implemented by subclass'
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Get JSON token from base64 buffer token
120
+ *
121
+ * @param {string} base64Token - Base64 encoded token
122
+ * @returns {Object} Decoded token object
123
+ */
124
+ getJSONTokenFromBase64BufferToken(base64Token) {
125
+ throw new Error(
126
+ 'Method getJSONTokenFromBase64BufferToken must be implemented by subclass'
127
+ );
128
+ }
129
+ }
130
+
131
+ module.exports = { TokenRepositoryInterface };