@mdguggenbichler/slugbase-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/backend/dist/app-factory.d.ts +17 -0
  2. package/backend/dist/app-factory.d.ts.map +1 -0
  3. package/backend/dist/app-factory.js +106 -0
  4. package/backend/dist/app-factory.js.map +1 -0
  5. package/backend/dist/auth/authorization.d.ts +25 -0
  6. package/backend/dist/auth/authorization.d.ts.map +1 -0
  7. package/backend/dist/auth/authorization.js +100 -0
  8. package/backend/dist/auth/authorization.js.map +1 -0
  9. package/backend/dist/auth/jwt.d.ts +5 -0
  10. package/backend/dist/auth/jwt.d.ts.map +1 -0
  11. package/backend/dist/auth/jwt.js +34 -0
  12. package/backend/dist/auth/jwt.js.map +1 -0
  13. package/backend/dist/auth/oidc.d.ts +4 -0
  14. package/backend/dist/auth/oidc.d.ts.map +1 -0
  15. package/backend/dist/auth/oidc.js +201 -0
  16. package/backend/dist/auth/oidc.js.map +1 -0
  17. package/backend/dist/config/cloud-providers.d.ts +18 -0
  18. package/backend/dist/config/cloud-providers.d.ts.map +1 -0
  19. package/backend/dist/config/cloud-providers.js +60 -0
  20. package/backend/dist/config/cloud-providers.js.map +1 -0
  21. package/backend/dist/config/cookies.d.ts +17 -0
  22. package/backend/dist/config/cookies.d.ts.map +1 -0
  23. package/backend/dist/config/cookies.js +26 -0
  24. package/backend/dist/config/cookies.js.map +1 -0
  25. package/backend/dist/config/mode.d.ts +7 -0
  26. package/backend/dist/config/mode.d.ts.map +1 -0
  27. package/backend/dist/config/mode.js +7 -0
  28. package/backend/dist/config/mode.js.map +1 -0
  29. package/backend/dist/config/swagger.d.ts +2 -0
  30. package/backend/dist/config/swagger.d.ts.map +1 -0
  31. package/backend/dist/config/swagger.js +76 -0
  32. package/backend/dist/config/swagger.js.map +1 -0
  33. package/backend/dist/config.d.ts +29 -0
  34. package/backend/dist/config.d.ts.map +1 -0
  35. package/backend/dist/config.js +41 -0
  36. package/backend/dist/config.js.map +1 -0
  37. package/backend/dist/db/index.d.ts +14 -0
  38. package/backend/dist/db/index.d.ts.map +1 -0
  39. package/backend/dist/db/index.js +114 -0
  40. package/backend/dist/db/index.js.map +1 -0
  41. package/backend/dist/db/migrate-slug-nullable.d.ts +10 -0
  42. package/backend/dist/db/migrate-slug-nullable.d.ts.map +1 -0
  43. package/backend/dist/db/migrate-slug-nullable.js +87 -0
  44. package/backend/dist/db/migrate-slug-nullable.js.map +1 -0
  45. package/backend/dist/db/migrations/001_migrate_slug_nullable.d.ts +10 -0
  46. package/backend/dist/db/migrations/001_migrate_slug_nullable.d.ts.map +1 -0
  47. package/backend/dist/db/migrations/001_migrate_slug_nullable.js +103 -0
  48. package/backend/dist/db/migrations/001_migrate_slug_nullable.js.map +1 -0
  49. package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.d.ts +11 -0
  50. package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.d.ts.map +1 -0
  51. package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.js +92 -0
  52. package/backend/dist/db/migrations/002_add_oidc_custom_endpoints.js.map +1 -0
  53. package/backend/dist/db/migrations/003_add_bookmark_features.d.ts +5 -0
  54. package/backend/dist/db/migrations/003_add_bookmark_features.d.ts.map +1 -0
  55. package/backend/dist/db/migrations/003_add_bookmark_features.js +98 -0
  56. package/backend/dist/db/migrations/003_add_bookmark_features.js.map +1 -0
  57. package/backend/dist/db/migrations/004_make_slug_globally_unique.d.ts +12 -0
  58. package/backend/dist/db/migrations/004_make_slug_globally_unique.d.ts.map +1 -0
  59. package/backend/dist/db/migrations/004_make_slug_globally_unique.js +152 -0
  60. package/backend/dist/db/migrations/004_make_slug_globally_unique.js.map +1 -0
  61. package/backend/dist/db/migrations/005_add_email_verification.d.ts +5 -0
  62. package/backend/dist/db/migrations/005_add_email_verification.d.ts.map +1 -0
  63. package/backend/dist/db/migrations/005_add_email_verification.js +102 -0
  64. package/backend/dist/db/migrations/005_add_email_verification.js.map +1 -0
  65. package/backend/dist/db/migrations/006_refresh_tokens.d.ts +9 -0
  66. package/backend/dist/db/migrations/006_refresh_tokens.d.ts.map +1 -0
  67. package/backend/dist/db/migrations/006_refresh_tokens.js +61 -0
  68. package/backend/dist/db/migrations/006_refresh_tokens.js.map +1 -0
  69. package/backend/dist/db/migrations/007_password_reset_token_hash.d.ts +10 -0
  70. package/backend/dist/db/migrations/007_password_reset_token_hash.d.ts.map +1 -0
  71. package/backend/dist/db/migrations/007_password_reset_token_hash.js +40 -0
  72. package/backend/dist/db/migrations/007_password_reset_token_hash.js.map +1 -0
  73. package/backend/dist/db/migrations/008_slug_preferences.d.ts +8 -0
  74. package/backend/dist/db/migrations/008_slug_preferences.d.ts.map +1 -0
  75. package/backend/dist/db/migrations/008_slug_preferences.js +24 -0
  76. package/backend/dist/db/migrations/008_slug_preferences.js.map +1 -0
  77. package/backend/dist/db/migrations/009_signup_email_verified.d.ts +5 -0
  78. package/backend/dist/db/migrations/009_signup_email_verified.d.ts.map +1 -0
  79. package/backend/dist/db/migrations/009_signup_email_verified.js +79 -0
  80. package/backend/dist/db/migrations/009_signup_email_verified.js.map +1 -0
  81. package/backend/dist/db/migrations/010_organizations.d.ts +5 -0
  82. package/backend/dist/db/migrations/010_organizations.d.ts.map +1 -0
  83. package/backend/dist/db/migrations/010_organizations.js +113 -0
  84. package/backend/dist/db/migrations/010_organizations.js.map +1 -0
  85. package/backend/dist/db/migrations/011_org_scoped_teams.d.ts +11 -0
  86. package/backend/dist/db/migrations/011_org_scoped_teams.d.ts.map +1 -0
  87. package/backend/dist/db/migrations/011_org_scoped_teams.js +59 -0
  88. package/backend/dist/db/migrations/011_org_scoped_teams.js.map +1 -0
  89. package/backend/dist/db/migrations/012_org_invitations_token_hash.d.ts +10 -0
  90. package/backend/dist/db/migrations/012_org_invitations_token_hash.d.ts.map +1 -0
  91. package/backend/dist/db/migrations/012_org_invitations_token_hash.js +40 -0
  92. package/backend/dist/db/migrations/012_org_invitations_token_hash.js.map +1 -0
  93. package/backend/dist/db/migrations/013_signup_verification_token_hash.d.ts +10 -0
  94. package/backend/dist/db/migrations/013_signup_verification_token_hash.d.ts.map +1 -0
  95. package/backend/dist/db/migrations/013_signup_verification_token_hash.js +39 -0
  96. package/backend/dist/db/migrations/013_signup_verification_token_hash.js.map +1 -0
  97. package/backend/dist/db/migrations/014_stats_indexes.d.ts +8 -0
  98. package/backend/dist/db/migrations/014_stats_indexes.d.ts.map +1 -0
  99. package/backend/dist/db/migrations/014_stats_indexes.js +19 -0
  100. package/backend/dist/db/migrations/014_stats_indexes.js.map +1 -0
  101. package/backend/dist/db/migrations/015_api_tokens.d.ts +9 -0
  102. package/backend/dist/db/migrations/015_api_tokens.d.ts.map +1 -0
  103. package/backend/dist/db/migrations/015_api_tokens.js +48 -0
  104. package/backend/dist/db/migrations/015_api_tokens.js.map +1 -0
  105. package/backend/dist/db/migrations/016_free_plan_grace_ends_at.d.ts +9 -0
  106. package/backend/dist/db/migrations/016_free_plan_grace_ends_at.d.ts.map +1 -0
  107. package/backend/dist/db/migrations/016_free_plan_grace_ends_at.js +50 -0
  108. package/backend/dist/db/migrations/016_free_plan_grace_ends_at.js.map +1 -0
  109. package/backend/dist/db/migrations/017_ai_suggestions.d.ts +11 -0
  110. package/backend/dist/db/migrations/017_ai_suggestions.d.ts.map +1 -0
  111. package/backend/dist/db/migrations/017_ai_suggestions.js +78 -0
  112. package/backend/dist/db/migrations/017_ai_suggestions.js.map +1 -0
  113. package/backend/dist/db/migrations/018_ai_cache_output_language.d.ts +10 -0
  114. package/backend/dist/db/migrations/018_ai_cache_output_language.d.ts.map +1 -0
  115. package/backend/dist/db/migrations/018_ai_cache_output_language.js +89 -0
  116. package/backend/dist/db/migrations/018_ai_cache_output_language.js.map +1 -0
  117. package/backend/dist/db/migrations/019_ai_suggestion_usage.d.ts +10 -0
  118. package/backend/dist/db/migrations/019_ai_suggestion_usage.d.ts.map +1 -0
  119. package/backend/dist/db/migrations/019_ai_suggestion_usage.js +47 -0
  120. package/backend/dist/db/migrations/019_ai_suggestion_usage.js.map +1 -0
  121. package/backend/dist/db/migrations/020_tenant_scope.d.ts +5 -0
  122. package/backend/dist/db/migrations/020_tenant_scope.d.ts.map +1 -0
  123. package/backend/dist/db/migrations/020_tenant_scope.js +105 -0
  124. package/backend/dist/db/migrations/020_tenant_scope.js.map +1 -0
  125. package/backend/dist/db/migrations/_legacy_cloud_010_organizations.d.ts +5 -0
  126. package/backend/dist/db/migrations/_legacy_cloud_010_organizations.d.ts.map +1 -0
  127. package/backend/dist/db/migrations/_legacy_cloud_010_organizations.js +113 -0
  128. package/backend/dist/db/migrations/_legacy_cloud_010_organizations.js.map +1 -0
  129. package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.d.ts +11 -0
  130. package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.d.ts.map +1 -0
  131. package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.js +59 -0
  132. package/backend/dist/db/migrations/_legacy_cloud_011_org_scoped_teams.js.map +1 -0
  133. package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.d.ts +10 -0
  134. package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.d.ts.map +1 -0
  135. package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.js +40 -0
  136. package/backend/dist/db/migrations/_legacy_cloud_012_org_invitations_token_hash.js.map +1 -0
  137. package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.d.ts +9 -0
  138. package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.d.ts.map +1 -0
  139. package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.js +50 -0
  140. package/backend/dist/db/migrations/_legacy_cloud_016_free_plan_grace_ends_at.js.map +1 -0
  141. package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.d.ts +11 -0
  142. package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.d.ts.map +1 -0
  143. package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.js +78 -0
  144. package/backend/dist/db/migrations/_legacy_cloud_017_ai_suggestions.js.map +1 -0
  145. package/backend/dist/db/migrations/index.d.ts +22 -0
  146. package/backend/dist/db/migrations/index.d.ts.map +1 -0
  147. package/backend/dist/db/migrations/index.js +194 -0
  148. package/backend/dist/db/migrations/index.js.map +1 -0
  149. package/backend/dist/db/pool.d.ts +13 -0
  150. package/backend/dist/db/pool.d.ts.map +1 -0
  151. package/backend/dist/db/pool.js +41 -0
  152. package/backend/dist/db/pool.js.map +1 -0
  153. package/backend/dist/db/seed-data.d.ts +66 -0
  154. package/backend/dist/db/seed-data.d.ts.map +1 -0
  155. package/backend/dist/db/seed-data.js +394 -0
  156. package/backend/dist/db/seed-data.js.map +1 -0
  157. package/backend/dist/db/seed.d.ts +19 -0
  158. package/backend/dist/db/seed.d.ts.map +1 -0
  159. package/backend/dist/db/seed.js +406 -0
  160. package/backend/dist/db/seed.js.map +1 -0
  161. package/backend/dist/index.d.ts +3 -0
  162. package/backend/dist/index.d.ts.map +1 -0
  163. package/backend/dist/index.js +64 -0
  164. package/backend/dist/index.js.map +1 -0
  165. package/backend/dist/instrument.d.ts +2 -0
  166. package/backend/dist/instrument.d.ts.map +1 -0
  167. package/backend/dist/instrument.js +16 -0
  168. package/backend/dist/instrument.js.map +1 -0
  169. package/backend/dist/load-env.d.ts +2 -0
  170. package/backend/dist/load-env.d.ts.map +1 -0
  171. package/backend/dist/load-env.js +33 -0
  172. package/backend/dist/load-env.js.map +1 -0
  173. package/backend/dist/middleware/auth.d.ts +23 -0
  174. package/backend/dist/middleware/auth.d.ts.map +1 -0
  175. package/backend/dist/middleware/auth.js +69 -0
  176. package/backend/dist/middleware/auth.js.map +1 -0
  177. package/backend/dist/middleware/error-handler.d.ts +11 -0
  178. package/backend/dist/middleware/error-handler.d.ts.map +1 -0
  179. package/backend/dist/middleware/error-handler.js +40 -0
  180. package/backend/dist/middleware/error-handler.js.map +1 -0
  181. package/backend/dist/middleware/security.d.ts +26 -0
  182. package/backend/dist/middleware/security.d.ts.map +1 -0
  183. package/backend/dist/middleware/security.js +162 -0
  184. package/backend/dist/middleware/security.js.map +1 -0
  185. package/backend/dist/middleware/stats-auth.d.ts +7 -0
  186. package/backend/dist/middleware/stats-auth.d.ts.map +1 -0
  187. package/backend/dist/middleware/stats-auth.js +20 -0
  188. package/backend/dist/middleware/stats-auth.js.map +1 -0
  189. package/backend/dist/middleware/tenant.d.ts +3 -0
  190. package/backend/dist/middleware/tenant.d.ts.map +1 -0
  191. package/backend/dist/middleware/tenant.js +13 -0
  192. package/backend/dist/middleware/tenant.js.map +1 -0
  193. package/backend/dist/register-routes.d.ts +12 -0
  194. package/backend/dist/register-routes.d.ts.map +1 -0
  195. package/backend/dist/register-routes.js +59 -0
  196. package/backend/dist/register-routes.js.map +1 -0
  197. package/backend/dist/routes/admin/demo-reset.d.ts +8 -0
  198. package/backend/dist/routes/admin/demo-reset.d.ts.map +1 -0
  199. package/backend/dist/routes/admin/demo-reset.js +66 -0
  200. package/backend/dist/routes/admin/demo-reset.js.map +1 -0
  201. package/backend/dist/routes/admin/settings.d.ts +3 -0
  202. package/backend/dist/routes/admin/settings.d.ts.map +1 -0
  203. package/backend/dist/routes/admin/settings.js +452 -0
  204. package/backend/dist/routes/admin/settings.js.map +1 -0
  205. package/backend/dist/routes/admin/stats.d.ts +7 -0
  206. package/backend/dist/routes/admin/stats.d.ts.map +1 -0
  207. package/backend/dist/routes/admin/stats.js +66 -0
  208. package/backend/dist/routes/admin/stats.js.map +1 -0
  209. package/backend/dist/routes/admin/teams.d.ts +3 -0
  210. package/backend/dist/routes/admin/teams.d.ts.map +1 -0
  211. package/backend/dist/routes/admin/teams.js +509 -0
  212. package/backend/dist/routes/admin/teams.js.map +1 -0
  213. package/backend/dist/routes/admin/users.d.ts +3 -0
  214. package/backend/dist/routes/admin/users.d.ts.map +1 -0
  215. package/backend/dist/routes/admin/users.js +525 -0
  216. package/backend/dist/routes/admin/users.js.map +1 -0
  217. package/backend/dist/routes/auth.d.ts +3 -0
  218. package/backend/dist/routes/auth.d.ts.map +1 -0
  219. package/backend/dist/routes/auth.js +992 -0
  220. package/backend/dist/routes/auth.js.map +1 -0
  221. package/backend/dist/routes/billing.d.ts +8 -0
  222. package/backend/dist/routes/billing.d.ts.map +1 -0
  223. package/backend/dist/routes/billing.js +481 -0
  224. package/backend/dist/routes/billing.js.map +1 -0
  225. package/backend/dist/routes/bookmarks.d.ts +3 -0
  226. package/backend/dist/routes/bookmarks.d.ts.map +1 -0
  227. package/backend/dist/routes/bookmarks.js +1593 -0
  228. package/backend/dist/routes/bookmarks.js.map +1 -0
  229. package/backend/dist/routes/config.d.ts +7 -0
  230. package/backend/dist/routes/config.d.ts.map +1 -0
  231. package/backend/dist/routes/config.js +52 -0
  232. package/backend/dist/routes/config.js.map +1 -0
  233. package/backend/dist/routes/contact.d.ts +9 -0
  234. package/backend/dist/routes/contact.d.ts.map +1 -0
  235. package/backend/dist/routes/contact.js +99 -0
  236. package/backend/dist/routes/contact.js.map +1 -0
  237. package/backend/dist/routes/csrf.d.ts +3 -0
  238. package/backend/dist/routes/csrf.d.ts.map +1 -0
  239. package/backend/dist/routes/csrf.js +39 -0
  240. package/backend/dist/routes/csrf.js.map +1 -0
  241. package/backend/dist/routes/dashboard.d.ts +3 -0
  242. package/backend/dist/routes/dashboard.d.ts.map +1 -0
  243. package/backend/dist/routes/dashboard.js +212 -0
  244. package/backend/dist/routes/dashboard.js.map +1 -0
  245. package/backend/dist/routes/email-verification.d.ts +3 -0
  246. package/backend/dist/routes/email-verification.d.ts.map +1 -0
  247. package/backend/dist/routes/email-verification.js +124 -0
  248. package/backend/dist/routes/email-verification.js.map +1 -0
  249. package/backend/dist/routes/folders.d.ts +3 -0
  250. package/backend/dist/routes/folders.d.ts.map +1 -0
  251. package/backend/dist/routes/folders.js +524 -0
  252. package/backend/dist/routes/folders.js.map +1 -0
  253. package/backend/dist/routes/go-helpers.d.ts +18 -0
  254. package/backend/dist/routes/go-helpers.d.ts.map +1 -0
  255. package/backend/dist/routes/go-helpers.js +64 -0
  256. package/backend/dist/routes/go-helpers.js.map +1 -0
  257. package/backend/dist/routes/go.d.ts +23 -0
  258. package/backend/dist/routes/go.d.ts.map +1 -0
  259. package/backend/dist/routes/go.js +361 -0
  260. package/backend/dist/routes/go.js.map +1 -0
  261. package/backend/dist/routes/health.d.ts +6 -0
  262. package/backend/dist/routes/health.d.ts.map +1 -0
  263. package/backend/dist/routes/health.js +79 -0
  264. package/backend/dist/routes/health.js.map +1 -0
  265. package/backend/dist/routes/invitations.d.ts +3 -0
  266. package/backend/dist/routes/invitations.d.ts.map +1 -0
  267. package/backend/dist/routes/invitations.js +172 -0
  268. package/backend/dist/routes/invitations.js.map +1 -0
  269. package/backend/dist/routes/oidc-providers.d.ts +3 -0
  270. package/backend/dist/routes/oidc-providers.d.ts.map +1 -0
  271. package/backend/dist/routes/oidc-providers.js +495 -0
  272. package/backend/dist/routes/oidc-providers.js.map +1 -0
  273. package/backend/dist/routes/organizations.d.ts +3 -0
  274. package/backend/dist/routes/organizations.d.ts.map +1 -0
  275. package/backend/dist/routes/organizations.js +538 -0
  276. package/backend/dist/routes/organizations.js.map +1 -0
  277. package/backend/dist/routes/password-reset.d.ts +3 -0
  278. package/backend/dist/routes/password-reset.d.ts.map +1 -0
  279. package/backend/dist/routes/password-reset.js +212 -0
  280. package/backend/dist/routes/password-reset.js.map +1 -0
  281. package/backend/dist/routes/redirect.d.ts +3 -0
  282. package/backend/dist/routes/redirect.d.ts.map +1 -0
  283. package/backend/dist/routes/redirect.js +124 -0
  284. package/backend/dist/routes/redirect.js.map +1 -0
  285. package/backend/dist/routes/tags.d.ts +3 -0
  286. package/backend/dist/routes/tags.d.ts.map +1 -0
  287. package/backend/dist/routes/tags.js +302 -0
  288. package/backend/dist/routes/tags.js.map +1 -0
  289. package/backend/dist/routes/teams.d.ts +3 -0
  290. package/backend/dist/routes/teams.d.ts.map +1 -0
  291. package/backend/dist/routes/teams.js +60 -0
  292. package/backend/dist/routes/teams.js.map +1 -0
  293. package/backend/dist/routes/tokens.d.ts +3 -0
  294. package/backend/dist/routes/tokens.d.ts.map +1 -0
  295. package/backend/dist/routes/tokens.js +157 -0
  296. package/backend/dist/routes/tokens.js.map +1 -0
  297. package/backend/dist/routes/users.d.ts +3 -0
  298. package/backend/dist/routes/users.d.ts.map +1 -0
  299. package/backend/dist/routes/users.js +199 -0
  300. package/backend/dist/routes/users.js.map +1 -0
  301. package/backend/dist/services/ai-suggestions.d.ts +29 -0
  302. package/backend/dist/services/ai-suggestions.d.ts.map +1 -0
  303. package/backend/dist/services/ai-suggestions.js +163 -0
  304. package/backend/dist/services/ai-suggestions.js.map +1 -0
  305. package/backend/dist/services/api-tokens.d.ts +66 -0
  306. package/backend/dist/services/api-tokens.d.ts.map +1 -0
  307. package/backend/dist/services/api-tokens.js +129 -0
  308. package/backend/dist/services/api-tokens.js.map +1 -0
  309. package/backend/dist/services/fetch-page-metadata.d.ts +15 -0
  310. package/backend/dist/services/fetch-page-metadata.d.ts.map +1 -0
  311. package/backend/dist/services/fetch-page-metadata.js +205 -0
  312. package/backend/dist/services/fetch-page-metadata.js.map +1 -0
  313. package/backend/dist/services/stats.d.ts +73 -0
  314. package/backend/dist/services/stats.d.ts.map +1 -0
  315. package/backend/dist/services/stats.js +145 -0
  316. package/backend/dist/services/stats.js.map +1 -0
  317. package/backend/dist/types/oidc-provider.d.ts +17 -0
  318. package/backend/dist/types/oidc-provider.d.ts.map +1 -0
  319. package/backend/dist/types/oidc-provider.js +2 -0
  320. package/backend/dist/types/oidc-provider.js.map +1 -0
  321. package/backend/dist/types.d.ts +86 -0
  322. package/backend/dist/types.d.ts.map +1 -0
  323. package/backend/dist/types.js +2 -0
  324. package/backend/dist/types.js.map +1 -0
  325. package/backend/dist/utils/ai-feature.d.ts +23 -0
  326. package/backend/dist/utils/ai-feature.d.ts.map +1 -0
  327. package/backend/dist/utils/ai-feature.js +62 -0
  328. package/backend/dist/utils/ai-feature.js.map +1 -0
  329. package/backend/dist/utils/email.d.ts +40 -0
  330. package/backend/dist/utils/email.d.ts.map +1 -0
  331. package/backend/dist/utils/email.js +456 -0
  332. package/backend/dist/utils/email.js.map +1 -0
  333. package/backend/dist/utils/encryption.d.ts +18 -0
  334. package/backend/dist/utils/encryption.d.ts.map +1 -0
  335. package/backend/dist/utils/encryption.js +95 -0
  336. package/backend/dist/utils/encryption.js.map +1 -0
  337. package/backend/dist/utils/env-validation.d.ts +6 -0
  338. package/backend/dist/utils/env-validation.d.ts.map +1 -0
  339. package/backend/dist/utils/env-validation.js +51 -0
  340. package/backend/dist/utils/env-validation.js.map +1 -0
  341. package/backend/dist/utils/jwt.d.ts +20 -0
  342. package/backend/dist/utils/jwt.d.ts.map +1 -0
  343. package/backend/dist/utils/jwt.js +48 -0
  344. package/backend/dist/utils/jwt.js.map +1 -0
  345. package/backend/dist/utils/org-cleanup.d.ts +6 -0
  346. package/backend/dist/utils/org-cleanup.d.ts.map +1 -0
  347. package/backend/dist/utils/org-cleanup.js +37 -0
  348. package/backend/dist/utils/org-cleanup.js.map +1 -0
  349. package/backend/dist/utils/organizations.d.ts +12 -0
  350. package/backend/dist/utils/organizations.d.ts.map +1 -0
  351. package/backend/dist/utils/organizations.js +24 -0
  352. package/backend/dist/utils/organizations.js.map +1 -0
  353. package/backend/dist/utils/plan-errors.d.ts +18 -0
  354. package/backend/dist/utils/plan-errors.d.ts.map +1 -0
  355. package/backend/dist/utils/plan-errors.js +21 -0
  356. package/backend/dist/utils/plan-errors.js.map +1 -0
  357. package/backend/dist/utils/refresh-token.d.ts +31 -0
  358. package/backend/dist/utils/refresh-token.d.ts.map +1 -0
  359. package/backend/dist/utils/refresh-token.js +63 -0
  360. package/backend/dist/utils/refresh-token.js.map +1 -0
  361. package/backend/dist/utils/session-store.d.ts +46 -0
  362. package/backend/dist/utils/session-store.d.ts.map +1 -0
  363. package/backend/dist/utils/session-store.js +222 -0
  364. package/backend/dist/utils/session-store.js.map +1 -0
  365. package/backend/dist/utils/tenant.d.ts +5 -0
  366. package/backend/dist/utils/tenant.d.ts.map +1 -0
  367. package/backend/dist/utils/tenant.js +12 -0
  368. package/backend/dist/utils/tenant.js.map +1 -0
  369. package/backend/dist/utils/user-key.d.ts +24 -0
  370. package/backend/dist/utils/user-key.d.ts.map +1 -0
  371. package/backend/dist/utils/user-key.js +116 -0
  372. package/backend/dist/utils/user-key.js.map +1 -0
  373. package/backend/dist/utils/validation.d.ts +91 -0
  374. package/backend/dist/utils/validation.d.ts.map +1 -0
  375. package/backend/dist/utils/validation.js +337 -0
  376. package/backend/dist/utils/validation.js.map +1 -0
  377. package/backend/index.js +15 -0
  378. package/frontend/index.js +5 -0
  379. package/frontend/index.tsx +7 -0
  380. package/package.json +16 -0
  381. package/types/index.js +4 -0
@@ -0,0 +1,69 @@
1
+ import passport from 'passport';
2
+ import { validateToken } from '../services/api-tokens.js';
3
+ // Type guard to check if request is AuthRequest
4
+ export function isAuthRequest(req) {
5
+ return 'user' in req;
6
+ }
7
+ /**
8
+ * Middleware to authenticate requests using JWT or API token.
9
+ * Priority: JWT (cookie or Bearer) → API token (Bearer with sb_ prefix).
10
+ * If JWT fails and Bearer token starts with sb_, tries API token lookup.
11
+ */
12
+ export function requireAuth() {
13
+ return (req, res, next) => {
14
+ passport.authenticate('jwt', { session: false }, async (err, user) => {
15
+ if (err) {
16
+ return res.status(401).json({ error: 'Unauthorized' });
17
+ }
18
+ if (user) {
19
+ req.user = user;
20
+ return next();
21
+ }
22
+ // JWT failed; try API token if Bearer header present
23
+ const authHeader = req.headers.authorization;
24
+ if (authHeader?.startsWith('Bearer ')) {
25
+ const token = authHeader.substring(7);
26
+ if (token.startsWith('sb_')) {
27
+ const apiUser = await validateToken(token);
28
+ if (apiUser) {
29
+ req.user = apiUser;
30
+ return next();
31
+ }
32
+ }
33
+ }
34
+ return res.status(401).json({ error: 'Unauthorized' });
35
+ })(req, res, next);
36
+ };
37
+ }
38
+ /**
39
+ * Middleware to authenticate and require global admin.
40
+ * Supports JWT and API token same as requireAuth.
41
+ */
42
+ export function requireAdmin() {
43
+ return (req, res, next) => {
44
+ passport.authenticate('jwt', { session: false }, async (err, user) => {
45
+ if (err) {
46
+ return res.status(401).json({ error: 'Unauthorized' });
47
+ }
48
+ if (!user) {
49
+ const authHeader = req.headers.authorization;
50
+ if (authHeader?.startsWith('Bearer ')) {
51
+ const token = authHeader.substring(7);
52
+ if (token.startsWith('sb_')) {
53
+ user = await validateToken(token);
54
+ }
55
+ }
56
+ }
57
+ if (!user) {
58
+ return res.status(401).json({ error: 'Unauthorized' });
59
+ }
60
+ const isGlobalAdmin = user.is_admin === true || user.is_admin === 1;
61
+ if (!isGlobalAdmin) {
62
+ return res.status(403).json({ error: 'Forbidden' });
63
+ }
64
+ req.user = user;
65
+ next();
66
+ })(req, res, next);
67
+ };
68
+ }
69
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ /**
3
+ * Error handling middleware
4
+ * Prevents information disclosure in production
5
+ */
6
+ export declare function errorHandler(err: any, req: Request, res: Response, next: NextFunction): Response<any, Record<string, any>>;
7
+ /**
8
+ * 404 handler
9
+ */
10
+ export declare function notFoundHandler(req: Request, res: Response): void;
11
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,sCA8BrF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,QAE1D"}
@@ -0,0 +1,40 @@
1
+ import * as Sentry from '@sentry/node';
2
+ /**
3
+ * Error handling middleware
4
+ * Prevents information disclosure in production
5
+ */
6
+ export function errorHandler(err, req, res, next) {
7
+ // Report to Sentry when configured (no-op when SENTRY_DSN is unset)
8
+ Sentry.captureException(err);
9
+ // Log error details server-side
10
+ console.error('Error:', {
11
+ message: err.message,
12
+ stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
13
+ path: req.path,
14
+ method: req.method,
15
+ });
16
+ // Don't expose error details in production (M5: never send err.message or stack)
17
+ if (process.env.NODE_ENV === 'production') {
18
+ const status = err.statusCode || 500;
19
+ const safeMessages = {
20
+ 400: 'Bad request',
21
+ 401: 'Unauthorized',
22
+ 403: 'Forbidden',
23
+ 404: 'Not found',
24
+ };
25
+ const safeMessage = status in safeMessages ? safeMessages[status] : 'Internal server error';
26
+ return res.status(status).json({ error: safeMessage });
27
+ }
28
+ // Development: show more details
29
+ return res.status(err.statusCode || 500).json({
30
+ error: err.message || 'An error occurred',
31
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
32
+ });
33
+ }
34
+ /**
35
+ * 404 handler
36
+ */
37
+ export function notFoundHandler(req, res) {
38
+ res.status(404).json({ error: 'Not found' });
39
+ }
40
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/middleware/error-handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAEvC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAQ,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB;IACpF,oEAAoE;IACpE,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAE7B,gCAAgC;IAChC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE;QACtB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QACrE,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM,EAAE,GAAG,CAAC,MAAM;KACnB,CAAC,CAAC;IAEH,iFAAiF;IACjF,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC;QACrC,MAAM,YAAY,GAA2B;YAC3C,GAAG,EAAE,aAAa;YAClB,GAAG,EAAE,cAAc;YACnB,GAAG,EAAE,WAAW;YAChB,GAAG,EAAE,WAAW;SACjB,CAAC;QACF,MAAM,WAAW,GAAG,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC;QAC5F,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,iCAAiC;IACjC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QAC5C,KAAK,EAAE,GAAG,CAAC,OAAO,IAAI,mBAAmB;QACzC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;KACpE,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa;IACzD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,26 @@
1
+ export declare const authRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
2
+ /** Refresh token: more lenient - 401 is expected when unauthenticated (e.g. signup/login page) */
3
+ export declare const refreshRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
4
+ export declare const generalRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
5
+ export declare const strictRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
6
+ /** Contact form: strict limit to prevent abuse and PII flooding (M1) */
7
+ export declare const contactRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
8
+ /** Redirect endpoint: stricter than general to reduce abuse/crawler load (M4) */
9
+ export declare const redirectRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
10
+ /** API token creation: limit to prevent abuse */
11
+ export declare const tokenCreateRateLimiter: ((req: any, res: any, next: any) => any) | import("express-rate-limit").RateLimitRequestHandler;
12
+ /**
13
+ * Security headers middleware
14
+ */
15
+ export declare function setupSecurityHeaders(): (req: import("http").IncomingMessage, res: import("http").ServerResponse, next: (err?: unknown) => void) => void;
16
+ /**
17
+ * CSRF protection middleware (custom implementation for JWT-based auth)
18
+ * Generates and validates CSRF tokens stored in httpOnly cookies
19
+ * Note: SameSite=strict cookies provide good CSRF protection, but tokens add defense in depth
20
+ */
21
+ export declare function csrfProtection(req: any, res: any, next: any): any;
22
+ /**
23
+ * Generate CSRF token and set cookie
24
+ */
25
+ export declare function generateCSRFToken(req: any, res: any): string;
26
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/middleware/security.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,eAAe,SAFE,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAWhD,CAAC;AAEP,kGAAkG;AAClG,eAAO,MAAM,kBAAkB,SAdD,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAuBhD,CAAC;AAEP,eAAO,MAAM,kBAAkB,SAzBD,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAgChD,CAAC;AAEP,eAAO,MAAM,iBAAiB,SAlCA,GAAG,OAAO,GAAG,QAAQ,GAAG,gEA0ChD,CAAC;AAEP,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,SA7CD,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAqDhD,CAAC;AAEP,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,SAxDF,GAAG,OAAO,GAAG,QAAQ,GAAG,gEAgEhD,CAAC;AAEP,iDAAiD;AACjD,eAAO,MAAM,sBAAsB,SAnEL,GAAG,OAAO,GAAG,QAAQ,GAAG,gEA2EhD,CAAC;AAEP;;GAEG;AACH,wBAAgB,oBAAoB,wFA8ElC,CAAD,4BApCA;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,OAmB3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,CAe5D"}
@@ -0,0 +1,162 @@
1
+ import rateLimit from 'express-rate-limit';
2
+ import helmet from 'helmet';
3
+ import crypto from 'crypto';
4
+ /**
5
+ * Rate limiting configuration
6
+ * Disabled in development for easier testing
7
+ */
8
+ const isDevelopment = process.env.NODE_ENV === 'development';
9
+ // No-op rate limiter for development (allows all requests)
10
+ const noOpRateLimiter = (req, res, next) => next();
11
+ export const authRateLimiter = isDevelopment
12
+ ? noOpRateLimiter
13
+ : rateLimit({
14
+ windowMs: 15 * 60 * 1000, // 15 minutes
15
+ max: 300, // Limit each IP to 300 failed auth attempts per windowMs
16
+ message: 'Too many authentication attempts, please try again later.',
17
+ standardHeaders: true,
18
+ legacyHeaders: false,
19
+ skipSuccessfulRequests: true, // Don't count successful requests
20
+ });
21
+ /** Refresh token: more lenient - 401 is expected when unauthenticated (e.g. signup/login page) */
22
+ export const refreshRateLimiter = isDevelopment
23
+ ? noOpRateLimiter
24
+ : rateLimit({
25
+ windowMs: 15 * 60 * 1000,
26
+ max: 500, // Higher limit; failures are often from unauthenticated users checking /auth/me
27
+ message: 'Too many requests, please try again later.',
28
+ standardHeaders: true,
29
+ legacyHeaders: false,
30
+ skipSuccessfulRequests: true,
31
+ });
32
+ export const generalRateLimiter = isDevelopment
33
+ ? noOpRateLimiter
34
+ : rateLimit({
35
+ windowMs: 15 * 60 * 1000, // 15 minutes
36
+ max: 2000, // Limit each IP to 2000 requests per windowMs
37
+ standardHeaders: true,
38
+ legacyHeaders: false,
39
+ });
40
+ export const strictRateLimiter = isDevelopment
41
+ ? noOpRateLimiter
42
+ : rateLimit({
43
+ windowMs: 15 * 60 * 1000, // 15 minutes
44
+ max: 500, // Limit each IP to 500 requests per windowMs
45
+ message: 'Too many requests, please try again later.',
46
+ standardHeaders: true,
47
+ legacyHeaders: false,
48
+ });
49
+ /** Contact form: strict limit to prevent abuse and PII flooding (M1) */
50
+ export const contactRateLimiter = isDevelopment
51
+ ? noOpRateLimiter
52
+ : rateLimit({
53
+ windowMs: 60 * 60 * 1000, // 1 hour
54
+ max: 10,
55
+ message: 'Too many contact form submissions. Please try again later.',
56
+ standardHeaders: true,
57
+ legacyHeaders: false,
58
+ });
59
+ /** Redirect endpoint: stricter than general to reduce abuse/crawler load (M4) */
60
+ export const redirectRateLimiter = isDevelopment
61
+ ? noOpRateLimiter
62
+ : rateLimit({
63
+ windowMs: 15 * 60 * 1000, // 15 minutes
64
+ max: 200,
65
+ message: 'Too many redirect requests. Please try again later.',
66
+ standardHeaders: true,
67
+ legacyHeaders: false,
68
+ });
69
+ /** API token creation: limit to prevent abuse */
70
+ export const tokenCreateRateLimiter = isDevelopment
71
+ ? noOpRateLimiter
72
+ : rateLimit({
73
+ windowMs: 15 * 60 * 1000, // 15 minutes
74
+ max: 10,
75
+ message: 'Too many token creation attempts. Please try again later.',
76
+ standardHeaders: true,
77
+ legacyHeaders: false,
78
+ });
79
+ /**
80
+ * Security headers middleware
81
+ */
82
+ export function setupSecurityHeaders() {
83
+ // Only enable HSTS if we're actually using HTTPS
84
+ const baseUrl = process.env.BASE_URL || 'http://localhost:5000';
85
+ const isHttps = baseUrl.startsWith('https://');
86
+ const cspDirectives = {
87
+ defaultSrc: ["'self'"],
88
+ styleSrc: ["'self'", "'unsafe-inline'"], // Swagger UI needs inline styles
89
+ scriptSrc: ["'self'"],
90
+ imgSrc: ["'self'", "data:", "https:"], // Allow data URIs and HTTPS images (for favicons)
91
+ connectSrc: [
92
+ "'self'",
93
+ // Sentry error tracking (ingest endpoints vary by region)
94
+ "https://*.ingest.sentry.io",
95
+ "https://*.ingest.de.sentry.io",
96
+ "https://*.ingest.eu.sentry.io",
97
+ ],
98
+ fontSrc: ["'self'"],
99
+ objectSrc: ["'none'"],
100
+ mediaSrc: ["'self'"],
101
+ frameSrc: ["'self'"], // Allow iframes for Swagger UI
102
+ };
103
+ // Only upgrade insecure requests when using HTTPS (set to null to disable when using HTTP)
104
+ if (isHttps) {
105
+ cspDirectives.upgradeInsecureRequests = [];
106
+ }
107
+ else {
108
+ cspDirectives.upgradeInsecureRequests = null; // Explicitly disable when using HTTP
109
+ }
110
+ return helmet({
111
+ contentSecurityPolicy: {
112
+ directives: cspDirectives,
113
+ },
114
+ crossOriginEmbedderPolicy: false, // Disable for compatibility
115
+ crossOriginOpenerPolicy: false, // Disable for compatibility (can cause issues with HTTP)
116
+ hsts: isHttps ? {
117
+ maxAge: 31536000, // 1 year
118
+ includeSubDomains: true,
119
+ preload: true,
120
+ } : false, // Disable HSTS when not using HTTPS
121
+ });
122
+ }
123
+ /**
124
+ * CSRF protection middleware (custom implementation for JWT-based auth)
125
+ * Generates and validates CSRF tokens stored in httpOnly cookies
126
+ * Note: SameSite=strict cookies provide good CSRF protection, but tokens add defense in depth
127
+ */
128
+ export function csrfProtection(req, res, next) {
129
+ // Get token from header or body
130
+ const token = req.headers['x-csrf-token'] || req.body?.csrfToken;
131
+ const cookieToken = req.cookies?._csrf;
132
+ // If no cookie token exists, generate one (for first request)
133
+ if (!cookieToken) {
134
+ generateCSRFToken(req, res);
135
+ // Allow first request to proceed (they'll get token in response)
136
+ return next();
137
+ }
138
+ // Validate token for state-changing operations
139
+ if (token && token === cookieToken) {
140
+ return next();
141
+ }
142
+ // If token doesn't match, return error
143
+ return res.status(403).json({ error: 'Invalid CSRF token' });
144
+ }
145
+ /**
146
+ * Generate CSRF token and set cookie
147
+ */
148
+ export function generateCSRFToken(req, res) {
149
+ const token = crypto.randomBytes(32).toString('hex');
150
+ // Only use secure cookies when actually using HTTPS (check BASE_URL)
151
+ const baseUrl = process.env.BASE_URL || 'http://localhost:5000';
152
+ const isHttps = baseUrl.startsWith('https://');
153
+ const isProduction = process.env.NODE_ENV === 'production' && isHttps;
154
+ res.cookie('_csrf', token, {
155
+ httpOnly: true,
156
+ secure: isProduction, // Only secure when using HTTPS
157
+ sameSite: 'strict',
158
+ maxAge: 24 * 60 * 60 * 1000, // 24 hours
159
+ });
160
+ return token;
161
+ }
162
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/middleware/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Secret-based auth for stats endpoint.
3
+ * Uses X-Stats-Secret header; constant-time comparison; returns 404 on invalid (no info leak).
4
+ */
5
+ import { Request, Response, NextFunction } from 'express';
6
+ export declare function statsSecretAuth(req: Request, res: Response, next: NextFunction): void;
7
+ //# sourceMappingURL=stats-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-auth.d.ts","sourceRoot":"","sources":["../../src/middleware/stats-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAgBrF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Secret-based auth for stats endpoint.
3
+ * Uses X-Stats-Secret header; constant-time comparison; returns 404 on invalid (no info leak).
4
+ */
5
+ import crypto from 'crypto';
6
+ export function statsSecretAuth(req, res, next) {
7
+ const secret = process.env.STATS_ENDPOINT_SECRET?.trim();
8
+ if (!secret) {
9
+ res.status(404).end();
10
+ return;
11
+ }
12
+ const headerSecret = req.headers['x-stats-secret'];
13
+ const provided = typeof headerSecret === 'string' ? headerSecret : '';
14
+ if (provided.length !== secret.length || !crypto.timingSafeEqual(Buffer.from(provided, 'utf8'), Buffer.from(secret, 'utf8'))) {
15
+ res.status(404).end();
16
+ return;
17
+ }
18
+ next();
19
+ }
20
+ //# sourceMappingURL=stats-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-auth.js","sourceRoot":"","sources":["../../src/middleware/stats-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC7E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAC;IACzD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtE,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7H,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Request, Response, NextFunction } from 'express';
2
+ export declare function tenantMiddleware(req: Request, _res: Response, next: NextFunction): void;
3
+ //# sourceMappingURL=tenant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG/D,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAYvF"}
@@ -0,0 +1,13 @@
1
+ import { DEFAULT_TENANT_ID } from '../utils/tenant.js';
2
+ export function tenantMiddleware(req, _res, next) {
3
+ let tenantId = DEFAULT_TENANT_ID;
4
+ if (process.env.NODE_ENV === 'test') {
5
+ const testTenant = req.header('x-test-tenant')?.trim();
6
+ if (testTenant) {
7
+ tenantId = testTenant;
8
+ }
9
+ }
10
+ req.tenantId = tenantId;
11
+ next();
12
+ }
13
+ //# sourceMappingURL=tenant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/middleware/tenant.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,UAAU,gBAAgB,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC/E,IAAI,QAAQ,GAAG,iBAAiB,CAAC;IAEjC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACpC,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC;QACvD,IAAI,UAAU,EAAE,CAAC;YACf,QAAQ,GAAG,UAAU,CAAC;QACxB,CAAC;IACH,CAAC;IAEA,GAAuC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7D,IAAI,EAAE,CAAC;AACT,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Mounts all core API routes and /go slug routes on the Express app.
3
+ * Does NOT add static file serving or error handlers.
4
+ */
5
+ import express from 'express';
6
+ export interface CoreRouteDeps {
7
+ }
8
+ /**
9
+ * Register all core API and /go routes. Call after createApp().
10
+ */
11
+ export declare function registerCoreRoutes(app: express.Express, _deps?: CoreRouteDeps): void;
12
+ //# sourceMappingURL=register-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-routes.d.ts","sourceRoot":"","sources":["../src/register-routes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAqB9B,MAAM,WAAW,aAAa;CAE7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAiCpF"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Mounts all core API routes and /go slug routes on the Express app.
3
+ * Does NOT add static file serving or error handlers.
4
+ */
5
+ import authRoutes from './routes/auth.js';
6
+ import bookmarkRoutes from './routes/bookmarks.js';
7
+ import folderRoutes from './routes/folders.js';
8
+ import tagRoutes from './routes/tags.js';
9
+ import goRoutes, { optionalAuthForGo, handleGoSlug, handleGoRemember } from './routes/go.js';
10
+ import userRoutes from './routes/users.js';
11
+ import teamRoutes from './routes/teams.js';
12
+ import oidcProviderRoutes from './routes/oidc-providers.js';
13
+ import adminUserRoutes from './routes/admin/users.js';
14
+ import adminTeamRoutes from './routes/admin/teams.js';
15
+ import adminSettingsRoutes from './routes/admin/settings.js';
16
+ import adminStatsRoutes from './routes/admin/stats.js';
17
+ import passwordResetRoutes from './routes/password-reset.js';
18
+ import emailVerificationRoutes from './routes/email-verification.js';
19
+ import dashboardRoutes from './routes/dashboard.js';
20
+ import healthRoutes from './routes/health.js';
21
+ import tokenRoutes from './routes/tokens.js';
22
+ import configRoutes from './routes/config.js';
23
+ import { redirectRateLimiter } from './middleware/security.js';
24
+ /**
25
+ * Register all core API and /go routes. Call after createApp().
26
+ */
27
+ export function registerCoreRoutes(app, _deps) {
28
+ app.use('/api/auth', authRoutes);
29
+ app.use('/api/password-reset', passwordResetRoutes);
30
+ app.use('/api/email-verification', emailVerificationRoutes);
31
+ app.use('/api/bookmarks', bookmarkRoutes);
32
+ app.use('/api/folders', folderRoutes);
33
+ app.use('/api/tags', tagRoutes);
34
+ app.use('/api/users', userRoutes);
35
+ app.use('/api/teams', teamRoutes);
36
+ app.use('/api/tokens', tokenRoutes);
37
+ app.use('/api/config', configRoutes);
38
+ app.use('/api/oidc-providers', oidcProviderRoutes);
39
+ app.use('/api/admin/users', adminUserRoutes);
40
+ app.use('/api/admin/teams', adminTeamRoutes);
41
+ app.use('/api/admin/settings', adminSettingsRoutes);
42
+ app.use('/api/admin/stats', adminStatsRoutes);
43
+ app.use('/api/dashboard', dashboardRoutes);
44
+ app.use('/api', healthRoutes);
45
+ app.use('/api/go', goRoutes);
46
+ if (process.env.SENTRY_DEBUG === 'true') {
47
+ app.get('/api/debug-sentry', () => {
48
+ throw new Error('Sentry backend test error');
49
+ });
50
+ }
51
+ app.get('/go/:slug/remember/:bookmarkId', redirectRateLimiter, optionalAuthForGo, (req, res) => {
52
+ handleGoRemember(req, res).catch((err) => {
53
+ console.error('Go remember error:', err);
54
+ res.status(500).send('Internal Server Error');
55
+ });
56
+ });
57
+ app.get('/go/:slug', redirectRateLimiter, optionalAuthForGo, handleGoSlug);
58
+ }
59
+ //# sourceMappingURL=register-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-routes.js","sourceRoot":"","sources":["../src/register-routes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,cAAc,MAAM,uBAAuB,CAAC;AACnD,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,SAAS,MAAM,kBAAkB,CAAC;AACzC,OAAO,QAAQ,EAAE,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,kBAAkB,MAAM,4BAA4B,CAAC;AAC5D,OAAO,eAAe,MAAM,yBAAyB,CAAC;AACtD,OAAO,eAAe,MAAM,yBAAyB,CAAC;AACtD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AACvD,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,uBAAuB,MAAM,gCAAgC,CAAC;AACrE,OAAO,eAAe,MAAM,uBAAuB,CAAC;AACpD,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,WAAW,MAAM,oBAAoB,CAAC;AAC7C,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAM/D;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAoB,EAAE,KAAqB;IAC5E,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,CAAC;IACpD,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,uBAAuB,CAAC,CAAC;IAC5D,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAC1C,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;IACtC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAChC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAClC,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAClC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACpC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IACrC,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAAC;IACnD,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IAC7C,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC;IAC7C,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,CAAC;IACpD,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;IAC9C,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;IAC3C,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC9B,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAE7B,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;QACxC,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,GAAG,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,GAAG,CAAC,gCAAgC,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC7F,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACvC,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;YACzC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Demo reset endpoint
3
+ * Only available when DEMO_MODE is enabled
4
+ * Allows manual triggering of database reset
5
+ */
6
+ declare const router: import("express-serve-static-core").Router;
7
+ export default router;
8
+ //# sourceMappingURL=demo-reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo-reset.d.ts","sourceRoot":"","sources":["../../../src/routes/admin/demo-reset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,QAAA,MAAM,MAAM,4CAAW,CAAC;AA4DxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Demo reset endpoint
3
+ * Only available when DEMO_MODE is enabled
4
+ * Allows manual triggering of database reset
5
+ */
6
+ import { Router } from 'express';
7
+ import { resetDatabase } from '../../db/seed.js';
8
+ import { requireAuth } from '../../middleware/auth.js';
9
+ const router = Router();
10
+ /**
11
+ * @swagger
12
+ * /api/admin/demo-reset:
13
+ * post:
14
+ * summary: Reset demo database
15
+ * description: Resets the database to initial demo state. Only available when DEMO_MODE=true. Requires admin authentication.
16
+ * tags: [Admin]
17
+ * security:
18
+ * - cookieAuth: []
19
+ * - bearerAuth: []
20
+ * responses:
21
+ * 200:
22
+ * description: Database reset completed successfully
23
+ * content:
24
+ * application/json:
25
+ * schema:
26
+ * type: object
27
+ * properties:
28
+ * message:
29
+ * type: string
30
+ * example: "Database reset completed successfully"
31
+ * 403:
32
+ * description: Not authorized (not admin) or DEMO_MODE not enabled
33
+ * 500:
34
+ * description: Internal server error
35
+ */
36
+ router.post('/', requireAuth(), async (req, res) => {
37
+ try {
38
+ // Only allow in DEMO_MODE
39
+ if (process.env.DEMO_MODE !== 'true') {
40
+ return res.status(403).json({
41
+ error: 'Demo reset is only available when DEMO_MODE is enabled',
42
+ });
43
+ }
44
+ // Check if user is admin
45
+ const authReq = req;
46
+ if (!authReq.user || !authReq.user.is_admin) {
47
+ return res.status(403).json({ error: 'Admin access required' });
48
+ }
49
+ // Perform reset
50
+ console.log('🔄 Manual database reset triggered by admin');
51
+ await resetDatabase();
52
+ res.json({
53
+ message: 'Database reset completed successfully',
54
+ });
55
+ }
56
+ catch (error) {
57
+ console.error('Error resetting database:', error);
58
+ res.status(500).json({
59
+ error: process.env.NODE_ENV === 'production'
60
+ ? 'Internal server error'
61
+ : error.message,
62
+ });
63
+ }
64
+ });
65
+ export default router;
66
+ //# sourceMappingURL=demo-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo-reset.js","sourceRoot":"","sources":["../../../src/routes/admin/demo-reset.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAe,MAAM,0BAA0B,CAAC;AAEpE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACjD,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YACrC,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBAC1B,KAAK,EAAE,wDAAwD;aAChE,CAAC,CAAC;QACL,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,GAAkB,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,gBAAgB;QAChB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,MAAM,aAAa,EAAE,CAAC;QAEtB,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,uCAAuC;SACjD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;QAClD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;gBAC1C,CAAC,CAAC,uBAAuB;gBACzB,CAAC,CAAC,KAAK,CAAC,OAAO;SAClB,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/routes/admin/settings.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA2dxB,eAAe,MAAM,CAAC"}