@teleporthq/teleport-plugin-next-workflows 0.44.11 → 0.45.0

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 (976) hide show
  1. package/__tests__/_helpers/fake-fetch.ts +75 -0
  2. package/__tests__/_helpers/gui-place-order-statements.ts +17 -0
  3. package/__tests__/_helpers/inserted-lines.ts +22 -0
  4. package/__tests__/_helpers/invoice-store.ts +10 -1
  5. package/__tests__/_helpers/load-security-runtime.ts +45 -0
  6. package/__tests__/_helpers/load-server-runtime.ts +26 -3
  7. package/__tests__/_helpers/run-account-delete-route.ts +3 -1
  8. package/__tests__/_helpers/run-generated-middleware.ts +7 -2
  9. package/__tests__/account-delete-owned-rows.test.ts +3 -1
  10. package/__tests__/adopted-element-trigger-code.test.ts +128 -0
  11. package/__tests__/analytics-track-outcome.test.ts +145 -0
  12. package/__tests__/auth-password-change-ends-sessions.test.ts +8 -1
  13. package/__tests__/auth-password-security.test.ts +2275 -0
  14. package/__tests__/auth-session-cost.test.ts +31 -0
  15. package/__tests__/auth-signup-route.test.ts +960 -0
  16. package/__tests__/authored-code-every-path.test.ts +247 -0
  17. package/__tests__/automations-bus.test.ts +3820 -0
  18. package/__tests__/automations-catalog-drift.test.ts +97 -0
  19. package/__tests__/booking-calendar-feed-route.test.ts +20 -3
  20. package/__tests__/cart-price-order.test.ts +336 -1
  21. package/__tests__/code-lookup-rate-limit-route.test.ts +189 -0
  22. package/__tests__/cost-bearing-node-types.test.ts +119 -0
  23. package/__tests__/credential-columns-reply.test.ts +9 -0
  24. package/__tests__/credential-result-reply.test.ts +19 -5
  25. package/__tests__/cron-route-loop-templateparams.test.ts +6 -3
  26. package/__tests__/custom-js-authored-code.test.ts +304 -0
  27. package/__tests__/custom-node-custom-code-gate.test.ts +136 -0
  28. package/__tests__/custom-node-step-handlers.test.ts +251 -0
  29. package/__tests__/custom-node-step-reach.test.ts +63 -0
  30. package/__tests__/data-api-anon-user-id-fallback.test.ts +7 -2
  31. package/__tests__/data-api-browser-reads.test.ts +7 -0
  32. package/__tests__/data-api-business-events.test.ts +403 -0
  33. package/__tests__/data-api-invalid-body.test.ts +7 -0
  34. package/__tests__/data-api-low-stock-autofire.test.ts +30 -4
  35. package/__tests__/data-api-optional-feature-columns.test.ts +44 -0
  36. package/__tests__/data-api-owner-scope-credentials.test.ts +1324 -0
  37. package/__tests__/data-api-protected-tables.test.ts +48 -15
  38. package/__tests__/data-api-retired-table-and-account-fields.test.ts +208 -0
  39. package/__tests__/email-locale-senders.test.ts +5 -3
  40. package/__tests__/expression-injection.test.ts +343 -0
  41. package/__tests__/fixtures/admin-file-workflows.json +242 -0
  42. package/__tests__/form-confirmation-email-template.test.ts +44 -0
  43. package/__tests__/internal-request-headers.test.ts +25 -0
  44. package/__tests__/invoice-pdf-service-project-header.test.ts +120 -0
  45. package/__tests__/invoice-self-call-origin.test.ts +57 -1
  46. package/__tests__/legacy-webhook-self-calls.test.ts +86 -1
  47. package/__tests__/middleware-home-route-protection.test.ts +3 -1
  48. package/__tests__/middleware-subscriber-access.test.ts +1 -1
  49. package/__tests__/newsletter-admin-route.test.ts +649 -0
  50. package/__tests__/newsletter-plugin.test.ts +1248 -0
  51. package/__tests__/outbound-nodes-security.test.ts +1929 -0
  52. package/__tests__/page-access-guard.test.ts +217 -0
  53. package/__tests__/page-access-route-table.test.ts +231 -0
  54. package/__tests__/payment-drivers-module.test.ts +23 -0
  55. package/__tests__/payment-legacy-webhook-routes.test.ts +100 -5
  56. package/__tests__/payment-webhook-route.test.ts +4 -1
  57. package/__tests__/paypal-webhook-signature-verification.test.ts +44 -0
  58. package/__tests__/place-order-guards.test.ts +506 -0
  59. package/__tests__/public-step-guards.test.ts +310 -0
  60. package/__tests__/publish-refusals.test.ts +505 -0
  61. package/__tests__/realtime-identity-routes.test.ts +492 -0
  62. package/__tests__/record-event-writer-server-only.test.ts +975 -0
  63. package/__tests__/resolve-config-template-params.test.ts +3 -3
  64. package/__tests__/runtime-storage-upload-access.test.ts +280 -17
  65. package/__tests__/security-integration-env-names.test.ts +74 -0
  66. package/__tests__/security-lists-parity.test.ts +245 -0
  67. package/__tests__/security-runtime-shadow.test.ts +224 -1
  68. package/__tests__/security-runtime.test.ts +893 -0
  69. package/__tests__/segment-rate-limit-error-branch.test.ts +284 -0
  70. package/__tests__/segment-route-abuse-gate.test.ts +309 -0
  71. package/__tests__/server-job-hops-real-data-api.test.ts +669 -0
  72. package/__tests__/server-session-identity.test.ts +522 -0
  73. package/__tests__/server-step-chain.test.ts +222 -0
  74. package/__tests__/server-step-signing.test.ts +107 -2
  75. package/__tests__/session-cookie-resolver.test.ts +62 -106
  76. package/__tests__/signup-event.test.ts +649 -0
  77. package/__tests__/signup-reply-identical.test.ts +144 -0
  78. package/__tests__/slack-message-escaping.test.ts +123 -0
  79. package/__tests__/visitor-step-limits.test.ts +318 -0
  80. package/__tests__/webhook-delivery-lease.test.ts +4 -1
  81. package/__tests__/webpack-safe-handlers.test.ts +57 -8
  82. package/__tests__/workflow-auth-guard.test.ts +9 -1
  83. package/dist/cjs/account-delete-route-generator.d.ts +1 -0
  84. package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
  85. package/dist/cjs/account-delete-route-generator.js +18 -3
  86. package/dist/cjs/account-delete-route-generator.js.map +1 -1
  87. package/dist/cjs/api-route-generator.d.ts +52 -3
  88. package/dist/cjs/api-route-generator.d.ts.map +1 -1
  89. package/dist/cjs/api-route-generator.js +600 -145
  90. package/dist/cjs/api-route-generator.js.map +1 -1
  91. package/dist/cjs/auth-generator.d.ts +126 -3
  92. package/dist/cjs/auth-generator.d.ts.map +1 -1
  93. package/dist/cjs/auth-generator.js +1353 -139
  94. package/dist/cjs/auth-generator.js.map +1 -1
  95. package/dist/cjs/automations/activity-kicks.d.ts +12 -0
  96. package/dist/cjs/automations/activity-kicks.d.ts.map +1 -0
  97. package/dist/cjs/automations/activity-kicks.js +123 -0
  98. package/dist/cjs/automations/activity-kicks.js.map +1 -0
  99. package/dist/cjs/automations/app-events-source.d.ts +33 -0
  100. package/dist/cjs/automations/app-events-source.d.ts.map +1 -0
  101. package/dist/cjs/automations/app-events-source.js +109 -0
  102. package/dist/cjs/automations/app-events-source.js.map +1 -0
  103. package/dist/cjs/automations/automations-project-plugin.d.ts +21 -0
  104. package/dist/cjs/automations/automations-project-plugin.d.ts.map +1 -0
  105. package/dist/cjs/automations/automations-project-plugin.js +102 -0
  106. package/dist/cjs/automations/automations-project-plugin.js.map +1 -0
  107. package/dist/cjs/automations/automations-scope.d.ts +104 -0
  108. package/dist/cjs/automations/automations-scope.d.ts.map +1 -0
  109. package/dist/cjs/automations/automations-scope.js +176 -0
  110. package/dist/cjs/automations/automations-scope.js.map +1 -0
  111. package/dist/cjs/automations/dispatcher-source.d.ts +72 -0
  112. package/dist/cjs/automations/dispatcher-source.d.ts.map +1 -0
  113. package/dist/cjs/automations/dispatcher-source.js +1008 -0
  114. package/dist/cjs/automations/dispatcher-source.js.map +1 -0
  115. package/dist/cjs/automations/event-bus-source.d.ts +44 -0
  116. package/dist/cjs/automations/event-bus-source.d.ts.map +1 -0
  117. package/dist/cjs/automations/event-bus-source.js +427 -0
  118. package/dist/cjs/automations/event-bus-source.js.map +1 -0
  119. package/dist/cjs/automations/handler-module-generator.d.ts +25 -0
  120. package/dist/cjs/automations/handler-module-generator.d.ts.map +1 -0
  121. package/dist/cjs/automations/handler-module-generator.js +78 -0
  122. package/dist/cjs/automations/handler-module-generator.js.map +1 -0
  123. package/dist/cjs/automations/hydrators-source.d.ts +33 -0
  124. package/dist/cjs/automations/hydrators-source.d.ts.map +1 -0
  125. package/dist/cjs/automations/hydrators-source.js +571 -0
  126. package/dist/cjs/automations/hydrators-source.js.map +1 -0
  127. package/dist/cjs/booking-calendar-feed-route-generator.d.ts.map +1 -1
  128. package/dist/cjs/booking-calendar-feed-route-generator.js +8 -0
  129. package/dist/cjs/booking-calendar-feed-route-generator.js.map +1 -1
  130. package/dist/cjs/configured-nextauth-url.d.ts +17 -0
  131. package/dist/cjs/configured-nextauth-url.d.ts.map +1 -0
  132. package/dist/cjs/configured-nextauth-url.js +20 -0
  133. package/dist/cjs/configured-nextauth-url.js.map +1 -0
  134. package/dist/cjs/cron-request-verification.d.ts +22 -1
  135. package/dist/cjs/cron-request-verification.d.ts.map +1 -1
  136. package/dist/cjs/cron-request-verification.js +50 -6
  137. package/dist/cjs/cron-request-verification.js.map +1 -1
  138. package/dist/cjs/data-api-route-generator.d.ts +19 -0
  139. package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
  140. package/dist/cjs/data-api-route-generator.js +711 -43
  141. package/dist/cjs/data-api-route-generator.js.map +1 -1
  142. package/dist/cjs/ecommerce/parameterized-stock-chain.d.ts +3 -1
  143. package/dist/cjs/ecommerce/parameterized-stock-chain.d.ts.map +1 -1
  144. package/dist/cjs/ecommerce/parameterized-stock-chain.js +45 -5
  145. package/dist/cjs/ecommerce/parameterized-stock-chain.js.map +1 -1
  146. package/dist/cjs/ecommerce/place-order-guards.d.ts +126 -0
  147. package/dist/cjs/ecommerce/place-order-guards.d.ts.map +1 -0
  148. package/dist/cjs/ecommerce/place-order-guards.js +670 -0
  149. package/dist/cjs/ecommerce/place-order-guards.js.map +1 -0
  150. package/dist/cjs/ecommerce-customhandler-rewriter.d.ts +2 -0
  151. package/dist/cjs/ecommerce-customhandler-rewriter.d.ts.map +1 -1
  152. package/dist/cjs/ecommerce-customhandler-rewriter.js +38 -2
  153. package/dist/cjs/ecommerce-customhandler-rewriter.js.map +1 -1
  154. package/dist/cjs/executor-generator.d.ts.map +1 -1
  155. package/dist/cjs/executor-generator.js +368 -60
  156. package/dist/cjs/executor-generator.js.map +1 -1
  157. package/dist/cjs/graph-utils.d.ts +9 -0
  158. package/dist/cjs/graph-utils.d.ts.map +1 -1
  159. package/dist/cjs/graph-utils.js +32 -1
  160. package/dist/cjs/graph-utils.js.map +1 -1
  161. package/dist/cjs/index.d.ts +20 -1
  162. package/dist/cjs/index.d.ts.map +1 -1
  163. package/dist/cjs/index.js +72 -2
  164. package/dist/cjs/index.js.map +1 -1
  165. package/dist/cjs/invoice/api-routes-code.d.ts +9 -3
  166. package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
  167. package/dist/cjs/invoice/api-routes-code.js +9 -7
  168. package/dist/cjs/invoice/api-routes-code.js.map +1 -1
  169. package/dist/cjs/invoice/index.d.ts.map +1 -1
  170. package/dist/cjs/invoice/index.js +12 -7
  171. package/dist/cjs/invoice/index.js.map +1 -1
  172. package/dist/cjs/invoice/invoice-assembly-code.d.ts.map +1 -1
  173. package/dist/cjs/invoice/invoice-assembly-code.js +8 -3
  174. package/dist/cjs/invoice/invoice-assembly-code.js.map +1 -1
  175. package/dist/cjs/invoice/pdf-generator-code.d.ts.map +1 -1
  176. package/dist/cjs/invoice/pdf-generator-code.js +2 -1
  177. package/dist/cjs/invoice/pdf-generator-code.js.map +1 -1
  178. package/dist/cjs/invoice/pdf-service-client-code.d.ts.map +1 -1
  179. package/dist/cjs/invoice/pdf-service-client-code.js +15 -7
  180. package/dist/cjs/invoice/pdf-service-client-code.js.map +1 -1
  181. package/dist/cjs/newsletter/admin-route-code.d.ts +60 -0
  182. package/dist/cjs/newsletter/admin-route-code.d.ts.map +1 -0
  183. package/dist/cjs/newsletter/admin-route-code.js +300 -0
  184. package/dist/cjs/newsletter/admin-route-code.js.map +1 -0
  185. package/dist/cjs/newsletter/helper-code.d.ts +109 -0
  186. package/dist/cjs/newsletter/helper-code.d.ts.map +1 -0
  187. package/dist/cjs/newsletter/helper-code.js +662 -0
  188. package/dist/cjs/newsletter/helper-code.js.map +1 -0
  189. package/dist/cjs/newsletter/newsletter-scope.d.ts +65 -0
  190. package/dist/cjs/newsletter/newsletter-scope.d.ts.map +1 -0
  191. package/dist/cjs/newsletter/newsletter-scope.js +103 -0
  192. package/dist/cjs/newsletter/newsletter-scope.js.map +1 -0
  193. package/dist/cjs/newsletter/project-plugin.d.ts +18 -0
  194. package/dist/cjs/newsletter/project-plugin.d.ts.map +1 -0
  195. package/dist/cjs/newsletter/project-plugin.js +97 -0
  196. package/dist/cjs/newsletter/project-plugin.js.map +1 -0
  197. package/dist/cjs/newsletter/routes-code.d.ts +6 -0
  198. package/dist/cjs/newsletter/routes-code.d.ts.map +1 -0
  199. package/dist/cjs/newsletter/routes-code.js +181 -0
  200. package/dist/cjs/newsletter/routes-code.js.map +1 -0
  201. package/dist/cjs/nodes/account/account-compare-passwords.d.ts.map +1 -1
  202. package/dist/cjs/nodes/account/account-compare-passwords.js +16 -6
  203. package/dist/cjs/nodes/account/account-compare-passwords.js.map +1 -1
  204. package/dist/cjs/nodes/account/account-delete-current.js +1 -1
  205. package/dist/cjs/nodes/account/account-get-current.js +1 -1
  206. package/dist/cjs/nodes/account/account-hash-password.d.ts.map +1 -1
  207. package/dist/cjs/nodes/account/account-hash-password.js +15 -3
  208. package/dist/cjs/nodes/account/account-hash-password.js.map +1 -1
  209. package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
  210. package/dist/cjs/nodes/account/account-login.js +23 -6
  211. package/dist/cjs/nodes/account/account-login.js.map +1 -1
  212. package/dist/cjs/nodes/account/account-logout.js +1 -1
  213. package/dist/cjs/nodes/account/account-refresh-session.js +1 -1
  214. package/dist/cjs/nodes/account/account-request-password-reset.d.ts +3 -0
  215. package/dist/cjs/nodes/account/account-request-password-reset.d.ts.map +1 -0
  216. package/dist/cjs/nodes/account/account-request-password-reset.js +46 -0
  217. package/dist/cjs/nodes/account/account-request-password-reset.js.map +1 -0
  218. package/dist/cjs/nodes/account/account-reset-password.d.ts +3 -0
  219. package/dist/cjs/nodes/account/account-reset-password.d.ts.map +1 -0
  220. package/dist/cjs/nodes/account/account-reset-password.js +44 -0
  221. package/dist/cjs/nodes/account/account-reset-password.js.map +1 -0
  222. package/dist/cjs/nodes/account/account-signup.d.ts.map +1 -1
  223. package/dist/cjs/nodes/account/account-signup.js +82 -19
  224. package/dist/cjs/nodes/account/account-signup.js.map +1 -1
  225. package/dist/cjs/nodes/account/account-social-login.js +1 -1
  226. package/dist/cjs/nodes/ai/ai-custom-prompt.d.ts.map +1 -1
  227. package/dist/cjs/nodes/ai/ai-custom-prompt.js +20 -5
  228. package/dist/cjs/nodes/ai/ai-custom-prompt.js.map +1 -1
  229. package/dist/cjs/nodes/ai/ai-detect-language.d.ts.map +1 -1
  230. package/dist/cjs/nodes/ai/ai-detect-language.js +20 -5
  231. package/dist/cjs/nodes/ai/ai-detect-language.js.map +1 -1
  232. package/dist/cjs/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
  233. package/dist/cjs/nodes/ai/ai-generate-text-embedding.js +10 -2
  234. package/dist/cjs/nodes/ai/ai-generate-text-embedding.js.map +1 -1
  235. package/dist/cjs/nodes/ai/ai-provider-utils-sources.generated.js +2 -2
  236. package/dist/cjs/nodes/ai/ai-provider-utils-sources.generated.js.map +1 -1
  237. package/dist/cjs/nodes/ai/ai-provider-utils.d.ts +31 -2
  238. package/dist/cjs/nodes/ai/ai-provider-utils.d.ts.map +1 -1
  239. package/dist/cjs/nodes/ai/ai-provider-utils.js +125 -11
  240. package/dist/cjs/nodes/ai/ai-provider-utils.js.map +1 -1
  241. package/dist/cjs/nodes/ai/ai-select-database-data.d.ts.map +1 -1
  242. package/dist/cjs/nodes/ai/ai-select-database-data.js +6 -2
  243. package/dist/cjs/nodes/ai/ai-select-database-data.js.map +1 -1
  244. package/dist/cjs/nodes/ai/ai-sentiment-analysis.d.ts.map +1 -1
  245. package/dist/cjs/nodes/ai/ai-sentiment-analysis.js +20 -5
  246. package/dist/cjs/nodes/ai/ai-sentiment-analysis.js.map +1 -1
  247. package/dist/cjs/nodes/ai/ai-summarization.d.ts.map +1 -1
  248. package/dist/cjs/nodes/ai/ai-summarization.js +20 -5
  249. package/dist/cjs/nodes/ai/ai-summarization.js.map +1 -1
  250. package/dist/cjs/nodes/ai/ai-text-classifier.d.ts.map +1 -1
  251. package/dist/cjs/nodes/ai/ai-text-classifier.js +20 -5
  252. package/dist/cjs/nodes/ai/ai-text-classifier.js.map +1 -1
  253. package/dist/cjs/nodes/ai/ai-text-transform.d.ts.map +1 -1
  254. package/dist/cjs/nodes/ai/ai-text-transform.js +20 -5
  255. package/dist/cjs/nodes/ai/ai-text-transform.js.map +1 -1
  256. package/dist/cjs/nodes/analytics/analytics-track-outcome.d.ts +3 -0
  257. package/dist/cjs/nodes/analytics/analytics-track-outcome.d.ts.map +1 -0
  258. package/dist/cjs/nodes/analytics/analytics-track-outcome.js +110 -0
  259. package/dist/cjs/nodes/analytics/analytics-track-outcome.js.map +1 -0
  260. package/dist/cjs/nodes/cart/cart-price-order.d.ts.map +1 -1
  261. package/dist/cjs/nodes/cart/cart-price-order.js +161 -2
  262. package/dist/cjs/nodes/cart/cart-price-order.js.map +1 -1
  263. package/dist/cjs/nodes/cost-bearing-node-types.d.ts +4 -0
  264. package/dist/cjs/nodes/cost-bearing-node-types.d.ts.map +1 -0
  265. package/dist/cjs/nodes/cost-bearing-node-types.js +43 -0
  266. package/dist/cjs/nodes/cost-bearing-node-types.js.map +1 -0
  267. package/dist/cjs/nodes/data/data-select.d.ts.map +1 -1
  268. package/dist/cjs/nodes/data/data-select.js +12 -2
  269. package/dist/cjs/nodes/data/data-select.js.map +1 -1
  270. package/dist/cjs/nodes/email/email-mailersend.d.ts.map +1 -1
  271. package/dist/cjs/nodes/email/email-mailersend.js +15 -11
  272. package/dist/cjs/nodes/email/email-mailersend.js.map +1 -1
  273. package/dist/cjs/nodes/email/email-mailgun.d.ts.map +1 -1
  274. package/dist/cjs/nodes/email/email-mailgun.js +15 -15
  275. package/dist/cjs/nodes/email/email-mailgun.js.map +1 -1
  276. package/dist/cjs/nodes/email/email-postmark.d.ts.map +1 -1
  277. package/dist/cjs/nodes/email/email-postmark.js +15 -15
  278. package/dist/cjs/nodes/email/email-postmark.js.map +1 -1
  279. package/dist/cjs/nodes/email/email-resend.d.ts.map +1 -1
  280. package/dist/cjs/nodes/email/email-resend.js +15 -15
  281. package/dist/cjs/nodes/email/email-resend.js.map +1 -1
  282. package/dist/cjs/nodes/email/email-sendgrid.d.ts.map +1 -1
  283. package/dist/cjs/nodes/email/email-sendgrid.js +15 -15
  284. package/dist/cjs/nodes/email/email-sendgrid.js.map +1 -1
  285. package/dist/cjs/nodes/email/html-escape-code.d.ts +3 -0
  286. package/dist/cjs/nodes/email/html-escape-code.d.ts.map +1 -0
  287. package/dist/cjs/nodes/email/html-escape-code.js +23 -0
  288. package/dist/cjs/nodes/email/html-escape-code.js.map +1 -0
  289. package/dist/cjs/nodes/email/message-trust.d.ts +40 -0
  290. package/dist/cjs/nodes/email/message-trust.d.ts.map +1 -0
  291. package/dist/cjs/nodes/email/message-trust.js +167 -0
  292. package/dist/cjs/nodes/email/message-trust.js.map +1 -0
  293. package/dist/cjs/nodes/email/outbound-message-guard.d.ts +113 -0
  294. package/dist/cjs/nodes/email/outbound-message-guard.d.ts.map +1 -0
  295. package/dist/cjs/nodes/email/outbound-message-guard.js +460 -0
  296. package/dist/cjs/nodes/email/outbound-message-guard.js.map +1 -0
  297. package/dist/cjs/nodes/email/trusted-html-code.d.ts +22 -0
  298. package/dist/cjs/nodes/email/trusted-html-code.d.ts.map +1 -0
  299. package/dist/cjs/nodes/email/trusted-html-code.js +52 -0
  300. package/dist/cjs/nodes/email/trusted-html-code.js.map +1 -0
  301. package/dist/cjs/nodes/general/general-custom-js.d.ts.map +1 -1
  302. package/dist/cjs/nodes/general/general-custom-js.js +44 -7
  303. package/dist/cjs/nodes/general/general-custom-js.js.map +1 -1
  304. package/dist/cjs/nodes/general/general-http-request.d.ts.map +1 -1
  305. package/dist/cjs/nodes/general/general-http-request.js +431 -45
  306. package/dist/cjs/nodes/general/general-http-request.js.map +1 -1
  307. package/dist/cjs/nodes/general/general-rate-limiter.d.ts.map +1 -1
  308. package/dist/cjs/nodes/general/general-rate-limiter.js +46 -78
  309. package/dist/cjs/nodes/general/general-rate-limiter.js.map +1 -1
  310. package/dist/cjs/nodes/general/general-wait.d.ts +3 -0
  311. package/dist/cjs/nodes/general/general-wait.d.ts.map +1 -0
  312. package/dist/cjs/nodes/general/general-wait.js +81 -0
  313. package/dist/cjs/nodes/general/general-wait.js.map +1 -0
  314. package/dist/cjs/nodes/general/visitor-request.d.ts +44 -0
  315. package/dist/cjs/nodes/general/visitor-request.d.ts.map +1 -0
  316. package/dist/cjs/nodes/general/visitor-request.js +72 -0
  317. package/dist/cjs/nodes/general/visitor-request.js.map +1 -0
  318. package/dist/cjs/nodes/index.d.ts.map +1 -1
  319. package/dist/cjs/nodes/index.js +7 -1
  320. package/dist/cjs/nodes/index.js.map +1 -1
  321. package/dist/cjs/nodes/integrations/integration-slack.d.ts.map +1 -1
  322. package/dist/cjs/nodes/integrations/integration-slack.js +17 -6
  323. package/dist/cjs/nodes/integrations/integration-slack.js.map +1 -1
  324. package/dist/cjs/nodes/newsletter/newsletter-confirm.d.ts +3 -0
  325. package/dist/cjs/nodes/newsletter/newsletter-confirm.d.ts.map +1 -0
  326. package/dist/cjs/nodes/newsletter/newsletter-confirm.js +41 -0
  327. package/dist/cjs/nodes/newsletter/newsletter-confirm.js.map +1 -0
  328. package/dist/cjs/nodes/newsletter/newsletter-subscribe.d.ts +7 -0
  329. package/dist/cjs/nodes/newsletter/newsletter-subscribe.d.ts.map +1 -0
  330. package/dist/cjs/nodes/newsletter/newsletter-subscribe.js +69 -0
  331. package/dist/cjs/nodes/newsletter/newsletter-subscribe.js.map +1 -0
  332. package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.d.ts +3 -0
  333. package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.d.ts.map +1 -0
  334. package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.js +42 -0
  335. package/dist/cjs/nodes/newsletter/newsletter-unsubscribe.js.map +1 -0
  336. package/dist/cjs/nodes/realtime/realtime-join-channel.d.ts.map +1 -1
  337. package/dist/cjs/nodes/realtime/realtime-join-channel.js +5 -4
  338. package/dist/cjs/nodes/realtime/realtime-join-channel.js.map +1 -1
  339. package/dist/cjs/nodes/realtime/realtime-send-channel-event.d.ts.map +1 -1
  340. package/dist/cjs/nodes/realtime/realtime-send-channel-event.js +11 -2
  341. package/dist/cjs/nodes/realtime/realtime-send-channel-event.js.map +1 -1
  342. package/dist/cjs/nodes/realtime/realtime-send-channel-message.d.ts.map +1 -1
  343. package/dist/cjs/nodes/realtime/realtime-send-channel-message.js +11 -2
  344. package/dist/cjs/nodes/realtime/realtime-send-channel-message.js.map +1 -1
  345. package/dist/cjs/nodes/sms/sms-infobip.d.ts.map +1 -1
  346. package/dist/cjs/nodes/sms/sms-infobip.js +11 -8
  347. package/dist/cjs/nodes/sms/sms-infobip.js.map +1 -1
  348. package/dist/cjs/nodes/sms/sms-smsapi.d.ts.map +1 -1
  349. package/dist/cjs/nodes/sms/sms-smsapi.js +11 -8
  350. package/dist/cjs/nodes/sms/sms-smsapi.js.map +1 -1
  351. package/dist/cjs/nodes/sms/sms-textmagic.d.ts.map +1 -1
  352. package/dist/cjs/nodes/sms/sms-textmagic.js +11 -8
  353. package/dist/cjs/nodes/sms/sms-textmagic.js.map +1 -1
  354. package/dist/cjs/nodes/sms/sms-twilio.d.ts.map +1 -1
  355. package/dist/cjs/nodes/sms/sms-twilio.js +12 -10
  356. package/dist/cjs/nodes/sms/sms-twilio.js.map +1 -1
  357. package/dist/cjs/nodes/types.d.ts +8 -1
  358. package/dist/cjs/nodes/types.d.ts.map +1 -1
  359. package/dist/cjs/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
  360. package/dist/cjs/nodes/utility/utility-similarity-scoring.js +29 -10
  361. package/dist/cjs/nodes/utility/utility-similarity-scoring.js.map +1 -1
  362. package/dist/cjs/page-access-guard-generator.d.ts +23 -0
  363. package/dist/cjs/page-access-guard-generator.d.ts.map +1 -0
  364. package/dist/cjs/page-access-guard-generator.js +135 -0
  365. package/dist/cjs/page-access-guard-generator.js.map +1 -0
  366. package/dist/cjs/password-reset-route-generator.d.ts +119 -0
  367. package/dist/cjs/password-reset-route-generator.d.ts.map +1 -0
  368. package/dist/cjs/password-reset-route-generator.js +460 -0
  369. package/dist/cjs/password-reset-route-generator.js.map +1 -0
  370. package/dist/cjs/payments/payment-core-code.d.ts.map +1 -1
  371. package/dist/cjs/payments/payment-core-code.js +12 -7
  372. package/dist/cjs/payments/payment-core-code.js.map +1 -1
  373. package/dist/cjs/project-code-scanner.d.ts +11 -0
  374. package/dist/cjs/project-code-scanner.d.ts.map +1 -0
  375. package/dist/cjs/project-code-scanner.js +80 -0
  376. package/dist/cjs/project-code-scanner.js.map +1 -0
  377. package/dist/cjs/public-step-guards.d.ts +122 -0
  378. package/dist/cjs/public-step-guards.d.ts.map +1 -0
  379. package/dist/cjs/public-step-guards.js +288 -0
  380. package/dist/cjs/public-step-guards.js.map +1 -0
  381. package/dist/cjs/publish-refusals.d.ts +66 -0
  382. package/dist/cjs/publish-refusals.d.ts.map +1 -0
  383. package/dist/cjs/publish-refusals.js +278 -0
  384. package/dist/cjs/publish-refusals.js.map +1 -0
  385. package/dist/cjs/realtime-generator.d.ts +63 -1
  386. package/dist/cjs/realtime-generator.d.ts.map +1 -1
  387. package/dist/cjs/realtime-generator.js +404 -230
  388. package/dist/cjs/realtime-generator.js.map +1 -1
  389. package/dist/cjs/runtime-storage-generator.d.ts +32 -1
  390. package/dist/cjs/runtime-storage-generator.d.ts.map +1 -1
  391. package/dist/cjs/runtime-storage-generator.js +265 -12
  392. package/dist/cjs/runtime-storage-generator.js.map +1 -1
  393. package/dist/cjs/security-runtime/index.d.ts +14 -0
  394. package/dist/cjs/security-runtime/index.d.ts.map +1 -0
  395. package/dist/cjs/security-runtime/index.js +48 -0
  396. package/dist/cjs/security-runtime/index.js.map +1 -0
  397. package/dist/cjs/security-runtime/security-runtime-code.d.ts +53 -0
  398. package/dist/cjs/security-runtime/security-runtime-code.d.ts.map +1 -0
  399. package/dist/cjs/security-runtime/security-runtime-code.js +580 -0
  400. package/dist/cjs/security-runtime/security-runtime-code.js.map +1 -0
  401. package/dist/cjs/security-scanner.d.ts +72 -3
  402. package/dist/cjs/security-scanner.d.ts.map +1 -1
  403. package/dist/cjs/security-scanner.js +220 -8
  404. package/dist/cjs/security-scanner.js.map +1 -1
  405. package/dist/cjs/segment-splitter.d.ts.map +1 -1
  406. package/dist/cjs/segment-splitter.js +10 -2
  407. package/dist/cjs/segment-splitter.js.map +1 -1
  408. package/dist/cjs/segment-trust.d.ts +36 -0
  409. package/dist/cjs/segment-trust.d.ts.map +1 -1
  410. package/dist/cjs/segment-trust.js +147 -3
  411. package/dist/cjs/segment-trust.js.map +1 -1
  412. package/dist/cjs/self-call-headers.d.ts +31 -0
  413. package/dist/cjs/self-call-headers.d.ts.map +1 -0
  414. package/dist/cjs/self-call-headers.js +48 -0
  415. package/dist/cjs/self-call-headers.js.map +1 -0
  416. package/dist/cjs/sent-email-log/index.d.ts +7 -0
  417. package/dist/cjs/sent-email-log/index.d.ts.map +1 -1
  418. package/dist/cjs/sent-email-log/index.js +17 -1
  419. package/dist/cjs/sent-email-log/index.js.map +1 -1
  420. package/dist/cjs/sent-email-log/sent-email-log-code.d.ts +7 -0
  421. package/dist/cjs/sent-email-log/sent-email-log-code.d.ts.map +1 -1
  422. package/dist/cjs/sent-email-log/sent-email-log-code.js +17 -3
  423. package/dist/cjs/sent-email-log/sent-email-log-code.js.map +1 -1
  424. package/dist/cjs/server-custom-node-call.d.ts +79 -0
  425. package/dist/cjs/server-custom-node-call.d.ts.map +1 -0
  426. package/dist/cjs/server-custom-node-call.js +285 -0
  427. package/dist/cjs/server-custom-node-call.js.map +1 -0
  428. package/dist/cjs/server-runtime-code.d.ts +39 -12
  429. package/dist/cjs/server-runtime-code.d.ts.map +1 -1
  430. package/dist/cjs/server-runtime-code.js +484 -41
  431. package/dist/cjs/server-runtime-code.js.map +1 -1
  432. package/dist/cjs/session-cookie-resolver.d.ts +3 -1
  433. package/dist/cjs/session-cookie-resolver.d.ts.map +1 -1
  434. package/dist/cjs/session-revocation-generator.d.ts +39 -0
  435. package/dist/cjs/session-revocation-generator.d.ts.map +1 -0
  436. package/dist/cjs/session-revocation-generator.js +177 -0
  437. package/dist/cjs/session-revocation-generator.js.map +1 -0
  438. package/dist/cjs/slack-message-values.d.ts +6 -0
  439. package/dist/cjs/slack-message-values.d.ts.map +1 -0
  440. package/dist/cjs/slack-message-values.js +73 -0
  441. package/dist/cjs/slack-message-values.js.map +1 -0
  442. package/dist/cjs/transactional-email-code.d.ts +11 -0
  443. package/dist/cjs/transactional-email-code.d.ts.map +1 -1
  444. package/dist/cjs/transactional-email-code.js +29 -5
  445. package/dist/cjs/transactional-email-code.js.map +1 -1
  446. package/dist/cjs/trigger-generator.d.ts +2 -0
  447. package/dist/cjs/trigger-generator.d.ts.map +1 -1
  448. package/dist/cjs/trigger-generator.js +17 -4
  449. package/dist/cjs/trigger-generator.js.map +1 -1
  450. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  451. package/dist/cjs/visitor-step-limits.d.ts +66 -0
  452. package/dist/cjs/visitor-step-limits.d.ts.map +1 -0
  453. package/dist/cjs/visitor-step-limits.js +187 -0
  454. package/dist/cjs/visitor-step-limits.js.map +1 -0
  455. package/dist/cjs/webhook-generator.d.ts.map +1 -1
  456. package/dist/cjs/webhook-generator.js +93 -15
  457. package/dist/cjs/webhook-generator.js.map +1 -1
  458. package/dist/cjs/webhook-signature-verification.d.ts.map +1 -1
  459. package/dist/cjs/webhook-signature-verification.js +13 -3
  460. package/dist/cjs/webhook-signature-verification.js.map +1 -1
  461. package/dist/cjs/workflow-auth-generator.d.ts +4 -1
  462. package/dist/cjs/workflow-auth-generator.d.ts.map +1 -1
  463. package/dist/cjs/workflow-auth-generator.js +8 -3
  464. package/dist/cjs/workflow-auth-generator.js.map +1 -1
  465. package/dist/cjs/workflow-component-plugin.js +11 -3
  466. package/dist/cjs/workflow-component-plugin.js.map +1 -1
  467. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  468. package/dist/cjs/workflow-project-plugin.js +302 -56
  469. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  470. package/dist/cjs/workflow-scope.d.ts.map +1 -1
  471. package/dist/cjs/workflow-scope.js +5 -0
  472. package/dist/cjs/workflow-scope.js.map +1 -1
  473. package/dist/esm/account-delete-route-generator.d.ts +1 -0
  474. package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
  475. package/dist/esm/account-delete-route-generator.js +18 -3
  476. package/dist/esm/account-delete-route-generator.js.map +1 -1
  477. package/dist/esm/api-route-generator.d.ts +52 -3
  478. package/dist/esm/api-route-generator.d.ts.map +1 -1
  479. package/dist/esm/api-route-generator.js +595 -142
  480. package/dist/esm/api-route-generator.js.map +1 -1
  481. package/dist/esm/auth-generator.d.ts +126 -3
  482. package/dist/esm/auth-generator.d.ts.map +1 -1
  483. package/dist/esm/auth-generator.js +1350 -140
  484. package/dist/esm/auth-generator.js.map +1 -1
  485. package/dist/esm/automations/activity-kicks.d.ts +12 -0
  486. package/dist/esm/automations/activity-kicks.d.ts.map +1 -0
  487. package/dist/esm/automations/activity-kicks.js +118 -0
  488. package/dist/esm/automations/activity-kicks.js.map +1 -0
  489. package/dist/esm/automations/app-events-source.d.ts +33 -0
  490. package/dist/esm/automations/app-events-source.d.ts.map +1 -0
  491. package/dist/esm/automations/app-events-source.js +104 -0
  492. package/dist/esm/automations/app-events-source.js.map +1 -0
  493. package/dist/esm/automations/automations-project-plugin.d.ts +21 -0
  494. package/dist/esm/automations/automations-project-plugin.d.ts.map +1 -0
  495. package/dist/esm/automations/automations-project-plugin.js +98 -0
  496. package/dist/esm/automations/automations-project-plugin.js.map +1 -0
  497. package/dist/esm/automations/automations-scope.d.ts +104 -0
  498. package/dist/esm/automations/automations-scope.d.ts.map +1 -0
  499. package/dist/esm/automations/automations-scope.js +165 -0
  500. package/dist/esm/automations/automations-scope.js.map +1 -0
  501. package/dist/esm/automations/dispatcher-source.d.ts +72 -0
  502. package/dist/esm/automations/dispatcher-source.d.ts.map +1 -0
  503. package/dist/esm/automations/dispatcher-source.js +999 -0
  504. package/dist/esm/automations/dispatcher-source.js.map +1 -0
  505. package/dist/esm/automations/event-bus-source.d.ts +44 -0
  506. package/dist/esm/automations/event-bus-source.d.ts.map +1 -0
  507. package/dist/esm/automations/event-bus-source.js +421 -0
  508. package/dist/esm/automations/event-bus-source.js.map +1 -0
  509. package/dist/esm/automations/handler-module-generator.d.ts +25 -0
  510. package/dist/esm/automations/handler-module-generator.d.ts.map +1 -0
  511. package/dist/esm/automations/handler-module-generator.js +71 -0
  512. package/dist/esm/automations/handler-module-generator.js.map +1 -0
  513. package/dist/esm/automations/hydrators-source.d.ts +33 -0
  514. package/dist/esm/automations/hydrators-source.d.ts.map +1 -0
  515. package/dist/esm/automations/hydrators-source.js +567 -0
  516. package/dist/esm/automations/hydrators-source.js.map +1 -0
  517. package/dist/esm/booking-calendar-feed-route-generator.d.ts.map +1 -1
  518. package/dist/esm/booking-calendar-feed-route-generator.js +8 -0
  519. package/dist/esm/booking-calendar-feed-route-generator.js.map +1 -1
  520. package/dist/esm/configured-nextauth-url.d.ts +17 -0
  521. package/dist/esm/configured-nextauth-url.d.ts.map +1 -0
  522. package/dist/esm/configured-nextauth-url.js +17 -0
  523. package/dist/esm/configured-nextauth-url.js.map +1 -0
  524. package/dist/esm/cron-request-verification.d.ts +22 -1
  525. package/dist/esm/cron-request-verification.d.ts.map +1 -1
  526. package/dist/esm/cron-request-verification.js +48 -5
  527. package/dist/esm/cron-request-verification.js.map +1 -1
  528. package/dist/esm/data-api-route-generator.d.ts +19 -0
  529. package/dist/esm/data-api-route-generator.d.ts.map +1 -1
  530. package/dist/esm/data-api-route-generator.js +710 -43
  531. package/dist/esm/data-api-route-generator.js.map +1 -1
  532. package/dist/esm/ecommerce/parameterized-stock-chain.d.ts +3 -1
  533. package/dist/esm/ecommerce/parameterized-stock-chain.d.ts.map +1 -1
  534. package/dist/esm/ecommerce/parameterized-stock-chain.js +43 -4
  535. package/dist/esm/ecommerce/parameterized-stock-chain.js.map +1 -1
  536. package/dist/esm/ecommerce/place-order-guards.d.ts +126 -0
  537. package/dist/esm/ecommerce/place-order-guards.d.ts.map +1 -0
  538. package/dist/esm/ecommerce/place-order-guards.js +655 -0
  539. package/dist/esm/ecommerce/place-order-guards.js.map +1 -0
  540. package/dist/esm/ecommerce-customhandler-rewriter.d.ts +2 -0
  541. package/dist/esm/ecommerce-customhandler-rewriter.d.ts.map +1 -1
  542. package/dist/esm/ecommerce-customhandler-rewriter.js +38 -2
  543. package/dist/esm/ecommerce-customhandler-rewriter.js.map +1 -1
  544. package/dist/esm/executor-generator.d.ts.map +1 -1
  545. package/dist/esm/executor-generator.js +368 -60
  546. package/dist/esm/executor-generator.js.map +1 -1
  547. package/dist/esm/graph-utils.d.ts +9 -0
  548. package/dist/esm/graph-utils.d.ts.map +1 -1
  549. package/dist/esm/graph-utils.js +30 -0
  550. package/dist/esm/graph-utils.js.map +1 -1
  551. package/dist/esm/index.d.ts +20 -1
  552. package/dist/esm/index.d.ts.map +1 -1
  553. package/dist/esm/index.js +27 -1
  554. package/dist/esm/index.js.map +1 -1
  555. package/dist/esm/invoice/api-routes-code.d.ts +9 -3
  556. package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
  557. package/dist/esm/invoice/api-routes-code.js +9 -7
  558. package/dist/esm/invoice/api-routes-code.js.map +1 -1
  559. package/dist/esm/invoice/index.d.ts.map +1 -1
  560. package/dist/esm/invoice/index.js +12 -7
  561. package/dist/esm/invoice/index.js.map +1 -1
  562. package/dist/esm/invoice/invoice-assembly-code.d.ts.map +1 -1
  563. package/dist/esm/invoice/invoice-assembly-code.js +8 -3
  564. package/dist/esm/invoice/invoice-assembly-code.js.map +1 -1
  565. package/dist/esm/invoice/pdf-generator-code.d.ts.map +1 -1
  566. package/dist/esm/invoice/pdf-generator-code.js +2 -1
  567. package/dist/esm/invoice/pdf-generator-code.js.map +1 -1
  568. package/dist/esm/invoice/pdf-service-client-code.d.ts.map +1 -1
  569. package/dist/esm/invoice/pdf-service-client-code.js +15 -7
  570. package/dist/esm/invoice/pdf-service-client-code.js.map +1 -1
  571. package/dist/esm/newsletter/admin-route-code.d.ts +60 -0
  572. package/dist/esm/newsletter/admin-route-code.d.ts.map +1 -0
  573. package/dist/esm/newsletter/admin-route-code.js +295 -0
  574. package/dist/esm/newsletter/admin-route-code.js.map +1 -0
  575. package/dist/esm/newsletter/helper-code.d.ts +109 -0
  576. package/dist/esm/newsletter/helper-code.d.ts.map +1 -0
  577. package/dist/esm/newsletter/helper-code.js +656 -0
  578. package/dist/esm/newsletter/helper-code.js.map +1 -0
  579. package/dist/esm/newsletter/newsletter-scope.d.ts +65 -0
  580. package/dist/esm/newsletter/newsletter-scope.d.ts.map +1 -0
  581. package/dist/esm/newsletter/newsletter-scope.js +97 -0
  582. package/dist/esm/newsletter/newsletter-scope.js.map +1 -0
  583. package/dist/esm/newsletter/project-plugin.d.ts +18 -0
  584. package/dist/esm/newsletter/project-plugin.d.ts.map +1 -0
  585. package/dist/esm/newsletter/project-plugin.js +93 -0
  586. package/dist/esm/newsletter/project-plugin.js.map +1 -0
  587. package/dist/esm/newsletter/routes-code.d.ts +6 -0
  588. package/dist/esm/newsletter/routes-code.d.ts.map +1 -0
  589. package/dist/esm/newsletter/routes-code.js +175 -0
  590. package/dist/esm/newsletter/routes-code.js.map +1 -0
  591. package/dist/esm/nodes/account/account-compare-passwords.d.ts.map +1 -1
  592. package/dist/esm/nodes/account/account-compare-passwords.js +16 -6
  593. package/dist/esm/nodes/account/account-compare-passwords.js.map +1 -1
  594. package/dist/esm/nodes/account/account-delete-current.js +1 -1
  595. package/dist/esm/nodes/account/account-get-current.js +1 -1
  596. package/dist/esm/nodes/account/account-hash-password.d.ts.map +1 -1
  597. package/dist/esm/nodes/account/account-hash-password.js +15 -3
  598. package/dist/esm/nodes/account/account-hash-password.js.map +1 -1
  599. package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
  600. package/dist/esm/nodes/account/account-login.js +23 -6
  601. package/dist/esm/nodes/account/account-login.js.map +1 -1
  602. package/dist/esm/nodes/account/account-logout.js +1 -1
  603. package/dist/esm/nodes/account/account-refresh-session.js +1 -1
  604. package/dist/esm/nodes/account/account-request-password-reset.d.ts +3 -0
  605. package/dist/esm/nodes/account/account-request-password-reset.d.ts.map +1 -0
  606. package/dist/esm/nodes/account/account-request-password-reset.js +43 -0
  607. package/dist/esm/nodes/account/account-request-password-reset.js.map +1 -0
  608. package/dist/esm/nodes/account/account-reset-password.d.ts +3 -0
  609. package/dist/esm/nodes/account/account-reset-password.d.ts.map +1 -0
  610. package/dist/esm/nodes/account/account-reset-password.js +41 -0
  611. package/dist/esm/nodes/account/account-reset-password.js.map +1 -0
  612. package/dist/esm/nodes/account/account-signup.d.ts.map +1 -1
  613. package/dist/esm/nodes/account/account-signup.js +82 -19
  614. package/dist/esm/nodes/account/account-signup.js.map +1 -1
  615. package/dist/esm/nodes/account/account-social-login.js +1 -1
  616. package/dist/esm/nodes/ai/ai-custom-prompt.d.ts.map +1 -1
  617. package/dist/esm/nodes/ai/ai-custom-prompt.js +20 -5
  618. package/dist/esm/nodes/ai/ai-custom-prompt.js.map +1 -1
  619. package/dist/esm/nodes/ai/ai-detect-language.d.ts.map +1 -1
  620. package/dist/esm/nodes/ai/ai-detect-language.js +20 -5
  621. package/dist/esm/nodes/ai/ai-detect-language.js.map +1 -1
  622. package/dist/esm/nodes/ai/ai-generate-text-embedding.d.ts.map +1 -1
  623. package/dist/esm/nodes/ai/ai-generate-text-embedding.js +10 -2
  624. package/dist/esm/nodes/ai/ai-generate-text-embedding.js.map +1 -1
  625. package/dist/esm/nodes/ai/ai-provider-utils-sources.generated.js +2 -2
  626. package/dist/esm/nodes/ai/ai-provider-utils-sources.generated.js.map +1 -1
  627. package/dist/esm/nodes/ai/ai-provider-utils.d.ts +31 -2
  628. package/dist/esm/nodes/ai/ai-provider-utils.d.ts.map +1 -1
  629. package/dist/esm/nodes/ai/ai-provider-utils.js +124 -10
  630. package/dist/esm/nodes/ai/ai-provider-utils.js.map +1 -1
  631. package/dist/esm/nodes/ai/ai-select-database-data.d.ts.map +1 -1
  632. package/dist/esm/nodes/ai/ai-select-database-data.js +6 -2
  633. package/dist/esm/nodes/ai/ai-select-database-data.js.map +1 -1
  634. package/dist/esm/nodes/ai/ai-sentiment-analysis.d.ts.map +1 -1
  635. package/dist/esm/nodes/ai/ai-sentiment-analysis.js +20 -5
  636. package/dist/esm/nodes/ai/ai-sentiment-analysis.js.map +1 -1
  637. package/dist/esm/nodes/ai/ai-summarization.d.ts.map +1 -1
  638. package/dist/esm/nodes/ai/ai-summarization.js +20 -5
  639. package/dist/esm/nodes/ai/ai-summarization.js.map +1 -1
  640. package/dist/esm/nodes/ai/ai-text-classifier.d.ts.map +1 -1
  641. package/dist/esm/nodes/ai/ai-text-classifier.js +20 -5
  642. package/dist/esm/nodes/ai/ai-text-classifier.js.map +1 -1
  643. package/dist/esm/nodes/ai/ai-text-transform.d.ts.map +1 -1
  644. package/dist/esm/nodes/ai/ai-text-transform.js +20 -5
  645. package/dist/esm/nodes/ai/ai-text-transform.js.map +1 -1
  646. package/dist/esm/nodes/analytics/analytics-track-outcome.d.ts +3 -0
  647. package/dist/esm/nodes/analytics/analytics-track-outcome.d.ts.map +1 -0
  648. package/dist/esm/nodes/analytics/analytics-track-outcome.js +107 -0
  649. package/dist/esm/nodes/analytics/analytics-track-outcome.js.map +1 -0
  650. package/dist/esm/nodes/cart/cart-price-order.d.ts.map +1 -1
  651. package/dist/esm/nodes/cart/cart-price-order.js +161 -2
  652. package/dist/esm/nodes/cart/cart-price-order.js.map +1 -1
  653. package/dist/esm/nodes/cost-bearing-node-types.d.ts +4 -0
  654. package/dist/esm/nodes/cost-bearing-node-types.d.ts.map +1 -0
  655. package/dist/esm/nodes/cost-bearing-node-types.js +39 -0
  656. package/dist/esm/nodes/cost-bearing-node-types.js.map +1 -0
  657. package/dist/esm/nodes/data/data-select.d.ts.map +1 -1
  658. package/dist/esm/nodes/data/data-select.js +12 -2
  659. package/dist/esm/nodes/data/data-select.js.map +1 -1
  660. package/dist/esm/nodes/email/email-mailersend.d.ts.map +1 -1
  661. package/dist/esm/nodes/email/email-mailersend.js +15 -11
  662. package/dist/esm/nodes/email/email-mailersend.js.map +1 -1
  663. package/dist/esm/nodes/email/email-mailgun.d.ts.map +1 -1
  664. package/dist/esm/nodes/email/email-mailgun.js +15 -15
  665. package/dist/esm/nodes/email/email-mailgun.js.map +1 -1
  666. package/dist/esm/nodes/email/email-postmark.d.ts.map +1 -1
  667. package/dist/esm/nodes/email/email-postmark.js +15 -15
  668. package/dist/esm/nodes/email/email-postmark.js.map +1 -1
  669. package/dist/esm/nodes/email/email-resend.d.ts.map +1 -1
  670. package/dist/esm/nodes/email/email-resend.js +15 -15
  671. package/dist/esm/nodes/email/email-resend.js.map +1 -1
  672. package/dist/esm/nodes/email/email-sendgrid.d.ts.map +1 -1
  673. package/dist/esm/nodes/email/email-sendgrid.js +15 -15
  674. package/dist/esm/nodes/email/email-sendgrid.js.map +1 -1
  675. package/dist/esm/nodes/email/html-escape-code.d.ts +3 -0
  676. package/dist/esm/nodes/email/html-escape-code.d.ts.map +1 -0
  677. package/dist/esm/nodes/email/html-escape-code.js +18 -0
  678. package/dist/esm/nodes/email/html-escape-code.js.map +1 -0
  679. package/dist/esm/nodes/email/message-trust.d.ts +40 -0
  680. package/dist/esm/nodes/email/message-trust.d.ts.map +1 -0
  681. package/dist/esm/nodes/email/message-trust.js +161 -0
  682. package/dist/esm/nodes/email/message-trust.js.map +1 -0
  683. package/dist/esm/nodes/email/outbound-message-guard.d.ts +113 -0
  684. package/dist/esm/nodes/email/outbound-message-guard.d.ts.map +1 -0
  685. package/dist/esm/nodes/email/outbound-message-guard.js +452 -0
  686. package/dist/esm/nodes/email/outbound-message-guard.js.map +1 -0
  687. package/dist/esm/nodes/email/trusted-html-code.d.ts +22 -0
  688. package/dist/esm/nodes/email/trusted-html-code.d.ts.map +1 -0
  689. package/dist/esm/nodes/email/trusted-html-code.js +49 -0
  690. package/dist/esm/nodes/email/trusted-html-code.js.map +1 -0
  691. package/dist/esm/nodes/general/general-custom-js.d.ts.map +1 -1
  692. package/dist/esm/nodes/general/general-custom-js.js +44 -7
  693. package/dist/esm/nodes/general/general-custom-js.js.map +1 -1
  694. package/dist/esm/nodes/general/general-http-request.d.ts.map +1 -1
  695. package/dist/esm/nodes/general/general-http-request.js +431 -45
  696. package/dist/esm/nodes/general/general-http-request.js.map +1 -1
  697. package/dist/esm/nodes/general/general-rate-limiter.d.ts.map +1 -1
  698. package/dist/esm/nodes/general/general-rate-limiter.js +46 -78
  699. package/dist/esm/nodes/general/general-rate-limiter.js.map +1 -1
  700. package/dist/esm/nodes/general/general-wait.d.ts +3 -0
  701. package/dist/esm/nodes/general/general-wait.d.ts.map +1 -0
  702. package/dist/esm/nodes/general/general-wait.js +78 -0
  703. package/dist/esm/nodes/general/general-wait.js.map +1 -0
  704. package/dist/esm/nodes/general/visitor-request.d.ts +44 -0
  705. package/dist/esm/nodes/general/visitor-request.d.ts.map +1 -0
  706. package/dist/esm/nodes/general/visitor-request.js +65 -0
  707. package/dist/esm/nodes/general/visitor-request.js.map +1 -0
  708. package/dist/esm/nodes/index.d.ts.map +1 -1
  709. package/dist/esm/nodes/index.js +7 -1
  710. package/dist/esm/nodes/index.js.map +1 -1
  711. package/dist/esm/nodes/integrations/integration-slack.d.ts.map +1 -1
  712. package/dist/esm/nodes/integrations/integration-slack.js +17 -6
  713. package/dist/esm/nodes/integrations/integration-slack.js.map +1 -1
  714. package/dist/esm/nodes/newsletter/newsletter-confirm.d.ts +3 -0
  715. package/dist/esm/nodes/newsletter/newsletter-confirm.d.ts.map +1 -0
  716. package/dist/esm/nodes/newsletter/newsletter-confirm.js +38 -0
  717. package/dist/esm/nodes/newsletter/newsletter-confirm.js.map +1 -0
  718. package/dist/esm/nodes/newsletter/newsletter-subscribe.d.ts +7 -0
  719. package/dist/esm/nodes/newsletter/newsletter-subscribe.d.ts.map +1 -0
  720. package/dist/esm/nodes/newsletter/newsletter-subscribe.js +66 -0
  721. package/dist/esm/nodes/newsletter/newsletter-subscribe.js.map +1 -0
  722. package/dist/esm/nodes/newsletter/newsletter-unsubscribe.d.ts +3 -0
  723. package/dist/esm/nodes/newsletter/newsletter-unsubscribe.d.ts.map +1 -0
  724. package/dist/esm/nodes/newsletter/newsletter-unsubscribe.js +39 -0
  725. package/dist/esm/nodes/newsletter/newsletter-unsubscribe.js.map +1 -0
  726. package/dist/esm/nodes/realtime/realtime-join-channel.d.ts.map +1 -1
  727. package/dist/esm/nodes/realtime/realtime-join-channel.js +5 -4
  728. package/dist/esm/nodes/realtime/realtime-join-channel.js.map +1 -1
  729. package/dist/esm/nodes/realtime/realtime-send-channel-event.d.ts.map +1 -1
  730. package/dist/esm/nodes/realtime/realtime-send-channel-event.js +11 -2
  731. package/dist/esm/nodes/realtime/realtime-send-channel-event.js.map +1 -1
  732. package/dist/esm/nodes/realtime/realtime-send-channel-message.d.ts.map +1 -1
  733. package/dist/esm/nodes/realtime/realtime-send-channel-message.js +11 -2
  734. package/dist/esm/nodes/realtime/realtime-send-channel-message.js.map +1 -1
  735. package/dist/esm/nodes/sms/sms-infobip.d.ts.map +1 -1
  736. package/dist/esm/nodes/sms/sms-infobip.js +11 -8
  737. package/dist/esm/nodes/sms/sms-infobip.js.map +1 -1
  738. package/dist/esm/nodes/sms/sms-smsapi.d.ts.map +1 -1
  739. package/dist/esm/nodes/sms/sms-smsapi.js +11 -8
  740. package/dist/esm/nodes/sms/sms-smsapi.js.map +1 -1
  741. package/dist/esm/nodes/sms/sms-textmagic.d.ts.map +1 -1
  742. package/dist/esm/nodes/sms/sms-textmagic.js +11 -8
  743. package/dist/esm/nodes/sms/sms-textmagic.js.map +1 -1
  744. package/dist/esm/nodes/sms/sms-twilio.d.ts.map +1 -1
  745. package/dist/esm/nodes/sms/sms-twilio.js +12 -10
  746. package/dist/esm/nodes/sms/sms-twilio.js.map +1 -1
  747. package/dist/esm/nodes/types.d.ts +8 -1
  748. package/dist/esm/nodes/types.d.ts.map +1 -1
  749. package/dist/esm/nodes/utility/utility-similarity-scoring.d.ts.map +1 -1
  750. package/dist/esm/nodes/utility/utility-similarity-scoring.js +29 -10
  751. package/dist/esm/nodes/utility/utility-similarity-scoring.js.map +1 -1
  752. package/dist/esm/page-access-guard-generator.d.ts +23 -0
  753. package/dist/esm/page-access-guard-generator.d.ts.map +1 -0
  754. package/dist/esm/page-access-guard-generator.js +131 -0
  755. package/dist/esm/page-access-guard-generator.js.map +1 -0
  756. package/dist/esm/password-reset-route-generator.d.ts +119 -0
  757. package/dist/esm/password-reset-route-generator.d.ts.map +1 -0
  758. package/dist/esm/password-reset-route-generator.js +448 -0
  759. package/dist/esm/password-reset-route-generator.js.map +1 -0
  760. package/dist/esm/payments/payment-core-code.d.ts.map +1 -1
  761. package/dist/esm/payments/payment-core-code.js +12 -7
  762. package/dist/esm/payments/payment-core-code.js.map +1 -1
  763. package/dist/esm/project-code-scanner.d.ts +11 -0
  764. package/dist/esm/project-code-scanner.d.ts.map +1 -0
  765. package/dist/esm/project-code-scanner.js +75 -0
  766. package/dist/esm/project-code-scanner.js.map +1 -0
  767. package/dist/esm/public-step-guards.d.ts +122 -0
  768. package/dist/esm/public-step-guards.d.ts.map +1 -0
  769. package/dist/esm/public-step-guards.js +280 -0
  770. package/dist/esm/public-step-guards.js.map +1 -0
  771. package/dist/esm/publish-refusals.d.ts +66 -0
  772. package/dist/esm/publish-refusals.d.ts.map +1 -0
  773. package/dist/esm/publish-refusals.js +271 -0
  774. package/dist/esm/publish-refusals.js.map +1 -0
  775. package/dist/esm/realtime-generator.d.ts +63 -1
  776. package/dist/esm/realtime-generator.d.ts.map +1 -1
  777. package/dist/esm/realtime-generator.js +401 -229
  778. package/dist/esm/realtime-generator.js.map +1 -1
  779. package/dist/esm/runtime-storage-generator.d.ts +32 -1
  780. package/dist/esm/runtime-storage-generator.d.ts.map +1 -1
  781. package/dist/esm/runtime-storage-generator.js +264 -11
  782. package/dist/esm/runtime-storage-generator.js.map +1 -1
  783. package/dist/esm/security-runtime/index.d.ts +14 -0
  784. package/dist/esm/security-runtime/index.d.ts.map +1 -0
  785. package/dist/esm/security-runtime/index.js +37 -0
  786. package/dist/esm/security-runtime/index.js.map +1 -0
  787. package/dist/esm/security-runtime/security-runtime-code.d.ts +53 -0
  788. package/dist/esm/security-runtime/security-runtime-code.d.ts.map +1 -0
  789. package/dist/esm/security-runtime/security-runtime-code.js +575 -0
  790. package/dist/esm/security-runtime/security-runtime-code.js.map +1 -0
  791. package/dist/esm/security-scanner.d.ts +72 -3
  792. package/dist/esm/security-scanner.d.ts.map +1 -1
  793. package/dist/esm/security-scanner.js +217 -8
  794. package/dist/esm/security-scanner.js.map +1 -1
  795. package/dist/esm/segment-splitter.d.ts.map +1 -1
  796. package/dist/esm/segment-splitter.js +10 -2
  797. package/dist/esm/segment-splitter.js.map +1 -1
  798. package/dist/esm/segment-trust.d.ts +36 -0
  799. package/dist/esm/segment-trust.d.ts.map +1 -1
  800. package/dist/esm/segment-trust.js +146 -2
  801. package/dist/esm/segment-trust.js.map +1 -1
  802. package/dist/esm/self-call-headers.d.ts +31 -0
  803. package/dist/esm/self-call-headers.d.ts.map +1 -0
  804. package/dist/esm/self-call-headers.js +43 -0
  805. package/dist/esm/self-call-headers.js.map +1 -0
  806. package/dist/esm/sent-email-log/index.d.ts +7 -0
  807. package/dist/esm/sent-email-log/index.d.ts.map +1 -1
  808. package/dist/esm/sent-email-log/index.js +15 -0
  809. package/dist/esm/sent-email-log/index.js.map +1 -1
  810. package/dist/esm/sent-email-log/sent-email-log-code.d.ts +7 -0
  811. package/dist/esm/sent-email-log/sent-email-log-code.d.ts.map +1 -1
  812. package/dist/esm/sent-email-log/sent-email-log-code.js +17 -3
  813. package/dist/esm/sent-email-log/sent-email-log-code.js.map +1 -1
  814. package/dist/esm/server-custom-node-call.d.ts +79 -0
  815. package/dist/esm/server-custom-node-call.d.ts.map +1 -0
  816. package/dist/esm/server-custom-node-call.js +278 -0
  817. package/dist/esm/server-custom-node-call.js.map +1 -0
  818. package/dist/esm/server-runtime-code.d.ts +39 -12
  819. package/dist/esm/server-runtime-code.d.ts.map +1 -1
  820. package/dist/esm/server-runtime-code.js +483 -40
  821. package/dist/esm/server-runtime-code.js.map +1 -1
  822. package/dist/esm/session-cookie-resolver.d.ts +3 -1
  823. package/dist/esm/session-cookie-resolver.d.ts.map +1 -1
  824. package/dist/esm/session-revocation-generator.d.ts +39 -0
  825. package/dist/esm/session-revocation-generator.d.ts.map +1 -0
  826. package/dist/esm/session-revocation-generator.js +172 -0
  827. package/dist/esm/session-revocation-generator.js.map +1 -0
  828. package/dist/esm/slack-message-values.d.ts +6 -0
  829. package/dist/esm/slack-message-values.d.ts.map +1 -0
  830. package/dist/esm/slack-message-values.js +68 -0
  831. package/dist/esm/slack-message-values.js.map +1 -0
  832. package/dist/esm/transactional-email-code.d.ts +11 -0
  833. package/dist/esm/transactional-email-code.d.ts.map +1 -1
  834. package/dist/esm/transactional-email-code.js +28 -4
  835. package/dist/esm/transactional-email-code.js.map +1 -1
  836. package/dist/esm/trigger-generator.d.ts +2 -0
  837. package/dist/esm/trigger-generator.d.ts.map +1 -1
  838. package/dist/esm/trigger-generator.js +15 -3
  839. package/dist/esm/trigger-generator.js.map +1 -1
  840. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  841. package/dist/esm/visitor-step-limits.d.ts +66 -0
  842. package/dist/esm/visitor-step-limits.d.ts.map +1 -0
  843. package/dist/esm/visitor-step-limits.js +181 -0
  844. package/dist/esm/visitor-step-limits.js.map +1 -0
  845. package/dist/esm/webhook-generator.d.ts.map +1 -1
  846. package/dist/esm/webhook-generator.js +93 -15
  847. package/dist/esm/webhook-generator.js.map +1 -1
  848. package/dist/esm/webhook-signature-verification.d.ts.map +1 -1
  849. package/dist/esm/webhook-signature-verification.js +13 -3
  850. package/dist/esm/webhook-signature-verification.js.map +1 -1
  851. package/dist/esm/workflow-auth-generator.d.ts +4 -1
  852. package/dist/esm/workflow-auth-generator.d.ts.map +1 -1
  853. package/dist/esm/workflow-auth-generator.js +8 -3
  854. package/dist/esm/workflow-auth-generator.js.map +1 -1
  855. package/dist/esm/workflow-component-plugin.js +12 -4
  856. package/dist/esm/workflow-component-plugin.js.map +1 -1
  857. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  858. package/dist/esm/workflow-project-plugin.js +306 -60
  859. package/dist/esm/workflow-project-plugin.js.map +1 -1
  860. package/dist/esm/workflow-scope.d.ts.map +1 -1
  861. package/dist/esm/workflow-scope.js +5 -0
  862. package/dist/esm/workflow-scope.js.map +1 -1
  863. package/package.json +4 -4
  864. package/src/account-delete-route-generator.ts +28 -4
  865. package/src/api-route-generator.ts +712 -134
  866. package/src/auth-generator.ts +1471 -142
  867. package/src/automations/activity-kicks.ts +139 -0
  868. package/src/automations/app-events-source.ts +117 -0
  869. package/src/automations/automations-project-plugin.ts +202 -0
  870. package/src/automations/automations-scope.ts +196 -0
  871. package/src/automations/dispatcher-source.ts +1072 -0
  872. package/src/automations/event-bus-source.ts +428 -0
  873. package/src/automations/handler-module-generator.ts +107 -0
  874. package/src/automations/hydrators-source.ts +647 -0
  875. package/src/booking-calendar-feed-route-generator.ts +8 -0
  876. package/src/configured-nextauth-url.ts +17 -0
  877. package/src/cron-request-verification.ts +55 -5
  878. package/src/data-api-route-generator.ts +780 -43
  879. package/src/ecommerce/parameterized-stock-chain.ts +52 -5
  880. package/src/ecommerce/place-order-guards.ts +785 -0
  881. package/src/ecommerce-customhandler-rewriter.ts +55 -2
  882. package/src/executor-generator.ts +372 -60
  883. package/src/graph-utils.ts +33 -0
  884. package/src/index.ts +70 -0
  885. package/src/invoice/api-routes-code.ts +20 -7
  886. package/src/invoice/index.ts +11 -6
  887. package/src/invoice/invoice-assembly-code.ts +8 -3
  888. package/src/invoice/pdf-generator-code.ts +2 -1
  889. package/src/invoice/pdf-service-client-code.ts +15 -7
  890. package/src/newsletter/admin-route-code.ts +319 -0
  891. package/src/newsletter/helper-code.ts +748 -0
  892. package/src/newsletter/newsletter-scope.ts +116 -0
  893. package/src/newsletter/project-plugin.ts +119 -0
  894. package/src/newsletter/routes-code.ts +186 -0
  895. package/src/nodes/account/account-compare-passwords.ts +17 -6
  896. package/src/nodes/account/account-delete-current.ts +1 -1
  897. package/src/nodes/account/account-get-current.ts +1 -1
  898. package/src/nodes/account/account-hash-password.ts +19 -3
  899. package/src/nodes/account/account-login.ts +24 -7
  900. package/src/nodes/account/account-logout.ts +1 -1
  901. package/src/nodes/account/account-refresh-session.ts +1 -1
  902. package/src/nodes/account/account-request-password-reset.ts +47 -0
  903. package/src/nodes/account/account-reset-password.ts +45 -0
  904. package/src/nodes/account/account-signup.ts +86 -20
  905. package/src/nodes/account/account-social-login.ts +1 -1
  906. package/src/nodes/ai/ai-custom-prompt.ts +25 -6
  907. package/src/nodes/ai/ai-detect-language.ts +25 -6
  908. package/src/nodes/ai/ai-generate-text-embedding.ts +16 -3
  909. package/src/nodes/ai/ai-provider-utils-sources.generated.ts +2 -2
  910. package/src/nodes/ai/ai-provider-utils.ts +135 -10
  911. package/src/nodes/ai/ai-select-database-data.ts +8 -3
  912. package/src/nodes/ai/ai-sentiment-analysis.ts +25 -6
  913. package/src/nodes/ai/ai-summarization.ts +25 -6
  914. package/src/nodes/ai/ai-text-classifier.ts +25 -6
  915. package/src/nodes/ai/ai-text-transform.ts +25 -6
  916. package/src/nodes/analytics/analytics-track-outcome.ts +111 -0
  917. package/src/nodes/cart/cart-price-order.ts +200 -2
  918. package/src/nodes/cost-bearing-node-types.ts +45 -0
  919. package/src/nodes/data/data-select.ts +11 -2
  920. package/src/nodes/email/email-mailersend.ts +16 -8
  921. package/src/nodes/email/email-mailgun.ts +17 -12
  922. package/src/nodes/email/email-postmark.ts +17 -12
  923. package/src/nodes/email/email-resend.ts +17 -12
  924. package/src/nodes/email/email-sendgrid.ts +17 -12
  925. package/src/nodes/email/html-escape-code.ts +21 -0
  926. package/src/nodes/email/message-trust.ts +198 -0
  927. package/src/nodes/email/outbound-message-guard.ts +572 -0
  928. package/src/nodes/email/trusted-html-code.ts +49 -0
  929. package/src/nodes/general/general-custom-js.ts +46 -7
  930. package/src/nodes/general/general-http-request.ts +449 -46
  931. package/src/nodes/general/general-rate-limiter.ts +54 -81
  932. package/src/nodes/general/general-wait.ts +80 -0
  933. package/src/nodes/general/visitor-request.ts +79 -0
  934. package/src/nodes/index.ts +12 -0
  935. package/src/nodes/integrations/integration-slack.ts +21 -6
  936. package/src/nodes/newsletter/newsletter-confirm.ts +44 -0
  937. package/src/nodes/newsletter/newsletter-subscribe.ts +78 -0
  938. package/src/nodes/newsletter/newsletter-unsubscribe.ts +43 -0
  939. package/src/nodes/realtime/realtime-join-channel.ts +5 -4
  940. package/src/nodes/realtime/realtime-send-channel-event.ts +13 -2
  941. package/src/nodes/realtime/realtime-send-channel-message.ts +13 -2
  942. package/src/nodes/sms/sms-infobip.ts +14 -4
  943. package/src/nodes/sms/sms-smsapi.ts +14 -4
  944. package/src/nodes/sms/sms-textmagic.ts +14 -4
  945. package/src/nodes/sms/sms-twilio.ts +14 -4
  946. package/src/nodes/types.ts +9 -1
  947. package/src/nodes/utility/utility-similarity-scoring.ts +33 -12
  948. package/src/page-access-guard-generator.ts +154 -0
  949. package/src/password-reset-route-generator.ts +531 -0
  950. package/src/payments/payment-core-code.ts +12 -7
  951. package/src/project-code-scanner.ts +98 -0
  952. package/src/public-step-guards.ts +448 -0
  953. package/src/publish-refusals.ts +459 -0
  954. package/src/realtime-generator.ts +457 -234
  955. package/src/runtime-storage-generator.ts +270 -11
  956. package/src/security-runtime/index.ts +53 -0
  957. package/src/security-runtime/security-runtime-code.ts +579 -0
  958. package/src/security-scanner.ts +253 -10
  959. package/src/segment-splitter.ts +10 -2
  960. package/src/segment-trust.ts +205 -2
  961. package/src/self-call-headers.ts +46 -0
  962. package/src/sent-email-log/index.ts +16 -0
  963. package/src/sent-email-log/sent-email-log-code.ts +30 -4
  964. package/src/server-custom-node-call.ts +331 -0
  965. package/src/server-runtime-code.ts +488 -40
  966. package/src/session-revocation-generator.ts +177 -0
  967. package/src/slack-message-values.ts +84 -0
  968. package/src/transactional-email-code.ts +30 -4
  969. package/src/trigger-generator.ts +19 -3
  970. package/src/visitor-step-limits.ts +228 -0
  971. package/src/webhook-generator.ts +94 -14
  972. package/src/webhook-signature-verification.ts +13 -3
  973. package/src/workflow-auth-generator.ts +9 -4
  974. package/src/workflow-component-plugin.ts +14 -4
  975. package/src/workflow-project-plugin.ts +374 -61
  976. package/src/workflow-scope.ts +6 -0
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  UIDLAuthentication,
3
3
  UIDLAuthTableColumn,
4
4
  UIDLCustomUserProperty,
@@ -11,10 +11,39 @@ import {
11
11
  generateFillTemplateFn,
12
12
  generateEmailLocaleRequire,
13
13
  generateLocalizedEmailCopyFn,
14
+ EXISTING_ACCOUNT_EMAIL,
15
+ SET_PASSWORD_EMAIL,
14
16
  WELCOME_EMAIL_CONFIG_KEYS,
15
17
  } from './transactional-email-code'
16
- import { TableAccess } from '@teleporthq/teleport-shared'
18
+ import {
19
+ PASSWORD_RESET_TOKEN_TTL_SECONDS,
20
+ TRUSTED_ORIGIN_CODE,
21
+ resolveResetPagePath,
22
+ } from './password-reset-route-generator'
23
+ import { AccountFields, SessionCookieResolver, TableAccess } from '@teleporthq/teleport-shared'
17
24
  import { generateSessionTokenResolverCode } from './session-cookie-resolver'
25
+ import { AUTOMATIONS_PATH } from './automations/automations-scope'
26
+ import { SESSION_REVOCATION_FILE_NAME, SESSION_STAMP_KEY } from './session-revocation-generator'
27
+ import { securityRuntimeSpecifier } from './security-runtime/security-runtime-code'
28
+
29
+ /**
30
+ * Credentials sign-in throttle: a visitor's next sign-in for an email is
31
+ * refused (429) once this many failures for it are in the window, or once it
32
+ * was tried SIGN_IN_ATTEMPT_LIMIT times in the window whatever the outcome.
33
+ */
34
+ export const SIGN_IN_FAILURE_LIMIT = 10
35
+ export const SIGN_IN_ATTEMPT_LIMIT = 30
36
+ export const SIGN_IN_WINDOW_SECONDS = 900
37
+ /** Failed sign-ins one visitor may make across every email in the window. */
38
+ export const SIGN_IN_VISITOR_FAILURE_LIMIT = 50
39
+ /** Sign-ups per visitor per hour. */
40
+ export const SIGN_UP_LIMIT = 10
41
+ /**
42
+ * "You already have an account" (or, for an address without a password,
43
+ * "Set your password") emails one address can be sent per hour.
44
+ */
45
+ export const EXISTING_ACCOUNT_EMAIL_LIMIT = 3
46
+ export const SIGN_UP_WINDOW_SECONDS = 3600
18
47
 
19
48
  // GUI provider id → the actual next-auth v4 provider MODULE name, for the few
20
49
  // cases where they differ. Everything else uses the id as the module name.
@@ -218,9 +247,6 @@ export const SESSION_SAFE_USER_FIELDS: readonly string[] = [
218
247
  'roles',
219
248
  ]
220
249
 
221
- /** A `users` key the session derives the visitor's role from, in any case. */
222
- const ROLE_BEARING_USER_KEY = /^(roles?|role_?name)$/i
223
-
224
250
  /**
225
251
  * Credentials that must never leave the server, whatever the `users` table
226
252
  * happens to declare: the OAuth single-table adapter's provider tokens plus the
@@ -257,6 +283,13 @@ export const SENSITIVE_USER_FIELDS: readonly string[] = [
257
283
  */
258
284
  const ID_ALIAS_FIELD = '_id'
259
285
 
286
+ /**
287
+ * The Newsletter's own `users` columns (`newsletter_status`, …). A sign-in
288
+ * snapshot of them goes stale the moment the person confirms or unsubscribes,
289
+ * so they never reach the session: a page reads the row.
290
+ */
291
+ const NEWSLETTER_COLUMN_PREFIX = 'newsletter_'
292
+
260
293
  /**
261
294
  * The exact set of `users` columns this project allows into the session.
262
295
  *
@@ -272,7 +305,9 @@ export const buildSessionUserFields = (
272
305
  tables: Record<string, UIDLAuthTableColumn[]> | undefined,
273
306
  customProps: UIDLCustomUserProperty[]
274
307
  ): string[] => {
275
- const declared = (tables?.users || []).map((column) => column.name)
308
+ const declared = (tables?.users || [])
309
+ .map((column) => column.name)
310
+ .filter((name) => !name.startsWith(NEWSLETTER_COLUMN_PREFIX))
276
311
  const custom = customProps.map((prop) => prop.key)
277
312
  const denied = new Set<string>(SENSITIVE_USER_FIELDS)
278
313
 
@@ -373,6 +408,47 @@ const generateCustomPropAirtableEntries = (props: UIDLCustomUserProperty[]): str
373
408
  )
374
409
  }
375
410
 
411
+ /**
412
+ * The `users` columns a sign-up writes itself, never from its form: where the
413
+ * person came from (`source = 'signup'`) and their consent as given
414
+ * (`marketing_consent`, from the "Email me news and offers" box). On the
415
+ * Postgres family `createUser` writes each one it is given, and creates the
416
+ * account without them on a users table made before they existed.
417
+ */
418
+ export const SIGNUP_OWN_COLUMNS: readonly string[] = ['source', 'marketing_consent']
419
+
420
+ /**
421
+ * `findSignupUserByEmail(email)`: the sign-up's own existence check, blind to
422
+ * letter case, so `Ava@site.test` signing up reaches the `ava@site.test` row
423
+ * (a subscriber, a guest, an account) instead of making a second one. The
424
+ * exact address first; else the one row equal to it in any case, none when
425
+ * that is ambiguous. Sign-in keeps its exact `findUserByEmail`. On the other
426
+ * stores it is that exact lookup.
427
+ */
428
+ const generateSignupLookupFunction = (dataSourceType: DataSourceType | null): string => {
429
+ switch (dataSourceType) {
430
+ case 'teleport':
431
+ case 'postgresql':
432
+ case 'cockroachdb':
433
+ return `async function findSignupUserByEmail(email) {
434
+ const client = getClient();
435
+ try {
436
+ await client.connect();
437
+ const exact = await client.query('SELECT * FROM users WHERE email = $1 LIMIT 1', [email]);
438
+ if (exact.rows && exact.rows.length > 0) return exact.rows[0];
439
+ const anyCase = await client.query('SELECT * FROM users WHERE LOWER(email) = LOWER($1) LIMIT 2', [email]);
440
+ return anyCase.rows && anyCase.rows.length === 1 ? anyCase.rows[0] : null;
441
+ } finally {
442
+ try { await client.end(); } catch (_e) {}
443
+ }
444
+ }`
445
+ default:
446
+ return `async function findSignupUserByEmail(email) {
447
+ return findUserByEmail(email);
448
+ }`
449
+ }
450
+ }
451
+
376
452
  const generateFindUserFunction = (
377
453
  dataSourceType: DataSourceType | null,
378
454
  customProps: UIDLCustomUserProperty[]
@@ -390,6 +466,9 @@ async function userExistsByEmail() { return false; }`
390
466
  const customValues = generateCustomPropValues(customProps)
391
467
  const docEntries = generateCustomPropDocEntries(customProps)
392
468
  const airtableEntries = generateCustomPropAirtableEntries(customProps)
469
+ // A declared account property of the same name is already one of the columns.
470
+ const customKeys = new Set(customProps.map((prop) => prop.key))
471
+ const signupOwnColumns = SIGNUP_OWN_COLUMNS.filter((column) => !customKeys.has(column))
393
472
 
394
473
  switch (dataSourceType) {
395
474
  case 'teleport':
@@ -406,14 +485,44 @@ async function userExistsByEmail() { return false; }`
406
485
  }
407
486
  }
408
487
 
488
+ // What a sign-up writes besides its form (where the person came from, their
489
+ // consent as given), each when it is given. A users table made before one of
490
+ // them lacks it (the column is added when a feature that reads it is switched
491
+ // on): the account is then created without them.
492
+ const SIGNUP_OWN_COLUMNS = ${JSON.stringify(signupOwnColumns)};
493
+
409
494
  async function createUser(userData) {
410
495
  const client = getClient();
411
496
  try {
412
497
  await client.connect();
413
- const result = await client.query(
414
- 'INSERT INTO users (name, email, password, role, image${sqlCols}) VALUES ($1, $2, $3, $4, $5${pgPlaceholders}) RETURNING *',
415
- [userData.name || null, userData.email, userData.password, userData.role || 'user', userData.image || null${customValues}]
416
- );
498
+ const values = [userData.name || null, userData.email, userData.password, userData.role || 'user', userData.image || null${customValues}];
499
+ const insert = function (extra) {
500
+ let columns = '';
501
+ let placeholders = '';
502
+ for (let i = 0; i < extra.length; i++) {
503
+ columns += ', ' + extra[i];
504
+ placeholders += ', $' + (values.length + i + 1);
505
+ }
506
+ return client.query(
507
+ 'INSERT INTO users (name, email, password, role, image${sqlCols}' + columns + ') VALUES ($1, $2, $3, $4, $5${pgPlaceholders}' + placeholders + ') RETURNING *',
508
+ values.concat(extra.map(function (column) { return userData[column]; }))
509
+ );
510
+ };
511
+ let extra = SIGNUP_OWN_COLUMNS.filter(function (column) { return userData[column] !== undefined; });
512
+ let result = null;
513
+ while (!result) {
514
+ try {
515
+ result = await insert(extra);
516
+ } catch (err) {
517
+ // 42703 names a column the table does not have. Only that one is left
518
+ // out, and only when it is one of these: the others are still written.
519
+ const named = err && err.code === '42703' ? /column "([^"]+)"/.exec(String(err.message || '')) : null;
520
+ const missing = named ? named[1] : '';
521
+ if (!missing || extra.indexOf(missing) === -1) { throw err; }
522
+ console.warn('[auth] the users table has no ' + missing + ' column yet: the account is created without it');
523
+ extra = extra.filter(function (column) { return column !== missing; });
524
+ }
525
+ }
417
526
  return result.rows && result.rows.length > 0 ? result.rows[0] : null;
418
527
  } finally {
419
528
  try { await client.end(); } catch (_e) {}
@@ -615,6 +724,279 @@ async function userExistsByEmail() { return false; }`
615
724
  }
616
725
  }
617
726
 
727
+ /** Where the password-reset links live: hashed, single-use, per account id. */
728
+ export const PASSWORD_RESETS_TABLE = 'teleport_password_resets'
729
+
730
+ const PG_PASSWORD_RESET_FUNCTIONS = `
731
+ // Password-reset links (pages/api/auth/forgot-password + reset-password). Only
732
+ // the SHA-256 of a link's token is stored, bound to the account id, with its
733
+ // expiry; the table is created on first use. The earlier password_reset_tokens
734
+ // table and its rows are never read.
735
+ var PASSWORD_RESETS_TABLE = '${PASSWORD_RESETS_TABLE}';
736
+ var __passwordResetsTableReady = false;
737
+
738
+ async function ensurePasswordResetsTable(client) {
739
+ if (__passwordResetsTableReady) return;
740
+ await client.query('BEGIN');
741
+ try {
742
+ await client.query('SELECT pg_advisory_xact_lock(hashtext($1))', [PASSWORD_RESETS_TABLE]);
743
+ await client.query(
744
+ 'CREATE TABLE IF NOT EXISTS ' + PASSWORD_RESETS_TABLE + ' (token_hash TEXT PRIMARY KEY, user_id TEXT NOT NULL, ' +
745
+ 'expires_at TIMESTAMPTZ NOT NULL, used_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW())'
746
+ );
747
+ await client.query('CREATE INDEX IF NOT EXISTS ' + PASSWORD_RESETS_TABLE + '_user_id_idx ON ' + PASSWORD_RESETS_TABLE + ' (user_id)');
748
+ await client.query('COMMIT');
749
+ } catch (err) {
750
+ try { await client.query('ROLLBACK'); } catch (_e) {}
751
+ throw err;
752
+ }
753
+ __passwordResetsTableReady = true;
754
+ }
755
+
756
+ // One live link per account: a new one ends the ones sent before it.
757
+ async function storePasswordReset(userId, tokenHash, ttlSeconds) {
758
+ const client = getClient();
759
+ try {
760
+ await client.connect();
761
+ await ensurePasswordResetsTable(client);
762
+ await client.query(
763
+ 'UPDATE ' + PASSWORD_RESETS_TABLE + ' SET used_at = NOW() WHERE user_id = $1 AND used_at IS NULL',
764
+ [String(userId)]
765
+ );
766
+ await client.query(
767
+ 'INSERT INTO ' + PASSWORD_RESETS_TABLE + " (token_hash, user_id, expires_at) VALUES ($1, $2, NOW() + ($3::int * INTERVAL '1 second'))",
768
+ [tokenHash, String(userId), ttlSeconds]
769
+ );
770
+ await client.query(
771
+ 'DELETE FROM ' + PASSWORD_RESETS_TABLE + " WHERE expires_at < NOW() - INTERVAL '1 day'"
772
+ );
773
+ } finally {
774
+ try { await client.end(); } catch (_e) {}
775
+ }
776
+ }
777
+
778
+ // Spends the link and sets the password in ONE statement: the link must be
779
+ // unspent and unexpired, and is spent by this call alone (a second call with the
780
+ // same token finds it used). Returns the account it was for, or null.
781
+ async function consumePasswordReset(tokenHash, passwordHash) {
782
+ const client = getClient();
783
+ try {
784
+ await client.connect();
785
+ const result = await client.query(
786
+ 'WITH consumed AS (' +
787
+ ' UPDATE ' + PASSWORD_RESETS_TABLE + ' SET used_at = NOW()' +
788
+ ' WHERE token_hash = $1 AND used_at IS NULL AND expires_at > NOW()' +
789
+ ' RETURNING user_id' +
790
+ '), changed AS (' +
791
+ ' UPDATE users SET password = $2 FROM consumed WHERE users.id::text = consumed.user_id' +
792
+ ' RETURNING users.id, users.email' +
793
+ ') SELECT id, email FROM changed',
794
+ [tokenHash, passwordHash]
795
+ );
796
+ return result.rows && result.rows.length > 0 ? result.rows[0] : null;
797
+ } catch (err) {
798
+ // 42P01: no link was ever sent, so the table is not there yet.
799
+ if (err && err.code === '42P01') return null;
800
+ throw err;
801
+ } finally {
802
+ try { await client.end(); } catch (_e) {}
803
+ }
804
+ }
805
+
806
+ async function passwordResetIsLive(tokenHash) {
807
+ const client = getClient();
808
+ try {
809
+ await client.connect();
810
+ const result = await client.query(
811
+ 'SELECT 1 FROM ' + PASSWORD_RESETS_TABLE + ' WHERE token_hash = $1 AND used_at IS NULL AND expires_at > NOW() LIMIT 1',
812
+ [tokenHash]
813
+ );
814
+ return !!(result.rows && result.rows.length > 0);
815
+ } catch (err) {
816
+ if (err && err.code === '42P01') return false;
817
+ throw err;
818
+ } finally {
819
+ try { await client.end(); } catch (_e) {}
820
+ }
821
+ }
822
+
823
+ const PASSWORD_RESET_SUPPORTED = true;`
824
+
825
+ const UNSUPPORTED_PASSWORD_RESET_FUNCTIONS = `
826
+ // Password-reset links need a Postgres database; this project's user store is
827
+ // not one, so the reset routes answer without ever sending a link.
828
+ async function storePasswordReset() { throw new Error('Password reset needs a Postgres database'); }
829
+ async function consumePasswordReset() { return null; }
830
+ async function passwordResetIsLive() { return false; }
831
+ const PASSWORD_RESET_SUPPORTED = false;`
832
+
833
+ /**
834
+ * `updateUserPasswordHash(user, newHash, oldHash)` — the sign-in moving a hash
835
+ * onto the project's own pepper. It writes only over the hash it verified, so a
836
+ * reset that landed in between is never undone. Plus the password-reset link
837
+ * store (Postgres family only).
838
+ */
839
+ const generatePasswordStoreFunctions = (dataSourceType: DataSourceType | null): string => {
840
+ switch (dataSourceType) {
841
+ case 'teleport':
842
+ case 'postgresql':
843
+ case 'cockroachdb':
844
+ return `// The account a stamped session was issued for (session-revocation). A value
845
+ // that is not an id of this table's type (22P02) is no account; any other
846
+ // error is thrown, so the session check fails closed.
847
+ async function findUserById(id) {
848
+ const client = getClient();
849
+ try {
850
+ await client.connect();
851
+ const result = await client.query('SELECT * FROM users WHERE id = $1 LIMIT 1', [id]);
852
+ return result.rows && result.rows.length > 0 ? result.rows[0] : null;
853
+ } catch (err) {
854
+ if (err && err.code === '22P02') return null;
855
+ throw err;
856
+ } finally {
857
+ try { await client.end(); } catch (_e) {}
858
+ }
859
+ }
860
+
861
+ async function updateUserPasswordHash(user, newHash, oldHash) {
862
+ const client = getClient();
863
+ try {
864
+ await client.connect();
865
+ const result = await client.query('UPDATE users SET password = $1 WHERE id = $2 AND password = $3', [newHash, user.id, oldHash]);
866
+ return !!(result && result.rowCount > 0);
867
+ } finally {
868
+ try { await client.end(); } catch (_e) {}
869
+ }
870
+ }
871
+ ${PG_PASSWORD_RESET_FUNCTIONS}`
872
+ case 'supabase':
873
+ return `async function findUserById(id) {
874
+ const client = getSupabaseClient();
875
+ const result = await client.from('users').select('*').eq('id', id).maybeSingle();
876
+ if (result.error) throw new Error(result.error.message || 'users lookup failed');
877
+ return result.data || null;
878
+ }
879
+
880
+ async function updateUserPasswordHash(user, newHash, oldHash) {
881
+ const client = getSupabaseClient();
882
+ const result = await client.from('users').update({ password: newHash }).eq('id', user.id).eq('password', oldHash).select('id');
883
+ return !!(result.data && result.data.length > 0);
884
+ }
885
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
886
+ case 'mysql':
887
+ case 'mariadb':
888
+ case 'tidb':
889
+ return `async function findUserById(id) {
890
+ const conn = await getConnection();
891
+ try {
892
+ const [rows] = await conn.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [id]);
893
+ return rows && rows.length > 0 ? rows[0] : null;
894
+ } finally {
895
+ try { await conn.end(); } catch (_e) {}
896
+ }
897
+ }
898
+
899
+ async function updateUserPasswordHash(user, newHash, oldHash) {
900
+ const conn = await getConnection();
901
+ try {
902
+ const [result] = await conn.execute('UPDATE users SET password = ? WHERE id = ? AND password = ?', [newHash, user.id, oldHash]);
903
+ return !!(result && result.affectedRows > 0);
904
+ } finally {
905
+ try { await conn.end(); } catch (_e) {}
906
+ }
907
+ }
908
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
909
+ case 'mongodb':
910
+ return `async function findUserById(id) {
911
+ const client = await _mongoClientPromise;
912
+ const db = client.db();
913
+ const ObjectId = require('mongodb').ObjectId;
914
+ if (!ObjectId.isValid(String(id))) return null;
915
+ return await db.collection('users').findOne({ _id: new ObjectId(String(id)) });
916
+ }
917
+
918
+ async function updateUserPasswordHash(user, newHash, oldHash) {
919
+ const client = await _mongoClientPromise;
920
+ const db = client.db();
921
+ const result = await db.collection('users').updateOne({ _id: user._id, password: oldHash }, { $set: { password: newHash } });
922
+ return !!(result && result.modifiedCount > 0);
923
+ }
924
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
925
+ case 'firestore':
926
+ return `async function findUserById(id) {
927
+ const snap = await firestoreDb.collection('users').doc(String(id)).get();
928
+ return snap.exists ? Object.assign({ id: snap.id }, snap.data()) : null;
929
+ }
930
+
931
+ async function updateUserPasswordHash(user, newHash, oldHash) {
932
+ const ref = firestoreDb.collection('users').doc(String(user.id));
933
+ return firestoreDb.runTransaction(async function (tx) {
934
+ const snap = await tx.get(ref);
935
+ if (!snap.exists || snap.data().password !== oldHash) return false;
936
+ tx.update(ref, { password: newHash });
937
+ return true;
938
+ });
939
+ }
940
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
941
+ case 'turso':
942
+ return `async function findUserById(id) {
943
+ const result = await tursoClient.execute({ sql: 'SELECT * FROM users WHERE id = ? LIMIT 1', args: [id] });
944
+ return result.rows && result.rows.length > 0 ? result.rows[0] : null;
945
+ }
946
+
947
+ async function updateUserPasswordHash(user, newHash, oldHash) {
948
+ const result = await tursoClient.execute({ sql: 'UPDATE users SET password = ? WHERE id = ? AND password = ?', args: [newHash, user.id, oldHash] });
949
+ return !!(result && result.rowsAffected > 0);
950
+ }
951
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
952
+ case 'airtable':
953
+ return `async function findUserById(id) {
954
+ return new Promise(function(resolve, reject) {
955
+ airtableBase('users').find(String(id), function(err, rec) {
956
+ if (err && (err.statusCode === 404 || err.error === 'NOT_FOUND')) { resolve(null); return; }
957
+ if (err) { reject(err); return; }
958
+ resolve(rec ? Object.assign({ id: rec.id }, rec.fields) : null);
959
+ });
960
+ });
961
+ }
962
+
963
+ async function updateUserPasswordHash(user, newHash, oldHash) {
964
+ const current = await findUserByEmail(user.email);
965
+ if (!current || current.password !== oldHash) return false;
966
+ await new Promise(function(resolve, reject) {
967
+ airtableBase('users').update(String(user.id), { password: newHash }, function(err) { if (err) { reject(err); } else { resolve(); } });
968
+ });
969
+ return true;
970
+ }
971
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
972
+ default:
973
+ return `async function findUserById() { return null; }
974
+ async function updateUserPasswordHash() { return false; }
975
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`
976
+ }
977
+ }
978
+
979
+ /** Microsoft provider ids whose email claim is only trusted for one tenant. */
980
+ const MICROSOFT_PROVIDER_IDS = new Set(['azure-ad', 'microsoft-entra-id'])
981
+
982
+ /** The credential key naming a Microsoft provider's tenant (`*_TENANT_ID`, or Entra's `*_ISSUER`). */
983
+ const microsoftTenantKeyOf = (provider: { id: string; credentials: Record<string, string> }) =>
984
+ Object.keys(provider.credentials || {}).find(
985
+ (key) => key.endsWith('_TENANT_ID') || key.endsWith('_ISSUER')
986
+ )
987
+
988
+ /** provider id → env var of its configured tenant, for each Microsoft provider. */
989
+ const microsoftTenantEnvKeys = (auth: UIDLAuthentication): Record<string, string> => {
990
+ const keys: Record<string, string> = {}
991
+ for (const provider of auth.providers || []) {
992
+ const key = MICROSOFT_PROVIDER_IDS.has(provider.id) ? microsoftTenantKeyOf(provider) : undefined
993
+ if (key) {
994
+ keys[provider.id] = key
995
+ }
996
+ }
997
+ return keys
998
+ }
999
+
618
1000
  // Only the CredentialsProvider is imported at module scope (it always exists).
619
1001
  // OAuth providers are required lazily inside generateProvidersSetup.
620
1002
  const generateProviderImports = (auth: UIDLAuthentication): string => {
@@ -654,11 +1036,11 @@ const generateProvidersSetup = (auth: UIDLAuthentication): string => {
654
1036
  //
655
1037
  // Unknown email and wrong password deliberately share one code: telling them
656
1038
  // apart is a user-enumeration oracle.
657
- async authorize(credentials) {
1039
+ async authorize(credentials, req) {
658
1040
  if (!credentials || !credentials.email || !credentials.password) {
659
1041
  throw new Error('MissingCredentials');
660
1042
  }
661
- const { verifyPassword } = require('./hash-password');
1043
+ const { checkPassword, hashPassword } = require('./hash-password');
662
1044
  const { classifyAuthInfrastructureError } = require('./db-health');
663
1045
  let user;
664
1046
  try {
@@ -668,22 +1050,35 @@ const generateProvidersSetup = (auth: UIDLAuthentication): string => {
668
1050
  console.error('[auth] Could not reach the user store (' + kind + '):', err && err.message ? err.message : err);
669
1051
  throw new Error('ServiceUnavailable');
670
1052
  }
1053
+ let verdict;
671
1054
  try {
672
- if (!user) throw new Error('InvalidCredentials');
673
- if (!verifyPassword(String(credentials.password), user.password)) {
674
- throw new Error('InvalidCredentials');
675
- }
676
- const signedIn = sanitizeUser(user);
677
- signedIn[TOKEN_PASSWORD_FINGERPRINT] = passwordFingerprint(user.password);
678
- return signedIn;
1055
+ // No account, or one without a password, is checked too (against a
1056
+ // stand-in hash): every failure costs what a wrong password costs.
1057
+ verdict = checkPassword(String(credentials.password), user ? user.password : null);
679
1058
  } catch (err) {
680
- if (err && err.message === 'InvalidCredentials') throw err;
681
1059
  // A hashing/serialisation fault is an infrastructure problem, not a
682
1060
  // wrong password — saying "check your details" would send the user
683
1061
  // round in circles.
684
1062
  console.error('[auth] Credential check failed:', err && err.message ? err.message : err);
685
1063
  throw new Error('ServiceUnavailable');
686
1064
  }
1065
+ if (!verdict.ok) {
1066
+ await countSignInFailure(req, credentials.email);
1067
+ throw new Error('InvalidCredentials');
1068
+ }
1069
+ // A hash still made with the old pepper moves onto the project's own.
1070
+ let storedHash = user.password;
1071
+ if (verdict.needsRehash) {
1072
+ try {
1073
+ const rehashed = hashPassword(String(credentials.password));
1074
+ if (await updateUserPasswordHash(user, rehashed, storedHash)) {
1075
+ storedHash = rehashed;
1076
+ }
1077
+ } catch (err) {
1078
+ console.error('[auth] Could not move the password onto the current pepper:', err && err.message ? err.message : err);
1079
+ }
1080
+ }
1081
+ return withSessionStamp(sanitizeUser(user), Object.assign({}, user, { password: storedHash }));
687
1082
  }
688
1083
  }));`)
689
1084
  }
@@ -702,7 +1097,11 @@ const generateProvidersSetup = (auth: UIDLAuthentication): string => {
702
1097
  ` clientId: process.env.${idKey}`,
703
1098
  ` clientSecret: process.env.${secretKey}`,
704
1099
  ]
705
- if (issuerKey) {
1100
+ if (provider.id === 'azure-ad' && issuerKey && issuerKey.endsWith('_TENANT_ID')) {
1101
+ // next-auth's Azure AD provider takes the tenant as tenantId ("common",
1102
+ // every tenant, when absent).
1103
+ cfg.push(` tenantId: process.env.${issuerKey} || undefined`)
1104
+ } else if (issuerKey) {
706
1105
  cfg.push(` issuer: process.env.${issuerKey}`)
707
1106
  }
708
1107
 
@@ -730,17 +1129,35 @@ export const generateAuthOptionsFile = (
730
1129
  const providerImports = generateProviderImports(auth)
731
1130
  const providersSetup = generateProvidersSetup(auth)
732
1131
  const findUserCode = auth.passwordAuthEnabled
733
- ? generateFindUserFunction(auth.dataSourceType, customProps)
1132
+ ? `${generateFindUserFunction(auth.dataSourceType, customProps)}
1133
+
1134
+ ${generateSignupLookupFunction(auth.dataSourceType)}`
734
1135
  : ''
735
1136
  const sanitizeUserCode = generateSanitizeUserFunction(auth.tables, customProps)
736
1137
  const signInRoute = auth.authPages.signIn?.route || '/auth/sign-in'
1138
+ // Password sign-in brings the local account a session can be revoked from;
1139
+ // with an OAuth provider beside it, an OAuth sign-in may become that account.
1140
+ const withPassword = !!auth.passwordAuthEnabled
1141
+ // Every OAuth project checks whether the provider vouches for the email: an
1142
+ // unvouched email never is the visitor's identity, whether or not a local
1143
+ // account could be adopted (R15).
1144
+ const withOAuthBinding = (auth.providers || []).length > 0
1145
+ const passwordSessionCode = withPassword
1146
+ ? `${generatePasswordStoreFunctions(auth.dataSourceType)}
1147
+
1148
+ ${CREDENTIAL_SESSION_HELPERS}
1149
+ `
1150
+ : ''
1151
+ const oauthBindingCode = withOAuthBinding
1152
+ ? `${generateOAuthEmailVerificationHelpers(auth)}\n`
1153
+ : ''
737
1154
 
738
1155
  return `${providerImports}
739
1156
  ${dbSetupCode}
740
1157
  ${sanitizeUserCode}
741
1158
 
742
1159
  ${findUserCode}
743
-
1160
+ ${passwordSessionCode}${oauthBindingCode}
744
1161
  ${providersSetup}
745
1162
 
746
1163
  // How long a JWT may serve profile fields before the next /api/auth/session
@@ -791,7 +1208,29 @@ const authOptions = {
791
1208
  for (let i = 0; i < keys.length; i++) {
792
1209
  token[keys[i]] = user[keys[i]];
793
1210
  }
794
- // Deliberately NOT stamped. An OAuth \`user\` is the PROVIDER's profile
1211
+ ${
1212
+ withOAuthBinding
1213
+ ? ` // An OAuth sign-in becomes the local account with its email only when
1214
+ // the provider vouches for that email; otherwise it stays a session of
1215
+ // its own, without the account's id or role.
1216
+ if (params.account && params.account.type !== 'credentials') {
1217
+ if (!(await oauthEmailIsVerified(params.account, params.profile, token))) {
1218
+ asDistinctOAuthIdentity(token, params.account);
1219
+ }${
1220
+ withPassword
1221
+ ? ` else {
1222
+ // Vouched for: the next refresh adopts the local account with that
1223
+ // email (its id and role). Until then — and for good when there is
1224
+ // none — the id is the provider's, namespaced where it could equal
1225
+ // a local id.
1226
+ namespaceOAuthId(token, params.account);
1227
+ }`
1228
+ : ''
1229
+ }
1230
+ }
1231
+ `
1232
+ : ''
1233
+ } // Deliberately NOT stamped. An OAuth \`user\` is the PROVIDER's profile
795
1234
  // (id/name/email/image) — it carries no \`role\`, which only exists on
796
1235
  // the \`users\` row. Stamping here would make the first session request
797
1236
  // after an OAuth sign-in skip the database and leave the visitor
@@ -800,7 +1239,15 @@ const authOptions = {
800
1239
  // exactly as it does today, and the interval applies from there on.
801
1240
  return token;
802
1241
  }
803
- // Subsequent calls (every /api/auth/session): re-read the user from the
1242
+ ${
1243
+ withOAuthBinding
1244
+ ? ` // A session the provider did not vouch for never takes a local account.
1245
+ if (token && token[OAUTH_UNVERIFIED]) {
1246
+ return token;
1247
+ }
1248
+ `
1249
+ : ''
1250
+ } // Subsequent calls (every /api/auth/session): re-read the user from the
804
1251
  // database so profile edits — name, image, role, etc. — propagate into the
805
1252
  // session. The JWT is otherwise a snapshot captured at login, which is why
806
1253
  // the navbar avatar/name reverted to the old value after a refresh: the
@@ -821,35 +1268,19 @@ const authOptions = {
821
1268
  if (params.trigger !== 'update' && isFresh) {
822
1269
  return token;
823
1270
  }
824
- let passwordChanged = false;
825
- try {
826
- if (token && token.email && typeof findUserByEmail === 'function') {
827
- const fresh = await findUserByEmail(String(token.email));
828
- const safe = fresh && typeof sanitizeUser === 'function' ? sanitizeUser(fresh) : null;
829
- if (safe && typeof safe === 'object') {
830
- const fk = Object.keys(safe);
831
- for (let i = 0; i < fk.length; i++) {
832
- token[fk[i]] = safe[fk[i]];
833
- }
834
- }
835
- if (fresh) {
836
- const currentFingerprint = passwordFingerprint(fresh.password);
837
- if (typeof token[TOKEN_PASSWORD_FINGERPRINT] !== 'string') {
838
- token[TOKEN_PASSWORD_FINGERPRINT] = currentFingerprint;
839
- } else if (token[TOKEN_PASSWORD_FINGERPRINT] !== currentFingerprint) {
840
- passwordChanged = true;
841
- }
842
- }
843
- }
844
- } catch (e) {
1271
+ ${withPassword ? PASSWORD_REFRESH_CODE : PLAIN_REFRESH_CODE} } catch (e) {
845
1272
  // Keep the existing token on any DB hiccup — never sign the user out.
846
1273
  }
847
- if (passwordChanged) {
1274
+ ${
1275
+ withPassword
1276
+ ? ` if (revoked) {
848
1277
  // NextAuth answers a jwt callback that throws by clearing the session
849
- // cookie and returning no session: the visitor is signed out.
850
- throw new Error('The account password changed since this session signed in');
1278
+ // cookie: the visitor is signed out.
1279
+ throw new Error('SessionRevoked');
851
1280
  }
852
- // Stamped even when the read threw, so an unreachable database costs one
1281
+ `
1282
+ : ''
1283
+ } // Stamped even when the read threw, so an unreachable database costs one
853
1284
  // attempt per interval instead of one per request.
854
1285
  if (token) {
855
1286
  token[TOKEN_REFRESH_STAMP] = now;
@@ -863,7 +1294,9 @@ const authOptions = {
863
1294
  const skip = { iat: 1, exp: 1, jti: 1, sub: 1 };
864
1295
  skip[TOKEN_REFRESH_STAMP] = 1;
865
1296
  skip[TOKEN_PASSWORD_FINGERPRINT] = 1;
866
- const keys = Object.keys(token);
1297
+ ${withPassword ? ` skip['${SESSION_STAMP_KEY}'] = 1;\n` : ''}${
1298
+ withOAuthBinding ? ' skip[OAUTH_UNVERIFIED] = 1;\n' : ''
1299
+ } const keys = Object.keys(token);
867
1300
  for (let i = 0; i < keys.length; i++) {
868
1301
  if (!skip[keys[i]]) {
869
1302
  session.user[keys[i]] = token[keys[i]];
@@ -879,14 +1312,407 @@ const authOptions = {
879
1312
  secret: process.env.NEXTAUTH_SECRET,
880
1313
  };
881
1314
 
1315
+ // On https the session token and the callback-url cookie are "__Host-" cookies
1316
+ // (Path=/, Secure, HttpOnly, SameSite=Lax, no Domain): only this site can set
1317
+ // them. Published sites share a parent domain that is not a public suffix, so a
1318
+ // sibling site could otherwise plant a session cookie this site reads (cookie
1319
+ // tossing: the visitor silently signed in to someone else's account). Every
1320
+ // reader in the app reads this one name (session-cookie-resolver). NextAuth
1321
+ // reads the option on every request, after the auth route has set
1322
+ // NEXTAUTH_URL to the request's origin; on http (a local server) its defaults stay.
1323
+ var SECURE_SESSION_COOKIES = {
1324
+ sessionToken: {
1325
+ name: '${SessionCookieResolver.SECURE_SESSION_COOKIE_NAME}',
1326
+ options: { httpOnly: true, sameSite: 'lax', path: '/', secure: true },
1327
+ },
1328
+ callbackUrl: {
1329
+ name: '${SessionCookieResolver.SECURE_CALLBACK_URL_COOKIE_NAME}',
1330
+ options: { httpOnly: true, sameSite: 'lax', path: '/', secure: true },
1331
+ },
1332
+ };
1333
+ Object.defineProperty(authOptions, 'cookies', {
1334
+ enumerable: true,
1335
+ get: function () {
1336
+ return String(process.env.NEXTAUTH_URL || '').indexOf('https://') === 0 ? SECURE_SESSION_COOKIES : undefined;
1337
+ },
1338
+ });
1339
+
882
1340
  module.exports = authOptions;
883
1341
  module.exports.sanitizeUser = sanitizeUser;
884
1342
  ${
885
1343
  auth.passwordAuthEnabled
886
- ? `module.exports.findUserByEmail = findUserByEmail;\nmodule.exports.createUser = createUser;\nmodule.exports.userExistsByEmail = userExistsByEmail;\n`
1344
+ ? `module.exports.findUserByEmail = findUserByEmail;\nmodule.exports.findSignupUserByEmail = findSignupUserByEmail;\nmodule.exports.createUser = createUser;\nmodule.exports.userExistsByEmail = userExistsByEmail;\n`
887
1345
  : ''
1346
+ }${
1347
+ withPassword
1348
+ ? `module.exports.findUserById = findUserById;
1349
+ module.exports.checkSignInAllowed = checkSignInAllowed;
1350
+ module.exports.countSignInFailure = countSignInFailure;
1351
+ module.exports.SIGN_IN_VISITOR_HEADER = SIGN_IN_VISITOR_HEADER;
1352
+ module.exports.storePasswordReset = storePasswordReset;
1353
+ module.exports.consumePasswordReset = consumePasswordReset;
1354
+ module.exports.passwordResetIsLive = passwordResetIsLive;
1355
+ module.exports.PASSWORD_RESET_SUPPORTED = PASSWORD_RESET_SUPPORTED;
1356
+ `
1357
+ : ''
1358
+ }
1359
+ `
888
1360
  }
1361
+
1362
+ // The jwt callback's refresh without password sign-in (no local lookup exists).
1363
+ const PLAIN_REFRESH_CODE = ` try {
1364
+ if (token && token.email && typeof findUserByEmail === 'function') {
1365
+ const fresh = await findUserByEmail(String(token.email));
1366
+ const safe = fresh && typeof sanitizeUser === 'function' ? sanitizeUser(fresh) : null;
1367
+ if (safe && typeof safe === 'object') {
1368
+ const fk = Object.keys(safe);
1369
+ for (let i = 0; i < fk.length; i++) {
1370
+ token[fk[i]] = safe[fk[i]];
1371
+ }
1372
+ }
1373
+ }
1374
+ `
1375
+
1376
+ // With password sign-in: a stamped session follows its account BY ID (the key
1377
+ // every consumer acts on), so a deleted account or a changed password ends it
1378
+ // even after an email change; an unstamped one (an OAuth sign-in, a token from
1379
+ // before stamps) adopts the local account by its email.
1380
+ const PASSWORD_REFRESH_CODE = ` let revoked = false;
1381
+ try {
1382
+ const stamped = !!token && typeof token['${SESSION_STAMP_KEY}'] === 'string';
1383
+ const accountId = token && (token.id != null ? token.id : token.sub);
1384
+ let fresh = null;
1385
+ let looked = false;
1386
+ if (stamped && typeof findUserById === 'function') {
1387
+ fresh = accountId != null ? await findUserById(String(accountId)) : null;
1388
+ looked = true;
1389
+ } else if (token && token.email && typeof findUserByEmail === 'function') {
1390
+ fresh = await findUserByEmail(String(token.email));
1391
+ looked = true;
1392
+ }
1393
+ if (looked) {
1394
+ // The account's password (or session_version) changed since this
1395
+ // token was stamped, or the account is gone: the session is over.
1396
+ // Otherwise the token takes the stamp of the account as it is now.
1397
+ revoked = sessionStampCheck(token, fresh) === 'revoked';
1398
+ // The same end, for a token issued before stamps: a short fingerprint
1399
+ // of the stored hash, never the hash. A change (a reset included)
1400
+ // signs that session out at its next refresh.
1401
+ if (!revoked && fresh) {
1402
+ const currentFingerprint = passwordFingerprint(fresh.password);
1403
+ if (typeof token[TOKEN_PASSWORD_FINGERPRINT] !== 'string') {
1404
+ token[TOKEN_PASSWORD_FINGERPRINT] = currentFingerprint;
1405
+ } else if (token[TOKEN_PASSWORD_FINGERPRINT] !== currentFingerprint) {
1406
+ revoked = true;
1407
+ }
1408
+ }
1409
+ const safe = !revoked && fresh && typeof sanitizeUser === 'function' ? sanitizeUser(fresh) : null;
1410
+ if (safe && typeof safe === 'object') {
1411
+ const fk = Object.keys(safe);
1412
+ for (let i = 0; i < fk.length; i++) {
1413
+ token[fk[i]] = safe[fk[i]];
1414
+ }
1415
+ }
1416
+ }
889
1417
  `
1418
+
1419
+ /**
1420
+ * auth-options helpers for password sign-in: the sign-in throttle (failures
1421
+ * per visitor and email, counted after a wrong password, checked by the
1422
+ * NextAuth route before the next attempt) and the session stamp
1423
+ * (`utils/auth/session-revocation.js`).
1424
+ */
1425
+ const CREDENTIAL_SESSION_HELPERS = `// Sign-in throttle. The NextAuth route refuses a visitor's next sign-in for an
1426
+ // email once SIGN_IN_FAILURE_LIMIT failures for it are in the window, once the
1427
+ // visitor has SIGN_IN_VISITOR_FAILURE_LIMIT failures across all emails, or once
1428
+ // they tried it SIGN_IN_ATTEMPT_LIMIT times (so a burst of parallel guesses
1429
+ // cannot all start before the first failure is counted). The route writes who
1430
+ // the visitor is on the request (SIGN_IN_VISITOR_HEADER, replacing whatever the
1431
+ // request carried), because NextAuth hands authorize() the headers only.
1432
+ var SIGN_IN_VISITOR_HEADER = 'x-teleport-signin-visitor';
1433
+ var SIGN_IN_FAILURE_SCOPE = 'auth-signin-failures';
1434
+ var SIGN_IN_FAILURE_LIMIT = ${SIGN_IN_FAILURE_LIMIT};
1435
+ var SIGN_IN_ATTEMPT_SCOPE = 'auth-signin-attempts';
1436
+ var SIGN_IN_ATTEMPT_LIMIT = ${SIGN_IN_ATTEMPT_LIMIT};
1437
+ var SIGN_IN_WINDOW_SECONDS = ${SIGN_IN_WINDOW_SECONDS};
1438
+ // Failures one visitor may make across every email (credential stuffing tries
1439
+ // many addresses once each), counted the same way: after a failure only.
1440
+ var SIGN_IN_VISITOR_FAILURE_SCOPE = 'auth-signin-visitor-failures';
1441
+ var SIGN_IN_VISITOR_FAILURE_LIMIT = ${SIGN_IN_VISITOR_FAILURE_LIMIT};
1442
+
1443
+ function signInVisitorRequest(req) {
1444
+ var headers = (req && req.headers) || {};
1445
+ var visitor = headers[SIGN_IN_VISITOR_HEADER];
1446
+ return { headers: {}, socket: { remoteAddress: typeof visitor === 'string' ? visitor : '' } };
1447
+ }
1448
+
1449
+ function signInEmailKey(email) {
1450
+ return String(email == null ? '' : email).trim().toLowerCase();
1451
+ }
1452
+
1453
+ // { allowed, retryAfter } for the sign-in the request is about to make.
1454
+ async function checkSignInAllowed(req) {
1455
+ var security = require('../security-runtime');
1456
+ var visitor = signInVisitorRequest(req);
1457
+ var email = signInEmailKey(req && req.body ? req.body.email : '');
1458
+ var failures = await security.peekRateLimitRequest(visitor, {
1459
+ scope: SIGN_IN_FAILURE_SCOPE,
1460
+ limit: SIGN_IN_FAILURE_LIMIT,
1461
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1462
+ keyParts: [email],
1463
+ });
1464
+ if (!failures.allowed) {
1465
+ return failures;
1466
+ }
1467
+ var visitorFailures = await security.peekRateLimitRequest(visitor, {
1468
+ scope: SIGN_IN_VISITOR_FAILURE_SCOPE,
1469
+ limit: SIGN_IN_VISITOR_FAILURE_LIMIT,
1470
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1471
+ });
1472
+ if (!visitorFailures.allowed) {
1473
+ return visitorFailures;
1474
+ }
1475
+ var attemptAllowed = await security.rateLimitRequest(visitor, null, {
1476
+ scope: SIGN_IN_ATTEMPT_SCOPE,
1477
+ limit: SIGN_IN_ATTEMPT_LIMIT,
1478
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1479
+ keyParts: [email],
1480
+ });
1481
+ if (!attemptAllowed) {
1482
+ var nowSec = Math.floor(Date.now() / 1000);
1483
+ return { allowed: false, retryAfter: Math.max(1, SIGN_IN_WINDOW_SECONDS - (nowSec % SIGN_IN_WINDOW_SECONDS)) };
1484
+ }
1485
+ return { allowed: true, retryAfter: 0 };
1486
+ }
1487
+
1488
+ async function countSignInFailure(req, email) {
1489
+ try {
1490
+ var security = require('../security-runtime');
1491
+ var visitor = signInVisitorRequest(req);
1492
+ await security.rateLimitRequest(visitor, null, {
1493
+ scope: SIGN_IN_FAILURE_SCOPE,
1494
+ limit: SIGN_IN_FAILURE_LIMIT,
1495
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1496
+ keyParts: [signInEmailKey(email)],
1497
+ });
1498
+ await security.rateLimitRequest(visitor, null, {
1499
+ scope: SIGN_IN_VISITOR_FAILURE_SCOPE,
1500
+ limit: SIGN_IN_VISITOR_FAILURE_LIMIT,
1501
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1502
+ });
1503
+ } catch (err) {
1504
+ console.error('[auth] Could not count a failed sign-in:', err && err.message ? err.message : err);
1505
+ }
1506
+ }
1507
+
1508
+ // The shared session-stamp check (utils/auth/session-revocation.js).
1509
+ function sessionRevocationModule() {
1510
+ try {
1511
+ var revocation = require('./${SESSION_REVOCATION_FILE_NAME}');
1512
+ return revocation && typeof revocation.stampVerdict === 'function' ? revocation : null;
1513
+ } catch (e) {
1514
+ return null;
1515
+ }
1516
+ }
1517
+
1518
+ // A signed-in user's session carries the stamp of the account it was issued for.
1519
+ function withSessionStamp(safeUser, row) {
1520
+ var revocation = sessionRevocationModule();
1521
+ var stamp = revocation ? revocation.credentialStamp(row) : null;
1522
+ if (safeUser && stamp) {
1523
+ safeUser[revocation.SESSION_STAMP_KEY] = stamp;
1524
+ }
1525
+ if (safeUser) {
1526
+ safeUser[TOKEN_PASSWORD_FINGERPRINT] = passwordFingerprint(row ? row.password : null);
1527
+ }
1528
+ return safeUser;
1529
+ }
1530
+
1531
+ // 'revoked' when the stored account no longer matches the token's stamp;
1532
+ // otherwise the token takes the account's current stamp.
1533
+ function sessionStampCheck(token, row) {
1534
+ var revocation = sessionRevocationModule();
1535
+ if (!revocation) {
1536
+ return 'unchecked';
1537
+ }
1538
+ var verdict = revocation.stampVerdict(token, row || null);
1539
+ if (verdict !== 'revoked' && row) {
1540
+ var stamp = revocation.credentialStamp(row);
1541
+ if (stamp) {
1542
+ token[revocation.SESSION_STAMP_KEY] = stamp;
1543
+ }
1544
+ }
1545
+ return verdict;
1546
+ }`
1547
+
1548
+ /**
1549
+ * The user stores whose own account ids can never equal an OAuth provider's id:
1550
+ * MongoDB (`_id`, a 24-hex ObjectId), Airtable (`rec…` record ids) and
1551
+ * Firestore (20-character auto ids). Read from `auth.dataSourceType`, the same
1552
+ * value that picks the auth driver.
1553
+ */
1554
+ const STORES_WITH_DISJOINT_IDS = new Set(['mongodb', 'airtable', 'firestore'])
1555
+
1556
+ /**
1557
+ * Whether an OAuth session's id must be namespaced (`oauth:<provider>:<id>`)
1558
+ * because the provider's raw account id could equal another account's id:
1559
+ * - the project has more than one OAuth provider: two providers' id spaces
1560
+ * can collide, whatever the store;
1561
+ * - otherwise a store whose ids are its own (STORES_WITH_DISJOINT_IDS) keeps
1562
+ * the raw id;
1563
+ * - any other store (SQL or not) is decided by the declared `users` id type:
1564
+ * a UUID keeps the raw id; any other type (a provider's integer id can equal
1565
+ * a local integer id on every owner rule), or none declared, namespaces.
1566
+ * The editor declares the type the database reported for its `users` table
1567
+ * (teleport-gui `liveUsersIdType`), and no type when none was recorded.
1568
+ * Where the raw id stays it never equals a local id, and every record a
1569
+ * published site wrote under it (entitlements, cart, favourites, chats,
1570
+ * downloads) stays the visitor's. Wherever a collision cannot be ruled out the
1571
+ * id is namespaced: a collision hands one person another's records, which no
1572
+ * later fix undoes; lost continuity leaves the records in place under the old
1573
+ * id.
1574
+ */
1575
+ export const oauthIdsNeedNamespace = (auth: UIDLAuthentication): boolean => {
1576
+ if ((auth.providers || []).length > 1) {
1577
+ return true
1578
+ }
1579
+ if (auth.dataSourceType && STORES_WITH_DISJOINT_IDS.has(auth.dataSourceType)) {
1580
+ return false
1581
+ }
1582
+ const idColumn = ((auth.tables && auth.tables.users) || []).find(
1583
+ (column) => !!column && String(column.name || '').toLowerCase() === 'id'
1584
+ )
1585
+ return !(idColumn && /^\s*uuid\b/i.test(String(idColumn.type || '')))
1586
+ }
1587
+
1588
+ /**
1589
+ * auth-options helpers for a project with password sign-in AND an OAuth
1590
+ * provider: whether the provider vouches for the email an OAuth sign-in
1591
+ * presents. Only then may that sign-in become the local account with the same
1592
+ * email (its id and role); otherwise it is a session of its own.
1593
+ */
1594
+ const generateOAuthEmailVerificationHelpers = (auth: UIDLAuthentication): string => {
1595
+ const tenants = microsoftTenantEnvKeys(auth)
1596
+ const tenantEntries = Object.keys(tenants)
1597
+ .map((id) => `${JSON.stringify(id)}: process.env.${tenants[id]}`)
1598
+ .join(', ')
1599
+ return `// Providers that only ever hand out an email its owner proved. Any other
1600
+ // provider must say so in the profile (email_verified); an explicit "not
1601
+ // verified" outweighs the list.
1602
+ var VERIFIED_EMAIL_PROVIDERS = { google: true, apple: true };
1603
+ var OAUTH_UNVERIFIED = '__oauthUnverified';
1604
+ // A provider's raw account id could equal another account's id here (see
1605
+ // oauthIdsNeedNamespace in the code generator): sessions without a local
1606
+ // account take the provider's id as "oauth:<provider>:<id>".
1607
+ var OAUTH_IDS_NAMESPACED = ${JSON.stringify(oauthIdsNeedNamespace(auth))};
1608
+
1609
+ // Microsoft (Azure AD / Entra ID) tokens carry no email_verified, and on the
1610
+ // multi-tenant endpoint the email claim is whatever the signing-in tenant's
1611
+ // administrator set (the "nOAuth" class). An email counts only when the token
1612
+ // says its domain is verified (xms_edov), or when the provider is configured
1613
+ // for one specific tenant (an id or a domain, never common / organizations /
1614
+ // consumers): the site owner's own directory.
1615
+ var MICROSOFT_PROVIDERS = { 'azure-ad': true, 'microsoft-entra-id': true };
1616
+ var MICROSOFT_TENANTS = { ${tenantEntries} };
1617
+ var MICROSOFT_TENANT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
1618
+
1619
+ // The one tenant a Microsoft provider is configured for, or '' (multi-tenant).
1620
+ function microsoftTenantOf(value) {
1621
+ var raw = String(value == null ? '' : value).trim().toLowerCase();
1622
+ if (!raw || raw.indexOf('teleporthq.secrets.') === 0) {
1623
+ return '';
1624
+ }
1625
+ var fromIssuer = /^https:\\/\\/login\\.microsoftonline\\.com\\/([^\\/?#]+)/.exec(raw);
1626
+ var tenant = fromIssuer ? fromIssuer[1] : raw;
1627
+ if (tenant === 'common' || tenant === 'organizations' || tenant === 'consumers') {
1628
+ return '';
1629
+ }
1630
+ return MICROSOFT_TENANT_ID.test(tenant) || /^[a-z0-9-]+(\\.[a-z0-9-]+)+$/.test(tenant) ? tenant : '';
1631
+ }
1632
+
1633
+ function microsoftEmailIsVerified(provider, claims) {
1634
+ if (claims.xms_edov === true || claims.xms_edov === 'true' || claims.xms_edov === 1) {
1635
+ return true;
1636
+ }
1637
+ var tenant = microsoftTenantOf(MICROSOFT_TENANTS[provider]);
1638
+ if (!tenant) {
1639
+ return false;
1640
+ }
1641
+ // A tenant given by id must be the one the token was issued in.
1642
+ if (MICROSOFT_TENANT_ID.test(tenant) && claims.tid != null && String(claims.tid).toLowerCase() !== tenant) {
1643
+ return false;
1644
+ }
1645
+ return true;
1646
+ }
1647
+
1648
+ // GitHub's profile email is not always a verified one: ask GitHub (the
1649
+ // provider requests the user:email scope) whether this address is.
1650
+ async function githubEmailIsVerified(account, email) {
1651
+ if (!account || !account.access_token || !email) {
1652
+ return false;
1653
+ }
1654
+ try {
1655
+ var res = await fetch('https://api.github.com/user/emails', {
1656
+ headers: {
1657
+ Authorization: 'Bearer ' + account.access_token,
1658
+ Accept: 'application/vnd.github+json',
1659
+ 'User-Agent': 'teleporthq-auth',
1660
+ },
1661
+ });
1662
+ if (!res.ok) {
1663
+ return false;
1664
+ }
1665
+ var list = await res.json();
1666
+ var wanted = String(email).toLowerCase();
1667
+ return Array.isArray(list) && list.some(function (entry) {
1668
+ return !!entry && entry.verified === true && String(entry.email || '').toLowerCase() === wanted;
1669
+ });
1670
+ } catch (e) {
1671
+ return false;
1672
+ }
1673
+ }
1674
+
1675
+ async function oauthEmailIsVerified(account, profile, token) {
1676
+ var claims = profile || {};
1677
+ if (claims.email_verified === false || claims.email_verified === 'false') {
1678
+ return false;
1679
+ }
1680
+ if (claims.email_verified === true || claims.email_verified === 'true') {
1681
+ return true;
1682
+ }
1683
+ var provider = String((account && account.provider) || '');
1684
+ if (provider === 'github') {
1685
+ return githubEmailIsVerified(account, token && token.email);
1686
+ }
1687
+ if (MICROSOFT_PROVIDERS[provider] === true) {
1688
+ return microsoftEmailIsVerified(provider, claims);
1689
+ }
1690
+ return VERIFIED_EMAIL_PROVIDERS[provider] === true;
1691
+ }
1692
+
1693
+ // The provider's own account id as "oauth:<provider>:<id>": a namespace no
1694
+ // local account id can share (a provider's integer ids would otherwise match
1695
+ // local integer ids on owner rules). Where no id can collide, the raw id stays.
1696
+ function namespaceOAuthId(token, account) {
1697
+ if (!OAUTH_IDS_NAMESPACED) {
1698
+ return;
1699
+ }
1700
+ var accountId = String((account && account.providerAccountId) || token.sub || token.id || '');
1701
+ var id = 'oauth:' + String((account && account.provider) || 'provider') + ':' + accountId;
1702
+ token.id = id;
1703
+ token.sub = id;
1704
+ }
1705
+
1706
+ // Not vouched for: the visitor keeps a session under an id no local account can
1707
+ // have (namespaced where one could), with no email to be matched by and no role.
1708
+ function asDistinctOAuthIdentity(token, account) {
1709
+ namespaceOAuthId(token, account);
1710
+ delete token.email;
1711
+ delete token.role;
1712
+ delete token.roleName;
1713
+ delete token.roles;
1714
+ token[OAUTH_UNVERIFIED] = true;
1715
+ }`
890
1716
  }
891
1717
 
892
1718
  /**
@@ -909,6 +1735,7 @@ const AUTH_ERROR_MESSAGES = {
909
1735
  InvalidCredentials: 'That email and password do not match an account.',
910
1736
  ServiceUnavailable:
911
1737
  'We could not reach the account service. Please try again in a moment — if it keeps happening, the site owner needs to check its database configuration.',
1738
+ TooManyAttempts: 'Too many sign-in attempts. Please wait a few minutes and try again.',
912
1739
 
913
1740
  // NextAuth's own.
914
1741
  CredentialsSignin: 'That email and password do not match an account.',
@@ -1008,37 +1835,163 @@ module.exports = {
1008
1835
  `
1009
1836
  }
1010
1837
 
1838
+ /** The password a site accepts when one is set (sign-up, reset, a change). */
1839
+ export const MIN_PASSWORD_LENGTH = 8
1840
+ export const MAX_PASSWORD_BYTES = 128
1841
+
1011
1842
  export const generateHashPasswordFile = (): string => {
1012
1843
  return `const bcrypt = require('bcryptjs');
1013
1844
  const crypto = require('crypto');
1014
1845
 
1015
- const PEPPER = process.env.AUTH_PEPPER || '';
1016
1846
  const COST_FACTOR = 12;
1847
+ const MIN_PASSWORD_LENGTH = ${MIN_PASSWORD_LENGTH};
1848
+ const MAX_PASSWORD_BYTES = ${MAX_PASSWORD_BYTES};
1849
+
1850
+ // Two peppers. AUTH_PEPPER_SECRET is the project's own random secret, which the
1851
+ // deploy step provisions; every new hash uses it. AUTH_PEPPER (the project id,
1852
+ // no secret) is the one every hash was made with before it existed: such a hash
1853
+ // still verifies, and the sign-in replaces it. Without the secret, hashing and
1854
+ // verifying stay on the old pepper — never on none.
1855
+ function pepperSecret() {
1856
+ var value = process.env.AUTH_PEPPER_SECRET;
1857
+ return typeof value === 'string' && value && value.indexOf('teleporthq.secrets.') !== 0 ? value : '';
1858
+ }
1017
1859
 
1018
- function prepare(password) {
1860
+ function legacyPepper() {
1861
+ return process.env.AUTH_PEPPER || '';
1862
+ }
1863
+
1864
+ // SHA-256 first, so bcrypt (which reads at most 72 bytes) sees all of it.
1865
+ function prepare(password, pepper) {
1019
1866
  const str = String(password);
1020
1867
  if (str.length > 1000) {
1021
1868
  throw new Error('Password exceeds maximum length');
1022
1869
  }
1023
- const sha = crypto.createHash('sha256').update(str + PEPPER).digest('base64');
1024
- return sha;
1870
+ return crypto.createHash('sha256').update(str + pepper).digest('base64');
1025
1871
  }
1026
1872
 
1027
1873
  function hashPassword(password) {
1028
- return bcrypt.hashSync(prepare(password), COST_FACTOR);
1874
+ return bcrypt.hashSync(prepare(password, pepperSecret() || legacyPepper()), COST_FACTOR);
1875
+ }
1876
+
1877
+ // A hash no password matches, made once per process with the project pepper
1878
+ // at the same cost. An address without an account, or a row without a
1879
+ // password (a subscriber, a guest), is checked against it, so every failed
1880
+ // sign-in does the bcrypt work a wrong password does: the time never tells
1881
+ // them apart.
1882
+ var __standInHash = null;
1883
+ function standInHash() {
1884
+ if (!__standInHash) {
1885
+ __standInHash = bcrypt.hashSync(prepare(crypto.randomBytes(32).toString('hex'), pepperSecret() || legacyPepper()), COST_FACTOR);
1886
+ }
1887
+ return __standInHash;
1888
+ }
1889
+
1890
+ // { ok, needsRehash }: ok when the password matches; needsRehash when it
1891
+ // matched through the old pepper while the project has its own.
1892
+ function checkPassword(password, hash) {
1893
+ var known = typeof hash === 'string' && hash !== '';
1894
+ var against = known ? hash : standInHash();
1895
+ var secret = pepperSecret();
1896
+ if (secret && bcrypt.compareSync(prepare(password, secret), against) && known) {
1897
+ return { ok: true, needsRehash: false };
1898
+ }
1899
+ // Run on every miss, whatever the hash was.
1900
+ if (bcrypt.compareSync(prepare(password, legacyPepper()), against) && known) {
1901
+ return { ok: true, needsRehash: !!secret };
1902
+ }
1903
+ return { ok: false, needsRehash: false };
1029
1904
  }
1030
1905
 
1031
1906
  function verifyPassword(password, hash) {
1032
- return bcrypt.compareSync(prepare(password), hash);
1907
+ return checkPassword(password, hash).ok;
1908
+ }
1909
+
1910
+ // Why a password may not be set, or '' when it may.
1911
+ function passwordPolicyError(password) {
1912
+ if (typeof password !== 'string' || password.length < MIN_PASSWORD_LENGTH) {
1913
+ return 'Password must be at least ' + MIN_PASSWORD_LENGTH + ' characters';
1914
+ }
1915
+ if (Buffer.byteLength(password, 'utf8') > MAX_PASSWORD_BYTES) {
1916
+ return 'Password is too long (at most ' + MAX_PASSWORD_BYTES + ' bytes)';
1917
+ }
1918
+ return '';
1033
1919
  }
1034
1920
 
1035
1921
  module.exports = hashPassword;
1036
1922
  module.exports.hashPassword = hashPassword;
1037
1923
  module.exports.verifyPassword = verifyPassword;
1924
+ module.exports.checkPassword = checkPassword;
1925
+ module.exports.passwordPolicyError = passwordPolicyError;
1038
1926
  `
1039
1927
  }
1040
1928
 
1041
- export const generateNextAuthRouteFile = (): string => {
1929
+ export interface NextAuthRouteOptions {
1930
+ /** Credentials sign-in is on: the route throttles it (see checkSignInAllowed). */
1931
+ passwordAuthEnabled?: boolean
1932
+ }
1933
+
1934
+ // Answered to a credentials sign-in the throttle refuses, in the shape
1935
+ // next-auth/react's signIn() reads (it parses \`url\` for the error code, which
1936
+ // describeAuthError turns into copy).
1937
+ const SIGN_IN_THROTTLE_CODE = `var __security = require('${securityRuntimeSpecifier('../../..')}');
1938
+
1939
+ function isCredentialsSignIn(req) {
1940
+ var parts = req && req.query ? req.query.nextauth : null;
1941
+ return (
1942
+ req && req.method === 'POST' && Array.isArray(parts) && parts[0] === 'callback' && parts[1] === 'credentials'
1943
+ );
1944
+ }
1945
+
1946
+ function refuseSignIn(res, status, code, message, retryAfter) {
1947
+ var origin = process.env.NEXTAUTH_URL || 'http://localhost:3000';
1948
+ var url;
1949
+ try {
1950
+ url = new URL('/api/auth/error?error=' + code, origin).toString();
1951
+ } catch (e) {
1952
+ url = 'http://localhost:3000/api/auth/error?error=' + code;
1953
+ }
1954
+ if (retryAfter) {
1955
+ res.setHeader('Retry-After', String(retryAfter));
1956
+ }
1957
+ res.status(status).json({ url: url, error: message });
1958
+ }
1959
+
1960
+ // Too many failed (or attempted) sign-ins for this email from this visitor:
1961
+ // refused before the password is even looked at.
1962
+ async function throttleCredentialsSignIn(req, res) {
1963
+ if (req && req.headers) {
1964
+ delete req.headers[authOptions.SIGN_IN_VISITOR_HEADER];
1965
+ }
1966
+ if (!isCredentialsSignIn(req)) {
1967
+ return false;
1968
+ }
1969
+ req.headers[authOptions.SIGN_IN_VISITOR_HEADER] = __security.clientIp(req);
1970
+ var verdict;
1971
+ try {
1972
+ verdict = await authOptions.checkSignInAllowed(req);
1973
+ } catch (err) {
1974
+ console.error('[auth] The sign-in throttle failed:', err && err.message ? err.message : err);
1975
+ refuseSignIn(res, 503, 'ServiceUnavailable', 'Sign-in is unavailable right now. Please try again in a moment.', 0);
1976
+ return true;
1977
+ }
1978
+ if (verdict && verdict.allowed) {
1979
+ return false;
1980
+ }
1981
+ refuseSignIn(
1982
+ res,
1983
+ 429,
1984
+ 'TooManyAttempts',
1985
+ 'Too many sign-in attempts. Try again later.',
1986
+ verdict && verdict.retryAfter ? verdict.retryAfter : ${SIGN_IN_WINDOW_SECONDS}
1987
+ );
1988
+ return true;
1989
+ }
1990
+
1991
+ `
1992
+
1993
+ export const generateNextAuthRouteFile = (options: NextAuthRouteOptions = {}): string => {
1994
+ const throttled = options.passwordAuthEnabled === true
1042
1995
  return `let NextAuth = require('next-auth');
1043
1996
  if (NextAuth.default) NextAuth = NextAuth.default;
1044
1997
  const authOptions = require('../../../utils/auth/auth-options');
@@ -1133,13 +2086,22 @@ function resolveRequestOrigin(req) {
1133
2086
  return proto + '://' + host;
1134
2087
  }
1135
2088
 
1136
- module.exports = function nextAuthRoute(req, res) {
2089
+ ${throttled ? SIGN_IN_THROTTLE_CODE : ''}module.exports = ${
2090
+ throttled ? 'async ' : ''
2091
+ }function nextAuthRoute(req, res) {
1137
2092
  try {
1138
2093
  process.env.NEXTAUTH_URL = resolveRequestOrigin(req);
1139
2094
  } catch (e) {
1140
2095
  /* fall back to whatever NEXTAUTH_URL holds */
1141
2096
  }
1142
- return authHandler(req, res);
2097
+ ${
2098
+ throttled
2099
+ ? ` if (await throttleCredentialsSignIn(req, res)) {
2100
+ return;
2101
+ }
2102
+ `
2103
+ : ''
2104
+ } return authHandler(req, res);
1143
2105
  };
1144
2106
  `
1145
2107
  }
@@ -1161,31 +2123,333 @@ export interface WelcomeEmailOptions {
1161
2123
  siteName?: string
1162
2124
  }
1163
2125
 
2126
+ /** The business events an account route records (spec §5.1). */
2127
+ export interface AccountEventOptions {
2128
+ /** The project has the in-app event bus (`hasAutomationsBus`). */
2129
+ withAutomations?: boolean
2130
+ }
2131
+
2132
+ /**
2133
+ * `recordAccountEvent(type, user, source, req)`, for the account routes of a
2134
+ * project with automations: records `user-signed-up` / `user-deleted` on the
2135
+ * in-app event bus, which writes the `teleport_events` row and wakes the
2136
+ * automations off the request path, on the app's own origin as `req` reached
2137
+ * it. Only the profile fields go into the event, never a credential. It never
2138
+ * throws, so the event cannot fail the request it records. `relativePrefix`
2139
+ * leads from the route to the project root.
2140
+ */
2141
+ export const generateAccountEventRecorder = (options: {
2142
+ relativePrefix: string
2143
+ logTag: string
2144
+ }): string => `
2145
+ // The project has automations: the account event wakes them. Best effort,
2146
+ // like the emails: recording it can never fail the request.
2147
+ function accountEventTime(value) {
2148
+ var date = value ? new Date(value) : new Date();
2149
+ return isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString();
2150
+ }
2151
+
2152
+ async function recordAccountEvent(type, user, source, req) {
2153
+ try {
2154
+ var userId = user ? user.id || user._id : null;
2155
+ if (!userId) { return; }
2156
+ var id = String(userId);
2157
+ var email = user.email ? String(user.email) : '';
2158
+ var bus = require('${options.relativePrefix}/${AUTOMATIONS_PATH.join('/')}/event-bus');
2159
+ await bus.emitBusinessEvent({
2160
+ type: type,
2161
+ entityType: 'user',
2162
+ entityId: id,
2163
+ payload: {
2164
+ user: {
2165
+ id: id,
2166
+ email: email || null,
2167
+ name: user.name || null,
2168
+ role: user.role || null,
2169
+ source: source || user.source || null,
2170
+ createdAt: accountEventTime(user.created_at || user.createdAt),
2171
+ },
2172
+ },
2173
+ actor: email,
2174
+ actorType: 'customer',
2175
+ dedupeKey: type + ':' + id,
2176
+ }, req);
2177
+ } catch (eventErr) {
2178
+ var reason = eventErr && eventErr.message ? eventErr.message : eventErr;
2179
+ console.error('${options.logTag} could not record the ' + type + ' event:', reason);
2180
+ }
2181
+ }
2182
+ `
2183
+
2184
+ /**
2185
+ * A user column that grants something — a role, an admin or staff flag, a
2186
+ * verified email, credit, a plan or an entitlement — in any spelling
2187
+ * (`is_admin`, `isAdmin`, `Email-Verified`). Only the server sets these; a
2188
+ * sign-up never takes them from the visitor. The one shared rule
2189
+ * (`AccountFields.isPrivilegedAccountField`).
2190
+ */
2191
+ export const isPrivilegedUserField = (key: string): boolean =>
2192
+ AccountFields.isPrivilegedAccountField(key)
2193
+
2194
+ /** Config keys of an `account-signup` node that are not user fields. */
2195
+ const SIGNUP_NODE_NON_FIELD_KEYS = new Set<string>([
2196
+ 'email',
2197
+ 'password',
2198
+ 'name',
2199
+ 'image',
2200
+ 'role',
2201
+ ...WELCOME_EMAIL_CONFIG_KEYS,
2202
+ ])
2203
+
2204
+ /**
2205
+ * The fields a sign-up may write besides email, password and name: the avatar
2206
+ * (`image`) and each declared custom account property that a sign-up form of
2207
+ * the project collects (a key of an `account-signup` node), never a
2208
+ * privileged one.
2209
+ */
2210
+ export const resolveSignupFields = (
2211
+ auth: UIDLAuthentication,
2212
+ signupNodeConfigs: Array<Record<string, unknown>>
2213
+ ): string[] => {
2214
+ const declared = new Set((auth.customUserProperties || []).map((prop) => prop.key))
2215
+ const collected = new Set<string>()
2216
+ for (const config of signupNodeConfigs) {
2217
+ for (const key of Object.keys(config || {})) {
2218
+ if (
2219
+ !SIGNUP_NODE_NON_FIELD_KEYS.has(key) &&
2220
+ declared.has(key) &&
2221
+ !isPrivilegedUserField(key)
2222
+ ) {
2223
+ collected.add(key)
2224
+ }
2225
+ }
2226
+ }
2227
+ return ['image', ...Array.from(collected).sort()]
2228
+ }
2229
+
2230
+ export interface SignupRouteOptions {
2231
+ /** `resolveSignupFields` — what a sign-up may write besides email, password, name. */
2232
+ fields?: string[]
2233
+ /**
2234
+ * The page the set-password link opens and where it carries its token: the
2235
+ * project's reset link (`resetLinkOf`). Default: `/reset-password`, `?token=`.
2236
+ */
2237
+ resetPagePath?: string
2238
+ tokenInFragment?: boolean
2239
+ /**
2240
+ * The forgot-password node's sender (`resetEmailSenderOf`): the emails to an
2241
+ * address the site already knows go through it when the sign-up node has no
2242
+ * email provider.
2243
+ */
2244
+ noticeEmail?: KnownAddressEmailSender
2245
+ /**
2246
+ * The project has the newsletter, and the sign-up form's box joins it: a
2247
+ * ticked box (consent) also subscribes the new account through the
2248
+ * newsletter helper (`subscribeNewsletterPerson`, sign-up point `signup`).
2249
+ */
2250
+ newsletter?: boolean
2251
+ }
2252
+
2253
+ /**
2254
+ * After a new account with a ticked consent box: the newsletter helper adds it
2255
+ * (double opt-in, the `newsletter-subscribed` event, the newsletter's welcome
2256
+ * unless the account's own went out). Best effort, like the welcome email.
2257
+ */
2258
+ const SIGNUP_NEWSLETTER_CODE = ` // The ticked box also subscribes the person to the newsletter.
2259
+ if (userData.marketing_consent) {
2260
+ try {
2261
+ const __newsletter = require('../../../utils/newsletter/newsletter');
2262
+ await __newsletter.withNewsletterDb(function (db) {
2263
+ return __newsletter.subscribeNewsletterPerson({ db: db, email: email, signUpPoint: 'signup', req: req });
2264
+ });
2265
+ } catch (newsletterErr) {
2266
+ console.error('[account-signup] newsletter sign-up failed:', newsletterErr && newsletterErr.message ? newsletterErr.message : newsletterErr);
2267
+ }
2268
+ }
2269
+ `
2270
+
2271
+ /** An email sender baked into a route: provider id without `email-`, sender, credential env var. */
2272
+ export interface KnownAddressEmailSender {
2273
+ emailProvider?: string | null
2274
+ fromEmail?: string
2275
+ emailSecretEnvName?: string | null
2276
+ }
2277
+
2278
+ /**
2279
+ * The answer to a sign-up for an address the site already knows (an account,
2280
+ * or a row without a password) takes at least this long, as the
2281
+ * forgot-password answer does: the two are answered alike, and the time must
2282
+ * not tell them apart either.
2283
+ */
2284
+ export const KNOWN_ADDRESS_MIN_RESPONSE_MS = 1200
2285
+
2286
+ /**
2287
+ * The sign-up route's emails to an address the site already knows, sent
2288
+ * through `sender` (the sign-up node's, else the forgot-password node's):
2289
+ * `sendAccountNotice(emailType, msg, logged)`, which sends and records the
2290
+ * email under its own purpose (with what the log may keep), and
2291
+ * `sendSetPasswordEmail(user, siteName, req)`, the link for an address without
2292
+ * a password, built on the forgot-password token flow (a CSPRNG token whose
2293
+ * SHA-256 alone is stored against the account, the same lifetime, origin rule
2294
+ * and reset page).
2295
+ */
2296
+ const generateKnownAddressEmailCode = (options: {
2297
+ sender: { provider: string | null; from: string; secretEnv: string }
2298
+ pagePath: string
2299
+ tokenInFragment: boolean
2300
+ }): string => {
2301
+ const { sender } = options
2302
+ const senderConstants = `
2303
+ // Who sends the emails to an address the site already knows: the sign-up
2304
+ // node's email settings, else the forgot-password node's.
2305
+ const NOTICE_EMAIL_PROVIDER = ${JSON.stringify(sender.provider)};
2306
+ const NOTICE_EMAIL_FROM = ${JSON.stringify(sender.from)};
2307
+ const NOTICE_EMAIL_SECRET_ENV_NAME = ${JSON.stringify(sender.secretEnv)};`
2308
+ if (!sender.provider) {
2309
+ return `${senderConstants}
2310
+
2311
+ // No email provider: nothing is sent to an address the site already knows.
2312
+ async function sendAccountNotice() {}
2313
+
2314
+ // A sign-up for an address the site knows without a password mails its owner
2315
+ // a link to set one; this project has no email provider, so none is sent.
2316
+ async function sendSetPasswordEmail() {
2317
+ console.warn('[account-signup] set-password link not sent: no email provider is configured');
2318
+ }`
2319
+ }
2320
+ const ttlMinutes = Math.round(PASSWORD_RESET_TOKEN_TTL_SECONDS / 60)
2321
+ // Where the link carries the token, as the forgot-password link does.
2322
+ const tokenLinkPrefix = options.tokenInFragment ? '#token=' : '?token='
2323
+ const noticeSend = generateProviderSendFunction(sender.provider).replace(
2324
+ 'async function __sendProviderEmail(',
2325
+ 'async function __sendNoticeEmail('
2326
+ )
2327
+ return `${senderConstants}
2328
+
2329
+ ${noticeSend}
2330
+
2331
+ var __noticeEmailLog = require('../../../utils/email/sent-email-log');
2332
+
2333
+ // Sends one of these emails and records it under its own purpose, with what
2334
+ // the log may keep of it (\`logged\`: a link's token hidden).
2335
+ async function sendAccountNotice(emailType, msg, logged) {
2336
+ var failure = null;
2337
+ try {
2338
+ await __sendNoticeEmail(msg);
2339
+ } catch (err) {
2340
+ failure = err;
2341
+ }
2342
+ __noticeEmailLog.recordSentEmail({
2343
+ emailType: emailType,
2344
+ audience: 'customer',
2345
+ to: msg.to,
2346
+ from: msg.from,
2347
+ subject: logged.subject,
2348
+ html: logged.html,
2349
+ payload: logged.payload,
2350
+ provider: NOTICE_EMAIL_PROVIDER,
2351
+ status: failure ? 'failed' : 'sent',
2352
+ error: failure ? (failure.message || String(failure)) : null,
2353
+ source: 'signup',
2354
+ sourceRef: 'api/auth/signup',
2355
+ userId: msg.userId,
2356
+ });
2357
+ if (failure) { throw failure; }
2358
+ }
2359
+
2360
+ // A sign-up for an address the site knows without a password (a newsletter
2361
+ // subscriber, a checkout or booking guest, a contact the owner added) never
2362
+ // takes that row: whoever typed the address may not own it. Its owner is mailed
2363
+ // a link to set a password instead, a password-reset link minted and stored as
2364
+ // the forgot-password route mints it, at most ${EXISTING_ACCOUNT_EMAIL_LIMIT} an hour per address
2365
+ // (counted with the "already have an account" email).
2366
+ var SET_PASSWORD_SUBJECT = 'Set your password to finish creating your account';
2367
+ var SET_PASSWORD_BODY_HTML =
2368
+ '<p>Someone, hopefully you, tried to create an account{{siteNameSuffix}} with this email address.</p>' +
2369
+ '<p>This address is already known here (from a newsletter sign-up or an order, for example), but it has no password yet. Set one to finish creating your account:</p>' +
2370
+ '<p><a href="{{resetUrl}}">Set your password</a></p>' +
2371
+ '<p>The link works for ${ttlMinutes} minutes. If this was not you, you can ignore this email: nothing has changed.</p>';
2372
+ var SET_PASSWORD_PAGE_PATH = ${JSON.stringify(options.pagePath)};
2373
+ var SET_PASSWORD_TOKEN_LINK_PREFIX = ${JSON.stringify(tokenLinkPrefix)};
2374
+ var SET_PASSWORD_TOKEN_TTL_SECONDS = ${PASSWORD_RESET_TOKEN_TTL_SECONDS};
2375
+
2376
+ ${TRUSTED_ORIGIN_CODE}
2377
+
2378
+ // The token, wherever it appears, for what the sent-email log keeps: whoever
2379
+ // can read the log must not be able to set the password with it.
2380
+ function hideToken(text, token) {
2381
+ return String(text == null ? '' : text).split(token).join('[hidden]');
2382
+ }
2383
+
2384
+ async function sendSetPasswordEmail(user, siteName, req) {
2385
+ var toEmail = String(user.email || '');
2386
+ var userId = user.id != null ? user.id : user._id;
2387
+ var apiKey = NOTICE_EMAIL_SECRET_ENV_NAME ? process.env[NOTICE_EMAIL_SECRET_ENV_NAME] : '';
2388
+ if (apiKey && String(apiKey).indexOf('teleporthq.secrets.') === 0) { apiKey = ''; }
2389
+ var from = NOTICE_EMAIL_FROM || process.env.EMAIL_FROM || '';
2390
+ if (!apiKey || !from) { console.warn('[account-signup] set-password link not sent: the email credential or sender is not set'); return; }
2391
+ if (!toEmail || userId == null) { return; }
2392
+ var allowed = await __security.rateLimit({
2393
+ key: 'auth-signup-existing:' + toEmail.trim().toLowerCase(),
2394
+ limit: ${EXISTING_ACCOUNT_EMAIL_LIMIT},
2395
+ windowSeconds: 3600,
2396
+ });
2397
+ if (!allowed.allowed) { return; }
2398
+ var crypto = require('crypto');
2399
+ var token = crypto.randomBytes(32).toString('hex');
2400
+ await authUtils.storePasswordReset(userId, crypto.createHash('sha256').update(token).digest('hex'), SET_PASSWORD_TOKEN_TTL_SECONDS);
2401
+ var resetUrl = trustedOrigin(req) + SET_PASSWORD_PAGE_PATH + SET_PASSWORD_TOKEN_LINK_PREFIX + token;
2402
+ var html = fillTemplate(SET_PASSWORD_BODY_HTML, { siteNameSuffix: siteName ? ' on ' + siteName : '', resetUrl: resetUrl });
2403
+ await sendAccountNotice(
2404
+ ${JSON.stringify(SET_PASSWORD_EMAIL)},
2405
+ { from: from, to: toEmail, subject: SET_PASSWORD_SUBJECT, html: html, apiKey: apiKey, userId: userId },
2406
+ {
2407
+ subject: SET_PASSWORD_SUBJECT,
2408
+ html: hideToken(html, token),
2409
+ payload: { resetUrl: hideToken(resetUrl, token), recipientEmail: toEmail },
2410
+ }
2411
+ );
2412
+ }`
2413
+ }
2414
+
1164
2415
  export const generateSignupRouteFile = (
1165
2416
  auth: UIDLAuthentication,
1166
- welcome: WelcomeEmailOptions = {}
2417
+ welcome: WelcomeEmailOptions = {},
2418
+ events: AccountEventOptions = {},
2419
+ signup: SignupRouteOptions = {}
1167
2420
  ): string => {
1168
2421
  const needsDb = !!auth.dataSourceType
2422
+ const recordsSignup = needsDb && events.withAutomations === true
1169
2423
  const welcomeProvider =
1170
2424
  welcome.emailProvider && SUPPORTED_EMAIL_PROVIDERS.has(welcome.emailProvider)
1171
2425
  ? welcome.emailProvider
1172
2426
  : null
1173
- // Reserved keys that must NOT be copied from the request body onto the new
1174
- // user row — the auth fields plus every welcome-email config key (a stale
1175
- // client could otherwise inject them as bogus user columns).
1176
- const reservedKeysObj: Record<string, number> = { email: 1, password: 1, name: 1, role: 1 }
1177
- for (const key of WELCOME_EMAIL_CONFIG_KEYS) {
1178
- reservedKeysObj[key] = 1
1179
- }
1180
- // A custom account property the session reads a role from (`roles`,
1181
- // `roleName`, or `role` in another case, which Postgres folds onto the same
1182
- // column) is set by the server alone — a signup body naming it would pick
1183
- // its own role.
1184
- for (const prop of auth.customUserProperties || []) {
1185
- if (ROLE_BEARING_USER_KEY.test(prop.key)) {
1186
- reservedKeysObj[prop.key] = 1
1187
- }
1188
- }
2427
+ // An ALLOW-list: the only body keys copied onto the new user row. Whatever
2428
+ // else the body carries (a role, `is_admin`, `email_verified`, credits, a
2429
+ // plan, a welcome-email config key) never reaches createUser. The columns
2430
+ // the route sets itself (source, consent) are never copied from it either.
2431
+ const signupFields = (signup.fields || ['image']).filter(
2432
+ (field) => field && !isPrivilegedUserField(field) && SIGNUP_OWN_COLUMNS.indexOf(field) === -1
2433
+ )
2434
+ const setPasswordPagePath = resolveResetPagePath(signup.resetPagePath)
2435
+ // The emails to an address the site already knows go through the sign-up
2436
+ // node's sender, else the forgot-password node's.
2437
+ const fallbackSender = signup.noticeEmail || {}
2438
+ const noticeSender = welcomeProvider
2439
+ ? {
2440
+ provider: welcomeProvider,
2441
+ from: welcome.fromEmail || '',
2442
+ secretEnv: welcome.emailSecretEnvName || '',
2443
+ }
2444
+ : {
2445
+ provider:
2446
+ fallbackSender.emailProvider &&
2447
+ SUPPORTED_EMAIL_PROVIDERS.has(fallbackSender.emailProvider)
2448
+ ? fallbackSender.emailProvider
2449
+ : null,
2450
+ from: fallbackSender.fromEmail || '',
2451
+ secretEnv: fallbackSender.emailSecretEnvName || '',
2452
+ }
1189
2453
  let dbImport = ''
1190
2454
  let createUserCall = ''
1191
2455
  let welcomeHelpers = ''
@@ -1193,8 +2457,7 @@ export const generateSignupRouteFile = (
1193
2457
  if (needsDb) {
1194
2458
  dbImport = `const authUtils = require('../../../utils/auth/auth-options');
1195
2459
  const createUser = authUtils.createUser;
1196
- const userExistsByEmail = authUtils.userExistsByEmail;
1197
- const sanitizeUser = authUtils.sanitizeUser;`
2460
+ const findSignupUserByEmail = authUtils.findSignupUserByEmail;`
1198
2461
 
1199
2462
  // Baked welcome-email helpers + config (no-op send when no provider set).
1200
2463
  welcomeHelpers = `
@@ -1234,19 +2497,95 @@ async function sendWelcomeEmail(toEmail, tokenValues, userId, locale) {
1234
2497
  var from = WELCOME_EMAIL_FROM || process.env.EMAIL_FROM || '';
1235
2498
  if (!from) { console.warn('[account-signup] welcome email skipped: sender not configured'); return; }
1236
2499
  var copy = resolveWelcomeEmailCopy(locale);
1237
- var subject = fillTemplate(copy.subject, tokenValues);
2500
+ var subject = fillSubjectTemplate(copy.subject, tokenValues);
1238
2501
  var html = fillTemplate(copy.body, tokenValues);
1239
2502
  await __sendProviderEmail({ from: from, fromName: WELCOME_EMAIL_FROM_NAME, to: toEmail, subject: subject, html: html, apiKey: apiKey, tokenValues: tokenValues, userId: userId });
1240
2503
  }
1241
- `
1242
2504
 
1243
- createUserCall = ` const exists = await userExistsByEmail(email);
1244
- if (exists) {
1245
- // A newsletter subscriber or a contact the owner added has a row but no
1246
- // password. Signing up must not hand that row — and what the site knows
1247
- // about the person — to whoever types the address first; the password
1248
- // reset proves the mailbox is theirs.
1249
- res.status(409).json({ error: 'An account with this email already exists. Sign in, or use "Forgot password" to set a password.' });
2505
+ // A sign-up for an address that already has an account gets the same status,
2506
+ // body and headers as a new one; its time differs from a new address's, which
2507
+ // the account a new sign-up makes reveals anyway. The address's owner is told
2508
+ // by email instead (only the mailbox owner reads it), at most
2509
+ // ${EXISTING_ACCOUNT_EMAIL_LIMIT} times an hour per address, through the known-address sender.
2510
+ var EXISTING_ACCOUNT_SUBJECT = 'You already have an account';
2511
+ var EXISTING_ACCOUNT_BODY_HTML =
2512
+ '<p>Someone, hopefully you, tried to create an account{{siteNameSuffix}} with this email address.</p>' +
2513
+ '<p>You already have one. Sign in with your password, or use "Forgot password" on the sign-in page to choose a new one.</p>' +
2514
+ '<p>If this was not you, you can ignore this email: nothing has changed.</p>';
2515
+
2516
+ async function sendExistingAccountEmail(toEmail, siteName, userId) {
2517
+ if (!NOTICE_EMAIL_PROVIDER || !toEmail) { return; }
2518
+ var apiKey = NOTICE_EMAIL_SECRET_ENV_NAME ? process.env[NOTICE_EMAIL_SECRET_ENV_NAME] : '';
2519
+ if (apiKey && String(apiKey).indexOf('teleporthq.secrets.') === 0) { apiKey = ''; }
2520
+ var from = NOTICE_EMAIL_FROM || process.env.EMAIL_FROM || '';
2521
+ if (!apiKey || !from) { return; }
2522
+ var allowed = await __security.rateLimit({
2523
+ key: 'auth-signup-existing:' + String(toEmail).trim().toLowerCase(),
2524
+ limit: ${EXISTING_ACCOUNT_EMAIL_LIMIT},
2525
+ windowSeconds: 3600,
2526
+ });
2527
+ if (!allowed.allowed) { return; }
2528
+ var tokenValues = { siteNameSuffix: siteName ? ' on ' + siteName : '' };
2529
+ var html = fillTemplate(EXISTING_ACCOUNT_BODY_HTML, tokenValues);
2530
+ await sendAccountNotice(
2531
+ ${JSON.stringify(EXISTING_ACCOUNT_EMAIL)},
2532
+ { from: from, to: toEmail, subject: EXISTING_ACCOUNT_SUBJECT, html: html, apiKey: apiKey, userId: userId },
2533
+ { subject: EXISTING_ACCOUNT_SUBJECT, html: html, payload: tokenValues }
2534
+ );
2535
+ }
2536
+ ${generateKnownAddressEmailCode({
2537
+ sender: noticeSender,
2538
+ pagePath: setPasswordPagePath,
2539
+ tokenInFragment: signup.tokenInFragment === true,
2540
+ })}
2541
+
2542
+ function waitUntilElapsed(startedAt, ms) {
2543
+ var left = ms - (Date.now() - startedAt);
2544
+ return left > 0 ? new Promise(function (resolve) { setTimeout(resolve, left); }) : Promise.resolve();
2545
+ }
2546
+ ${
2547
+ recordsSignup
2548
+ ? generateAccountEventRecorder({ relativePrefix: '../../..', logTag: '[account-signup]' })
2549
+ : ''
2550
+ }`
2551
+
2552
+ createUserCall = ` // The answer is the same for a new account and for an address that already
2553
+ // has one (see sendExistingAccountEmail): built from what the visitor sent.
2554
+ const answer = { user: { email: email, name: name || null } };
2555
+ const __siteName = WELCOME_EMAIL_SITE_NAME ||
2556
+ (req.headers && req.headers.host ? String(req.headers.host).replace(/^www\\./, '').split(':')[0] : '');
2557
+ // In any letter case: \`Ava@site.test\` is the \`ava@site.test\` row.
2558
+ const existing = await findSignupUserByEmail(email);
2559
+ if (existing) {
2560
+ // A newsletter subscriber, a checkout or booking guest or a contact the
2561
+ // owner added has a row but no password (and no OAuth sign-in). Signing
2562
+ // up must not hand that row — and what the site knows about the person —
2563
+ // to whoever types the address first: its owner is mailed a link to set
2564
+ // a password, which proves the mailbox is theirs. An account's owner is
2565
+ // told it already has one. Either way the page is answered alike, so it
2566
+ // never tells a subscriber or a guest from an account.
2567
+ const knownEmail = String(existing.email || email);
2568
+ const existingId = existing.id != null ? existing.id : existing._id;
2569
+ try {
2570
+ if (!existing.password && !existing.provider && authUtils.PASSWORD_RESET_SUPPORTED) {
2571
+ await sendSetPasswordEmail(existing, __siteName, req);
2572
+ } else {
2573
+ // An account; or a row without a password where the store cannot
2574
+ // keep reset links (not Postgres): told it is already known here.
2575
+ await sendExistingAccountEmail(knownEmail, __siteName, existingId);
2576
+ }
2577
+ } catch (existingErr) {
2578
+ console.error('[account-signup] existing-account email failed:', existingErr && existingErr.message ? existingErr.message : existingErr);
2579
+ }
2580
+ ${
2581
+ noticeSender.provider
2582
+ ? ` await __noticeEmailLog.settleSentEmailLog();
2583
+ `
2584
+ : ''
2585
+ } // At least ${KNOWN_ADDRESS_MIN_RESPONSE_MS} ms, like the forgot-password answer: the time tells
2586
+ // neither which email went out nor whether one did.
2587
+ await waitUntilElapsed(startedAt, ${KNOWN_ADDRESS_MIN_RESPONSE_MS});
2588
+ res.status(201).json(answer);
1250
2589
  return;
1251
2590
  }
1252
2591
 
@@ -1255,12 +2594,16 @@ async function sendWelcomeEmail(toEmail, tokenValues, userId, locale) {
1255
2594
  email: email,
1256
2595
  password: hashedPassword,
1257
2596
  role: 'user',
2597
+ // Where the person came from, and their consent as they gave it: the
2598
+ // "Email me news and offers" box ticked ('true') or not. Never assumed.
2599
+ source: 'signup',
2600
+ marketing_consent: body.marketing_consent === 'true',
1258
2601
  };
1259
- const reservedKeys = ${JSON.stringify(reservedKeysObj)};
1260
- const bodyKeys = Object.keys(body);
1261
- for (let i = 0; i < bodyKeys.length; i++) {
1262
- if (!reservedKeys[bodyKeys[i]]) {
1263
- userData[bodyKeys[i]] = body[bodyKeys[i]];
2602
+ // Only the fields this project's sign-up forms collect.
2603
+ const signupFields = ${JSON.stringify(signupFields)};
2604
+ for (let i = 0; i < signupFields.length; i++) {
2605
+ if (Object.prototype.hasOwnProperty.call(body, signupFields[i])) {
2606
+ userData[signupFields[i]] = body[signupFields[i]];
1264
2607
  }
1265
2608
  }
1266
2609
 
@@ -1273,12 +2616,10 @@ async function sendWelcomeEmail(toEmail, tokenValues, userId, locale) {
1273
2616
 
1274
2617
  // Best-effort welcome email — a failed send must never fail the signup.
1275
2618
  try {
1276
- const __welcomeSiteName = WELCOME_EMAIL_SITE_NAME ||
1277
- (req.headers && req.headers.host ? String(req.headers.host).replace(/^www\\./, '').split(':')[0] : '');
1278
2619
  await sendWelcomeEmail(email, {
1279
2620
  userName: name || (newUser && newUser.name) || 'there',
1280
2621
  userEmail: email,
1281
- siteName: __welcomeSiteName,
2622
+ siteName: __siteName,
1282
2623
  }, newUser && newUser.id, __emailLocale.resolveRequestLocale(req));
1283
2624
  } catch (welcomeErr) {
1284
2625
  console.error('[account-signup] welcome email failed:', welcomeErr && welcomeErr.message ? welcomeErr.message : welcomeErr);
@@ -1289,13 +2630,20 @@ ${
1289
2630
  if (typeof __sentEmailLog !== 'undefined') { await __sentEmailLog.settleSentEmailLog(); }
1290
2631
  `
1291
2632
  : ''
1292
- }
1293
- res.status(201).json({ user: sanitizeUser(newUser) });`
2633
+ }${
2634
+ recordsSignup
2635
+ ? ` // The account exists: the last thing the signup does is record it.
2636
+ await recordAccountEvent('user-signed-up', newUser, 'signup', req);
2637
+ `
2638
+ : ''
2639
+ }${signup.newsletter === true ? SIGNUP_NEWSLETTER_CODE : ''}
2640
+ res.status(201).json(answer);`
1294
2641
  } else {
1295
2642
  createUserCall = ` res.status(501).json({ error: 'No data source configured for user storage' });`
1296
2643
  }
1297
2644
 
1298
2645
  return `const hashPassword = require('../../../utils/auth/hash-password');
2646
+ const __security = require('${securityRuntimeSpecifier('../../..')}');
1299
2647
  ${dbImport}
1300
2648
  ${welcomeHelpers}
1301
2649
 
@@ -1305,11 +2653,16 @@ module.exports = async function handler(req, res) {
1305
2653
  return;
1306
2654
  }
1307
2655
 
2656
+ // ${SIGN_UP_LIMIT} sign-ups per visitor per hour.
2657
+ if (!(await __security.rateLimitRequest(req, res, { scope: 'auth-signup', limit: ${SIGN_UP_LIMIT}, windowSeconds: ${SIGN_UP_WINDOW_SECONDS} }))) {
2658
+ return;
2659
+ }
2660
+ ${needsDb ? ' const startedAt = Date.now();\n' : ''}
1308
2661
  try {
1309
- const body = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;
1310
- const email = body.email;
1311
- const password = body.password;
1312
- const name = body.name;
2662
+ const body = (typeof req.body === 'string' ? JSON.parse(req.body) : req.body) || {};
2663
+ const email = typeof body.email === 'string' ? body.email : '';
2664
+ const password = typeof body.password === 'string' ? body.password : '';
2665
+ const name = typeof body.name === 'string' ? body.name : '';
1313
2666
 
1314
2667
  if (!email || !password) {
1315
2668
  res.status(400).json({ error: 'Email and password are required' });
@@ -1322,13 +2675,9 @@ module.exports = async function handler(req, res) {
1322
2675
  return;
1323
2676
  }
1324
2677
 
1325
- if (password.length < 6) {
1326
- res.status(400).json({ error: 'Password must be at least 6 characters' });
1327
- return;
1328
- }
1329
-
1330
- if (password.length > 128) {
1331
- res.status(400).json({ error: 'Password must not exceed 128 characters' });
2678
+ const policyError = hashPassword.passwordPolicyError(password);
2679
+ if (policyError) {
2680
+ res.status(400).json({ error: policyError });
1332
2681
  return;
1333
2682
  }
1334
2683
 
@@ -1336,8 +2685,7 @@ module.exports = async function handler(req, res) {
1336
2685
 
1337
2686
  ${createUserCall}
1338
2687
  } catch (error) {
1339
- console.error('Signup error:', error);
1340
- res.status(500).json({ error: 'Internal server error' });
2688
+ __security.sendClientError(res, 500, 'Sign-up failed. Please try again.', error);
1341
2689
  }
1342
2690
  };
1343
2691
  `
@@ -1659,40 +3007,19 @@ function getUserRoleFromToken(token) {
1659
3007
  return null;
1660
3008
  }
1661
3009
 
1662
- // Reads a single cookie value, tolerating both the Next 12 string shape and the
1663
- // newer { name, value } object shape returned by request.cookies.get().
1664
- function readCookie(request, name) {
1665
- try {
1666
- var c = request.cookies.get(name);
1667
- if (!c) return null;
1668
- return typeof c === 'string' ? c : (c.value || null);
1669
- } catch (e) {
1670
- return null;
1671
- }
1672
- }
1673
-
1674
- // next-auth stores the session token under a secure-prefixed cookie on https
1675
- // and a plain one on http, and splits large JWTs into ".0"/".1" chunks. The
3010
+ // The session token lives in the "__Host-" cookie on https and the plain one on
3011
+ // http (see the auth options), split into ".0"/".1" chunks when large. The
1676
3012
  // Edge runtime's getToken() can return null for a session the Node runtime
1677
3013
  // considers valid (e.g. NEXTAUTH_SECRET not identical in the Edge runtime, or
1678
3014
  // the JWE simply failing to decode at the edge), which previously redirected
1679
3015
  // logged-in users to sign-in. So cookie PRESENCE is the source of truth for
1680
3016
  // "is there a session"; getToken is only trusted for the optional role check.
1681
- // Server-side (getServerSideProps / API routes) remain the authoritative
1682
- // validators of the session and role.
3017
+ // Only the cookie the request's protocol allows counts — the same one
3018
+ // __tqSessionTokenCandidates names: a cookie a sibling site planted under
3019
+ // another name is never a session. Server-side (getServerSideProps / API
3020
+ // routes) remain the authoritative validators of the session and role.
1683
3021
  function hasSessionCookie(request) {
1684
- var names = [
1685
- '__Secure-next-auth.session-token',
1686
- 'next-auth.session-token',
1687
- '__Secure-authjs.session-token',
1688
- 'authjs.session-token'
1689
- ];
1690
- for (var i = 0; i < names.length; i++) {
1691
- if (readCookie(request, names[i]) || readCookie(request, names[i] + '.0')) {
1692
- return true;
1693
- }
1694
- }
1695
- return false;
3022
+ return __tqSessionTokenCandidates(request).length > 0;
1696
3023
  }
1697
3024
 
1698
3025
  // Turns a Next.js route pattern into an anchored matcher: "[param]" matches a
@@ -1955,8 +3282,10 @@ export const config = {
1955
3282
  // Next.js does NOT run the second (negative-lookahead) matcher for the root
1956
3283
  // path, which would leave a page published at "/" (e.g. a protected dashboard)
1957
3284
  // publicly reachable. '/' compiles to ^/$ and covers exactly the home route;
1958
- // the second entry covers every deeper path.
1959
- matcher: ['/', '/((?!api|_next/static|_next/image|favicon\\\\.ico).*)'],
3285
+ // the second entry covers every deeper path. Only the API routes are left
3286
+ // out — "/api" and "/api/..." — never a page whose path merely starts with
3287
+ // "api" (a protected "/api-keys" page).
3288
+ matcher: ['/', '/((?!api(?:/|$)|_next/static|_next/image|favicon\\\\.ico).*)'],
1960
3289
  };
1961
3290
  `
1962
3291
  }