@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,6 +1,28 @@
1
- import { SUPPORTED_EMAIL_PROVIDERS, generateProviderSendFunction, generateFillTemplateFn, generateEmailLocaleRequire, generateLocalizedEmailCopyFn, WELCOME_EMAIL_CONFIG_KEYS, } from './transactional-email-code';
2
- import { TableAccess } from '@teleporthq/teleport-shared';
1
+ import { SUPPORTED_EMAIL_PROVIDERS, generateProviderSendFunction, generateFillTemplateFn, generateEmailLocaleRequire, generateLocalizedEmailCopyFn, EXISTING_ACCOUNT_EMAIL, SET_PASSWORD_EMAIL, WELCOME_EMAIL_CONFIG_KEYS, } from './transactional-email-code';
2
+ import { PASSWORD_RESET_TOKEN_TTL_SECONDS, TRUSTED_ORIGIN_CODE, resolveResetPagePath, } from './password-reset-route-generator';
3
+ import { AccountFields, SessionCookieResolver, TableAccess } from '@teleporthq/teleport-shared';
3
4
  import { generateSessionTokenResolverCode } from './session-cookie-resolver';
5
+ import { AUTOMATIONS_PATH } from './automations/automations-scope';
6
+ import { SESSION_REVOCATION_FILE_NAME, SESSION_STAMP_KEY } from './session-revocation-generator';
7
+ import { securityRuntimeSpecifier } from './security-runtime/security-runtime-code';
8
+ /**
9
+ * Credentials sign-in throttle: a visitor's next sign-in for an email is
10
+ * refused (429) once this many failures for it are in the window, or once it
11
+ * was tried SIGN_IN_ATTEMPT_LIMIT times in the window whatever the outcome.
12
+ */
13
+ export const SIGN_IN_FAILURE_LIMIT = 10;
14
+ export const SIGN_IN_ATTEMPT_LIMIT = 30;
15
+ export const SIGN_IN_WINDOW_SECONDS = 900;
16
+ /** Failed sign-ins one visitor may make across every email in the window. */
17
+ export const SIGN_IN_VISITOR_FAILURE_LIMIT = 50;
18
+ /** Sign-ups per visitor per hour. */
19
+ export const SIGN_UP_LIMIT = 10;
20
+ /**
21
+ * "You already have an account" (or, for an address without a password,
22
+ * "Set your password") emails one address can be sent per hour.
23
+ */
24
+ export const EXISTING_ACCOUNT_EMAIL_LIMIT = 3;
25
+ export const SIGN_UP_WINDOW_SECONDS = 3600;
4
26
  // GUI provider id → the actual next-auth v4 provider MODULE name, for the few
5
27
  // cases where they differ. Everything else uses the id as the module name.
6
28
  // (Providers next-auth v4 cannot supply are not offered by the GUI; if one
@@ -191,8 +213,6 @@ export const SESSION_SAFE_USER_FIELDS = [
191
213
  'roleName',
192
214
  'roles',
193
215
  ];
194
- /** A `users` key the session derives the visitor's role from, in any case. */
195
- const ROLE_BEARING_USER_KEY = /^(roles?|role_?name)$/i;
196
216
  /**
197
217
  * Credentials that must never leave the server, whatever the `users` table
198
218
  * happens to declare: the OAuth single-table adapter's provider tokens plus the
@@ -227,6 +247,12 @@ export const SENSITIVE_USER_FIELDS = [
227
247
  * it is kept out of `SENSITIVE_USER_FIELDS`.
228
248
  */
229
249
  const ID_ALIAS_FIELD = '_id';
250
+ /**
251
+ * The Newsletter's own `users` columns (`newsletter_status`, …). A sign-in
252
+ * snapshot of them goes stale the moment the person confirms or unsubscribes,
253
+ * so they never reach the session: a page reads the row.
254
+ */
255
+ const NEWSLETTER_COLUMN_PREFIX = 'newsletter_';
230
256
  /**
231
257
  * The exact set of `users` columns this project allows into the session.
232
258
  *
@@ -239,7 +265,9 @@ const ID_ALIAS_FIELD = '_id';
239
265
  * properties without a matching `tables` entry.
240
266
  */
241
267
  export const buildSessionUserFields = (tables, customProps) => {
242
- const declared = ((tables === null || tables === void 0 ? void 0 : tables.users) || []).map((column) => column.name);
268
+ const declared = ((tables === null || tables === void 0 ? void 0 : tables.users) || [])
269
+ .map((column) => column.name)
270
+ .filter((name) => !name.startsWith(NEWSLETTER_COLUMN_PREFIX));
243
271
  const custom = customProps.map((prop) => prop.key);
244
272
  const denied = new Set(SENSITIVE_USER_FIELDS);
245
273
  return Array.from(new Set([...SESSION_SAFE_USER_FIELDS, ...declared, ...custom])).filter((field) => Boolean(field) && field !== ID_ALIAS_FIELD && !denied.has(field));
@@ -319,6 +347,45 @@ const generateCustomPropAirtableEntries = (props) => {
319
347
  .map((p) => ` ${p.key}: userData.${p.key} != null ? userData.${p.key} : '',`)
320
348
  .join('\n'));
321
349
  };
350
+ /**
351
+ * The `users` columns a sign-up writes itself, never from its form: where the
352
+ * person came from (`source = 'signup'`) and their consent as given
353
+ * (`marketing_consent`, from the "Email me news and offers" box). On the
354
+ * Postgres family `createUser` writes each one it is given, and creates the
355
+ * account without them on a users table made before they existed.
356
+ */
357
+ export const SIGNUP_OWN_COLUMNS = ['source', 'marketing_consent'];
358
+ /**
359
+ * `findSignupUserByEmail(email)`: the sign-up's own existence check, blind to
360
+ * letter case, so `Ava@site.test` signing up reaches the `ava@site.test` row
361
+ * (a subscriber, a guest, an account) instead of making a second one. The
362
+ * exact address first; else the one row equal to it in any case, none when
363
+ * that is ambiguous. Sign-in keeps its exact `findUserByEmail`. On the other
364
+ * stores it is that exact lookup.
365
+ */
366
+ const generateSignupLookupFunction = (dataSourceType) => {
367
+ switch (dataSourceType) {
368
+ case 'teleport':
369
+ case 'postgresql':
370
+ case 'cockroachdb':
371
+ return `async function findSignupUserByEmail(email) {
372
+ const client = getClient();
373
+ try {
374
+ await client.connect();
375
+ const exact = await client.query('SELECT * FROM users WHERE email = $1 LIMIT 1', [email]);
376
+ if (exact.rows && exact.rows.length > 0) return exact.rows[0];
377
+ const anyCase = await client.query('SELECT * FROM users WHERE LOWER(email) = LOWER($1) LIMIT 2', [email]);
378
+ return anyCase.rows && anyCase.rows.length === 1 ? anyCase.rows[0] : null;
379
+ } finally {
380
+ try { await client.end(); } catch (_e) {}
381
+ }
382
+ }`;
383
+ default:
384
+ return `async function findSignupUserByEmail(email) {
385
+ return findUserByEmail(email);
386
+ }`;
387
+ }
388
+ };
322
389
  const generateFindUserFunction = (dataSourceType, customProps) => {
323
390
  if (!dataSourceType) {
324
391
  return `async function findUserByEmail() { return null; }
@@ -332,6 +399,9 @@ async function userExistsByEmail() { return false; }`;
332
399
  const customValues = generateCustomPropValues(customProps);
333
400
  const docEntries = generateCustomPropDocEntries(customProps);
334
401
  const airtableEntries = generateCustomPropAirtableEntries(customProps);
402
+ // A declared account property of the same name is already one of the columns.
403
+ const customKeys = new Set(customProps.map((prop) => prop.key));
404
+ const signupOwnColumns = SIGNUP_OWN_COLUMNS.filter((column) => !customKeys.has(column));
335
405
  switch (dataSourceType) {
336
406
  case 'teleport':
337
407
  case 'postgresql':
@@ -347,14 +417,44 @@ async function userExistsByEmail() { return false; }`;
347
417
  }
348
418
  }
349
419
 
420
+ // What a sign-up writes besides its form (where the person came from, their
421
+ // consent as given), each when it is given. A users table made before one of
422
+ // them lacks it (the column is added when a feature that reads it is switched
423
+ // on): the account is then created without them.
424
+ const SIGNUP_OWN_COLUMNS = ${JSON.stringify(signupOwnColumns)};
425
+
350
426
  async function createUser(userData) {
351
427
  const client = getClient();
352
428
  try {
353
429
  await client.connect();
354
- const result = await client.query(
355
- 'INSERT INTO users (name, email, password, role, image${sqlCols}) VALUES ($1, $2, $3, $4, $5${pgPlaceholders}) RETURNING *',
356
- [userData.name || null, userData.email, userData.password, userData.role || 'user', userData.image || null${customValues}]
357
- );
430
+ const values = [userData.name || null, userData.email, userData.password, userData.role || 'user', userData.image || null${customValues}];
431
+ const insert = function (extra) {
432
+ let columns = '';
433
+ let placeholders = '';
434
+ for (let i = 0; i < extra.length; i++) {
435
+ columns += ', ' + extra[i];
436
+ placeholders += ', $' + (values.length + i + 1);
437
+ }
438
+ return client.query(
439
+ 'INSERT INTO users (name, email, password, role, image${sqlCols}' + columns + ') VALUES ($1, $2, $3, $4, $5${pgPlaceholders}' + placeholders + ') RETURNING *',
440
+ values.concat(extra.map(function (column) { return userData[column]; }))
441
+ );
442
+ };
443
+ let extra = SIGNUP_OWN_COLUMNS.filter(function (column) { return userData[column] !== undefined; });
444
+ let result = null;
445
+ while (!result) {
446
+ try {
447
+ result = await insert(extra);
448
+ } catch (err) {
449
+ // 42703 names a column the table does not have. Only that one is left
450
+ // out, and only when it is one of these: the others are still written.
451
+ const named = err && err.code === '42703' ? /column "([^"]+)"/.exec(String(err.message || '')) : null;
452
+ const missing = named ? named[1] : '';
453
+ if (!missing || extra.indexOf(missing) === -1) { throw err; }
454
+ console.warn('[auth] the users table has no ' + missing + ' column yet: the account is created without it');
455
+ extra = extra.filter(function (column) { return column !== missing; });
456
+ }
457
+ }
358
458
  return result.rows && result.rows.length > 0 ? result.rows[0] : null;
359
459
  } finally {
360
460
  try { await client.end(); } catch (_e) {}
@@ -555,6 +655,269 @@ async function createUser() { return null; }
555
655
  async function userExistsByEmail() { return false; }`;
556
656
  }
557
657
  };
658
+ /** Where the password-reset links live: hashed, single-use, per account id. */
659
+ export const PASSWORD_RESETS_TABLE = 'teleport_password_resets';
660
+ const PG_PASSWORD_RESET_FUNCTIONS = `
661
+ // Password-reset links (pages/api/auth/forgot-password + reset-password). Only
662
+ // the SHA-256 of a link's token is stored, bound to the account id, with its
663
+ // expiry; the table is created on first use. The earlier password_reset_tokens
664
+ // table and its rows are never read.
665
+ var PASSWORD_RESETS_TABLE = '${PASSWORD_RESETS_TABLE}';
666
+ var __passwordResetsTableReady = false;
667
+
668
+ async function ensurePasswordResetsTable(client) {
669
+ if (__passwordResetsTableReady) return;
670
+ await client.query('BEGIN');
671
+ try {
672
+ await client.query('SELECT pg_advisory_xact_lock(hashtext($1))', [PASSWORD_RESETS_TABLE]);
673
+ await client.query(
674
+ 'CREATE TABLE IF NOT EXISTS ' + PASSWORD_RESETS_TABLE + ' (token_hash TEXT PRIMARY KEY, user_id TEXT NOT NULL, ' +
675
+ 'expires_at TIMESTAMPTZ NOT NULL, used_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW())'
676
+ );
677
+ await client.query('CREATE INDEX IF NOT EXISTS ' + PASSWORD_RESETS_TABLE + '_user_id_idx ON ' + PASSWORD_RESETS_TABLE + ' (user_id)');
678
+ await client.query('COMMIT');
679
+ } catch (err) {
680
+ try { await client.query('ROLLBACK'); } catch (_e) {}
681
+ throw err;
682
+ }
683
+ __passwordResetsTableReady = true;
684
+ }
685
+
686
+ // One live link per account: a new one ends the ones sent before it.
687
+ async function storePasswordReset(userId, tokenHash, ttlSeconds) {
688
+ const client = getClient();
689
+ try {
690
+ await client.connect();
691
+ await ensurePasswordResetsTable(client);
692
+ await client.query(
693
+ 'UPDATE ' + PASSWORD_RESETS_TABLE + ' SET used_at = NOW() WHERE user_id = $1 AND used_at IS NULL',
694
+ [String(userId)]
695
+ );
696
+ await client.query(
697
+ 'INSERT INTO ' + PASSWORD_RESETS_TABLE + " (token_hash, user_id, expires_at) VALUES ($1, $2, NOW() + ($3::int * INTERVAL '1 second'))",
698
+ [tokenHash, String(userId), ttlSeconds]
699
+ );
700
+ await client.query(
701
+ 'DELETE FROM ' + PASSWORD_RESETS_TABLE + " WHERE expires_at < NOW() - INTERVAL '1 day'"
702
+ );
703
+ } finally {
704
+ try { await client.end(); } catch (_e) {}
705
+ }
706
+ }
707
+
708
+ // Spends the link and sets the password in ONE statement: the link must be
709
+ // unspent and unexpired, and is spent by this call alone (a second call with the
710
+ // same token finds it used). Returns the account it was for, or null.
711
+ async function consumePasswordReset(tokenHash, passwordHash) {
712
+ const client = getClient();
713
+ try {
714
+ await client.connect();
715
+ const result = await client.query(
716
+ 'WITH consumed AS (' +
717
+ ' UPDATE ' + PASSWORD_RESETS_TABLE + ' SET used_at = NOW()' +
718
+ ' WHERE token_hash = $1 AND used_at IS NULL AND expires_at > NOW()' +
719
+ ' RETURNING user_id' +
720
+ '), changed AS (' +
721
+ ' UPDATE users SET password = $2 FROM consumed WHERE users.id::text = consumed.user_id' +
722
+ ' RETURNING users.id, users.email' +
723
+ ') SELECT id, email FROM changed',
724
+ [tokenHash, passwordHash]
725
+ );
726
+ return result.rows && result.rows.length > 0 ? result.rows[0] : null;
727
+ } catch (err) {
728
+ // 42P01: no link was ever sent, so the table is not there yet.
729
+ if (err && err.code === '42P01') return null;
730
+ throw err;
731
+ } finally {
732
+ try { await client.end(); } catch (_e) {}
733
+ }
734
+ }
735
+
736
+ async function passwordResetIsLive(tokenHash) {
737
+ const client = getClient();
738
+ try {
739
+ await client.connect();
740
+ const result = await client.query(
741
+ 'SELECT 1 FROM ' + PASSWORD_RESETS_TABLE + ' WHERE token_hash = $1 AND used_at IS NULL AND expires_at > NOW() LIMIT 1',
742
+ [tokenHash]
743
+ );
744
+ return !!(result.rows && result.rows.length > 0);
745
+ } catch (err) {
746
+ if (err && err.code === '42P01') return false;
747
+ throw err;
748
+ } finally {
749
+ try { await client.end(); } catch (_e) {}
750
+ }
751
+ }
752
+
753
+ const PASSWORD_RESET_SUPPORTED = true;`;
754
+ const UNSUPPORTED_PASSWORD_RESET_FUNCTIONS = `
755
+ // Password-reset links need a Postgres database; this project's user store is
756
+ // not one, so the reset routes answer without ever sending a link.
757
+ async function storePasswordReset() { throw new Error('Password reset needs a Postgres database'); }
758
+ async function consumePasswordReset() { return null; }
759
+ async function passwordResetIsLive() { return false; }
760
+ const PASSWORD_RESET_SUPPORTED = false;`;
761
+ /**
762
+ * `updateUserPasswordHash(user, newHash, oldHash)` — the sign-in moving a hash
763
+ * onto the project's own pepper. It writes only over the hash it verified, so a
764
+ * reset that landed in between is never undone. Plus the password-reset link
765
+ * store (Postgres family only).
766
+ */
767
+ const generatePasswordStoreFunctions = (dataSourceType) => {
768
+ switch (dataSourceType) {
769
+ case 'teleport':
770
+ case 'postgresql':
771
+ case 'cockroachdb':
772
+ return `// The account a stamped session was issued for (session-revocation). A value
773
+ // that is not an id of this table's type (22P02) is no account; any other
774
+ // error is thrown, so the session check fails closed.
775
+ async function findUserById(id) {
776
+ const client = getClient();
777
+ try {
778
+ await client.connect();
779
+ const result = await client.query('SELECT * FROM users WHERE id = $1 LIMIT 1', [id]);
780
+ return result.rows && result.rows.length > 0 ? result.rows[0] : null;
781
+ } catch (err) {
782
+ if (err && err.code === '22P02') return null;
783
+ throw err;
784
+ } finally {
785
+ try { await client.end(); } catch (_e) {}
786
+ }
787
+ }
788
+
789
+ async function updateUserPasswordHash(user, newHash, oldHash) {
790
+ const client = getClient();
791
+ try {
792
+ await client.connect();
793
+ const result = await client.query('UPDATE users SET password = $1 WHERE id = $2 AND password = $3', [newHash, user.id, oldHash]);
794
+ return !!(result && result.rowCount > 0);
795
+ } finally {
796
+ try { await client.end(); } catch (_e) {}
797
+ }
798
+ }
799
+ ${PG_PASSWORD_RESET_FUNCTIONS}`;
800
+ case 'supabase':
801
+ return `async function findUserById(id) {
802
+ const client = getSupabaseClient();
803
+ const result = await client.from('users').select('*').eq('id', id).maybeSingle();
804
+ if (result.error) throw new Error(result.error.message || 'users lookup failed');
805
+ return result.data || null;
806
+ }
807
+
808
+ async function updateUserPasswordHash(user, newHash, oldHash) {
809
+ const client = getSupabaseClient();
810
+ const result = await client.from('users').update({ password: newHash }).eq('id', user.id).eq('password', oldHash).select('id');
811
+ return !!(result.data && result.data.length > 0);
812
+ }
813
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
814
+ case 'mysql':
815
+ case 'mariadb':
816
+ case 'tidb':
817
+ return `async function findUserById(id) {
818
+ const conn = await getConnection();
819
+ try {
820
+ const [rows] = await conn.execute('SELECT * FROM users WHERE id = ? LIMIT 1', [id]);
821
+ return rows && rows.length > 0 ? rows[0] : null;
822
+ } finally {
823
+ try { await conn.end(); } catch (_e) {}
824
+ }
825
+ }
826
+
827
+ async function updateUserPasswordHash(user, newHash, oldHash) {
828
+ const conn = await getConnection();
829
+ try {
830
+ const [result] = await conn.execute('UPDATE users SET password = ? WHERE id = ? AND password = ?', [newHash, user.id, oldHash]);
831
+ return !!(result && result.affectedRows > 0);
832
+ } finally {
833
+ try { await conn.end(); } catch (_e) {}
834
+ }
835
+ }
836
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
837
+ case 'mongodb':
838
+ return `async function findUserById(id) {
839
+ const client = await _mongoClientPromise;
840
+ const db = client.db();
841
+ const ObjectId = require('mongodb').ObjectId;
842
+ if (!ObjectId.isValid(String(id))) return null;
843
+ return await db.collection('users').findOne({ _id: new ObjectId(String(id)) });
844
+ }
845
+
846
+ async function updateUserPasswordHash(user, newHash, oldHash) {
847
+ const client = await _mongoClientPromise;
848
+ const db = client.db();
849
+ const result = await db.collection('users').updateOne({ _id: user._id, password: oldHash }, { $set: { password: newHash } });
850
+ return !!(result && result.modifiedCount > 0);
851
+ }
852
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
853
+ case 'firestore':
854
+ return `async function findUserById(id) {
855
+ const snap = await firestoreDb.collection('users').doc(String(id)).get();
856
+ return snap.exists ? Object.assign({ id: snap.id }, snap.data()) : null;
857
+ }
858
+
859
+ async function updateUserPasswordHash(user, newHash, oldHash) {
860
+ const ref = firestoreDb.collection('users').doc(String(user.id));
861
+ return firestoreDb.runTransaction(async function (tx) {
862
+ const snap = await tx.get(ref);
863
+ if (!snap.exists || snap.data().password !== oldHash) return false;
864
+ tx.update(ref, { password: newHash });
865
+ return true;
866
+ });
867
+ }
868
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
869
+ case 'turso':
870
+ return `async function findUserById(id) {
871
+ const result = await tursoClient.execute({ sql: 'SELECT * FROM users WHERE id = ? LIMIT 1', args: [id] });
872
+ return result.rows && result.rows.length > 0 ? result.rows[0] : null;
873
+ }
874
+
875
+ async function updateUserPasswordHash(user, newHash, oldHash) {
876
+ const result = await tursoClient.execute({ sql: 'UPDATE users SET password = ? WHERE id = ? AND password = ?', args: [newHash, user.id, oldHash] });
877
+ return !!(result && result.rowsAffected > 0);
878
+ }
879
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
880
+ case 'airtable':
881
+ return `async function findUserById(id) {
882
+ return new Promise(function(resolve, reject) {
883
+ airtableBase('users').find(String(id), function(err, rec) {
884
+ if (err && (err.statusCode === 404 || err.error === 'NOT_FOUND')) { resolve(null); return; }
885
+ if (err) { reject(err); return; }
886
+ resolve(rec ? Object.assign({ id: rec.id }, rec.fields) : null);
887
+ });
888
+ });
889
+ }
890
+
891
+ async function updateUserPasswordHash(user, newHash, oldHash) {
892
+ const current = await findUserByEmail(user.email);
893
+ if (!current || current.password !== oldHash) return false;
894
+ await new Promise(function(resolve, reject) {
895
+ airtableBase('users').update(String(user.id), { password: newHash }, function(err) { if (err) { reject(err); } else { resolve(); } });
896
+ });
897
+ return true;
898
+ }
899
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
900
+ default:
901
+ return `async function findUserById() { return null; }
902
+ async function updateUserPasswordHash() { return false; }
903
+ ${UNSUPPORTED_PASSWORD_RESET_FUNCTIONS}`;
904
+ }
905
+ };
906
+ /** Microsoft provider ids whose email claim is only trusted for one tenant. */
907
+ const MICROSOFT_PROVIDER_IDS = new Set(['azure-ad', 'microsoft-entra-id']);
908
+ /** The credential key naming a Microsoft provider's tenant (`*_TENANT_ID`, or Entra's `*_ISSUER`). */
909
+ const microsoftTenantKeyOf = (provider) => Object.keys(provider.credentials || {}).find((key) => key.endsWith('_TENANT_ID') || key.endsWith('_ISSUER'));
910
+ /** provider id → env var of its configured tenant, for each Microsoft provider. */
911
+ const microsoftTenantEnvKeys = (auth) => {
912
+ const keys = {};
913
+ for (const provider of auth.providers || []) {
914
+ const key = MICROSOFT_PROVIDER_IDS.has(provider.id) ? microsoftTenantKeyOf(provider) : undefined;
915
+ if (key) {
916
+ keys[provider.id] = key;
917
+ }
918
+ }
919
+ return keys;
920
+ };
558
921
  // Only the CredentialsProvider is imported at module scope (it always exists).
559
922
  // OAuth providers are required lazily inside generateProvidersSetup.
560
923
  const generateProviderImports = (auth) => {
@@ -592,11 +955,11 @@ const generateProvidersSetup = (auth) => {
592
955
  //
593
956
  // Unknown email and wrong password deliberately share one code: telling them
594
957
  // apart is a user-enumeration oracle.
595
- async authorize(credentials) {
958
+ async authorize(credentials, req) {
596
959
  if (!credentials || !credentials.email || !credentials.password) {
597
960
  throw new Error('MissingCredentials');
598
961
  }
599
- const { verifyPassword } = require('./hash-password');
962
+ const { checkPassword, hashPassword } = require('./hash-password');
600
963
  const { classifyAuthInfrastructureError } = require('./db-health');
601
964
  let user;
602
965
  try {
@@ -606,22 +969,35 @@ const generateProvidersSetup = (auth) => {
606
969
  console.error('[auth] Could not reach the user store (' + kind + '):', err && err.message ? err.message : err);
607
970
  throw new Error('ServiceUnavailable');
608
971
  }
972
+ let verdict;
609
973
  try {
610
- if (!user) throw new Error('InvalidCredentials');
611
- if (!verifyPassword(String(credentials.password), user.password)) {
612
- throw new Error('InvalidCredentials');
613
- }
614
- const signedIn = sanitizeUser(user);
615
- signedIn[TOKEN_PASSWORD_FINGERPRINT] = passwordFingerprint(user.password);
616
- return signedIn;
974
+ // No account, or one without a password, is checked too (against a
975
+ // stand-in hash): every failure costs what a wrong password costs.
976
+ verdict = checkPassword(String(credentials.password), user ? user.password : null);
617
977
  } catch (err) {
618
- if (err && err.message === 'InvalidCredentials') throw err;
619
978
  // A hashing/serialisation fault is an infrastructure problem, not a
620
979
  // wrong password — saying "check your details" would send the user
621
980
  // round in circles.
622
981
  console.error('[auth] Credential check failed:', err && err.message ? err.message : err);
623
982
  throw new Error('ServiceUnavailable');
624
983
  }
984
+ if (!verdict.ok) {
985
+ await countSignInFailure(req, credentials.email);
986
+ throw new Error('InvalidCredentials');
987
+ }
988
+ // A hash still made with the old pepper moves onto the project's own.
989
+ let storedHash = user.password;
990
+ if (verdict.needsRehash) {
991
+ try {
992
+ const rehashed = hashPassword(String(credentials.password));
993
+ if (await updateUserPasswordHash(user, rehashed, storedHash)) {
994
+ storedHash = rehashed;
995
+ }
996
+ } catch (err) {
997
+ console.error('[auth] Could not move the password onto the current pepper:', err && err.message ? err.message : err);
998
+ }
999
+ }
1000
+ return withSessionStamp(sanitizeUser(user), Object.assign({}, user, { password: storedHash }));
625
1001
  }
626
1002
  }));`);
627
1003
  }
@@ -635,7 +1011,12 @@ const generateProvidersSetup = (auth) => {
635
1011
  ` clientId: process.env.${idKey}`,
636
1012
  ` clientSecret: process.env.${secretKey}`,
637
1013
  ];
638
- if (issuerKey) {
1014
+ if (provider.id === 'azure-ad' && issuerKey && issuerKey.endsWith('_TENANT_ID')) {
1015
+ // next-auth's Azure AD provider takes the tenant as tenantId ("common",
1016
+ // every tenant, when absent).
1017
+ cfg.push(` tenantId: process.env.${issuerKey} || undefined`);
1018
+ }
1019
+ else if (issuerKey) {
639
1020
  cfg.push(` issuer: process.env.${issuerKey}`);
640
1021
  }
641
1022
  lines.push(`try {
@@ -656,16 +1037,34 @@ export const generateAuthOptionsFile = (auth, dataSourceConfig) => {
656
1037
  const providerImports = generateProviderImports(auth);
657
1038
  const providersSetup = generateProvidersSetup(auth);
658
1039
  const findUserCode = auth.passwordAuthEnabled
659
- ? generateFindUserFunction(auth.dataSourceType, customProps)
1040
+ ? `${generateFindUserFunction(auth.dataSourceType, customProps)}
1041
+
1042
+ ${generateSignupLookupFunction(auth.dataSourceType)}`
660
1043
  : '';
661
1044
  const sanitizeUserCode = generateSanitizeUserFunction(auth.tables, customProps);
662
1045
  const signInRoute = ((_a = auth.authPages.signIn) === null || _a === void 0 ? void 0 : _a.route) || '/auth/sign-in';
1046
+ // Password sign-in brings the local account a session can be revoked from;
1047
+ // with an OAuth provider beside it, an OAuth sign-in may become that account.
1048
+ const withPassword = !!auth.passwordAuthEnabled;
1049
+ // Every OAuth project checks whether the provider vouches for the email: an
1050
+ // unvouched email never is the visitor's identity, whether or not a local
1051
+ // account could be adopted (R15).
1052
+ const withOAuthBinding = (auth.providers || []).length > 0;
1053
+ const passwordSessionCode = withPassword
1054
+ ? `${generatePasswordStoreFunctions(auth.dataSourceType)}
1055
+
1056
+ ${CREDENTIAL_SESSION_HELPERS}
1057
+ `
1058
+ : '';
1059
+ const oauthBindingCode = withOAuthBinding
1060
+ ? `${generateOAuthEmailVerificationHelpers(auth)}\n`
1061
+ : '';
663
1062
  return `${providerImports}
664
1063
  ${dbSetupCode}
665
1064
  ${sanitizeUserCode}
666
1065
 
667
1066
  ${findUserCode}
668
-
1067
+ ${passwordSessionCode}${oauthBindingCode}
669
1068
  ${providersSetup}
670
1069
 
671
1070
  // How long a JWT may serve profile fields before the next /api/auth/session
@@ -716,7 +1115,25 @@ const authOptions = {
716
1115
  for (let i = 0; i < keys.length; i++) {
717
1116
  token[keys[i]] = user[keys[i]];
718
1117
  }
719
- // Deliberately NOT stamped. An OAuth \`user\` is the PROVIDER's profile
1118
+ ${withOAuthBinding
1119
+ ? ` // An OAuth sign-in becomes the local account with its email only when
1120
+ // the provider vouches for that email; otherwise it stays a session of
1121
+ // its own, without the account's id or role.
1122
+ if (params.account && params.account.type !== 'credentials') {
1123
+ if (!(await oauthEmailIsVerified(params.account, params.profile, token))) {
1124
+ asDistinctOAuthIdentity(token, params.account);
1125
+ }${withPassword
1126
+ ? ` else {
1127
+ // Vouched for: the next refresh adopts the local account with that
1128
+ // email (its id and role). Until then — and for good when there is
1129
+ // none — the id is the provider's, namespaced where it could equal
1130
+ // a local id.
1131
+ namespaceOAuthId(token, params.account);
1132
+ }`
1133
+ : ''}
1134
+ }
1135
+ `
1136
+ : ''} // Deliberately NOT stamped. An OAuth \`user\` is the PROVIDER's profile
720
1137
  // (id/name/email/image) — it carries no \`role\`, which only exists on
721
1138
  // the \`users\` row. Stamping here would make the first session request
722
1139
  // after an OAuth sign-in skip the database and leave the visitor
@@ -725,7 +1142,13 @@ const authOptions = {
725
1142
  // exactly as it does today, and the interval applies from there on.
726
1143
  return token;
727
1144
  }
728
- // Subsequent calls (every /api/auth/session): re-read the user from the
1145
+ ${withOAuthBinding
1146
+ ? ` // A session the provider did not vouch for never takes a local account.
1147
+ if (token && token[OAUTH_UNVERIFIED]) {
1148
+ return token;
1149
+ }
1150
+ `
1151
+ : ''} // Subsequent calls (every /api/auth/session): re-read the user from the
729
1152
  // database so profile edits — name, image, role, etc. — propagate into the
730
1153
  // session. The JWT is otherwise a snapshot captured at login, which is why
731
1154
  // the navbar avatar/name reverted to the old value after a refresh: the
@@ -746,35 +1169,17 @@ const authOptions = {
746
1169
  if (params.trigger !== 'update' && isFresh) {
747
1170
  return token;
748
1171
  }
749
- let passwordChanged = false;
750
- try {
751
- if (token && token.email && typeof findUserByEmail === 'function') {
752
- const fresh = await findUserByEmail(String(token.email));
753
- const safe = fresh && typeof sanitizeUser === 'function' ? sanitizeUser(fresh) : null;
754
- if (safe && typeof safe === 'object') {
755
- const fk = Object.keys(safe);
756
- for (let i = 0; i < fk.length; i++) {
757
- token[fk[i]] = safe[fk[i]];
758
- }
759
- }
760
- if (fresh) {
761
- const currentFingerprint = passwordFingerprint(fresh.password);
762
- if (typeof token[TOKEN_PASSWORD_FINGERPRINT] !== 'string') {
763
- token[TOKEN_PASSWORD_FINGERPRINT] = currentFingerprint;
764
- } else if (token[TOKEN_PASSWORD_FINGERPRINT] !== currentFingerprint) {
765
- passwordChanged = true;
766
- }
767
- }
768
- }
769
- } catch (e) {
1172
+ ${withPassword ? PASSWORD_REFRESH_CODE : PLAIN_REFRESH_CODE} } catch (e) {
770
1173
  // Keep the existing token on any DB hiccup — never sign the user out.
771
1174
  }
772
- if (passwordChanged) {
1175
+ ${withPassword
1176
+ ? ` if (revoked) {
773
1177
  // NextAuth answers a jwt callback that throws by clearing the session
774
- // cookie and returning no session: the visitor is signed out.
775
- throw new Error('The account password changed since this session signed in');
1178
+ // cookie: the visitor is signed out.
1179
+ throw new Error('SessionRevoked');
776
1180
  }
777
- // Stamped even when the read threw, so an unreachable database costs one
1181
+ `
1182
+ : ''} // Stamped even when the read threw, so an unreachable database costs one
778
1183
  // attempt per interval instead of one per request.
779
1184
  if (token) {
780
1185
  token[TOKEN_REFRESH_STAMP] = now;
@@ -788,7 +1193,7 @@ const authOptions = {
788
1193
  const skip = { iat: 1, exp: 1, jti: 1, sub: 1 };
789
1194
  skip[TOKEN_REFRESH_STAMP] = 1;
790
1195
  skip[TOKEN_PASSWORD_FINGERPRINT] = 1;
791
- const keys = Object.keys(token);
1196
+ ${withPassword ? ` skip['${SESSION_STAMP_KEY}'] = 1;\n` : ''}${withOAuthBinding ? ' skip[OAUTH_UNVERIFIED] = 1;\n' : ''} const keys = Object.keys(token);
792
1197
  for (let i = 0; i < keys.length; i++) {
793
1198
  if (!skip[keys[i]]) {
794
1199
  session.user[keys[i]] = token[keys[i]];
@@ -804,13 +1209,396 @@ const authOptions = {
804
1209
  secret: process.env.NEXTAUTH_SECRET,
805
1210
  };
806
1211
 
1212
+ // On https the session token and the callback-url cookie are "__Host-" cookies
1213
+ // (Path=/, Secure, HttpOnly, SameSite=Lax, no Domain): only this site can set
1214
+ // them. Published sites share a parent domain that is not a public suffix, so a
1215
+ // sibling site could otherwise plant a session cookie this site reads (cookie
1216
+ // tossing: the visitor silently signed in to someone else's account). Every
1217
+ // reader in the app reads this one name (session-cookie-resolver). NextAuth
1218
+ // reads the option on every request, after the auth route has set
1219
+ // NEXTAUTH_URL to the request's origin; on http (a local server) its defaults stay.
1220
+ var SECURE_SESSION_COOKIES = {
1221
+ sessionToken: {
1222
+ name: '${SessionCookieResolver.SECURE_SESSION_COOKIE_NAME}',
1223
+ options: { httpOnly: true, sameSite: 'lax', path: '/', secure: true },
1224
+ },
1225
+ callbackUrl: {
1226
+ name: '${SessionCookieResolver.SECURE_CALLBACK_URL_COOKIE_NAME}',
1227
+ options: { httpOnly: true, sameSite: 'lax', path: '/', secure: true },
1228
+ },
1229
+ };
1230
+ Object.defineProperty(authOptions, 'cookies', {
1231
+ enumerable: true,
1232
+ get: function () {
1233
+ return String(process.env.NEXTAUTH_URL || '').indexOf('https://') === 0 ? SECURE_SESSION_COOKIES : undefined;
1234
+ },
1235
+ });
1236
+
807
1237
  module.exports = authOptions;
808
1238
  module.exports.sanitizeUser = sanitizeUser;
809
1239
  ${auth.passwordAuthEnabled
810
- ? `module.exports.findUserByEmail = findUserByEmail;\nmodule.exports.createUser = createUser;\nmodule.exports.userExistsByEmail = userExistsByEmail;\n`
1240
+ ? `module.exports.findUserByEmail = findUserByEmail;\nmodule.exports.findSignupUserByEmail = findSignupUserByEmail;\nmodule.exports.createUser = createUser;\nmodule.exports.userExistsByEmail = userExistsByEmail;\n`
1241
+ : ''}${withPassword
1242
+ ? `module.exports.findUserById = findUserById;
1243
+ module.exports.checkSignInAllowed = checkSignInAllowed;
1244
+ module.exports.countSignInFailure = countSignInFailure;
1245
+ module.exports.SIGN_IN_VISITOR_HEADER = SIGN_IN_VISITOR_HEADER;
1246
+ module.exports.storePasswordReset = storePasswordReset;
1247
+ module.exports.consumePasswordReset = consumePasswordReset;
1248
+ module.exports.passwordResetIsLive = passwordResetIsLive;
1249
+ module.exports.PASSWORD_RESET_SUPPORTED = PASSWORD_RESET_SUPPORTED;
1250
+ `
811
1251
  : ''}
812
1252
  `;
813
1253
  };
1254
+ // The jwt callback's refresh without password sign-in (no local lookup exists).
1255
+ const PLAIN_REFRESH_CODE = ` try {
1256
+ if (token && token.email && typeof findUserByEmail === 'function') {
1257
+ const fresh = await findUserByEmail(String(token.email));
1258
+ const safe = fresh && typeof sanitizeUser === 'function' ? sanitizeUser(fresh) : null;
1259
+ if (safe && typeof safe === 'object') {
1260
+ const fk = Object.keys(safe);
1261
+ for (let i = 0; i < fk.length; i++) {
1262
+ token[fk[i]] = safe[fk[i]];
1263
+ }
1264
+ }
1265
+ }
1266
+ `;
1267
+ // With password sign-in: a stamped session follows its account BY ID (the key
1268
+ // every consumer acts on), so a deleted account or a changed password ends it
1269
+ // even after an email change; an unstamped one (an OAuth sign-in, a token from
1270
+ // before stamps) adopts the local account by its email.
1271
+ const PASSWORD_REFRESH_CODE = ` let revoked = false;
1272
+ try {
1273
+ const stamped = !!token && typeof token['${SESSION_STAMP_KEY}'] === 'string';
1274
+ const accountId = token && (token.id != null ? token.id : token.sub);
1275
+ let fresh = null;
1276
+ let looked = false;
1277
+ if (stamped && typeof findUserById === 'function') {
1278
+ fresh = accountId != null ? await findUserById(String(accountId)) : null;
1279
+ looked = true;
1280
+ } else if (token && token.email && typeof findUserByEmail === 'function') {
1281
+ fresh = await findUserByEmail(String(token.email));
1282
+ looked = true;
1283
+ }
1284
+ if (looked) {
1285
+ // The account's password (or session_version) changed since this
1286
+ // token was stamped, or the account is gone: the session is over.
1287
+ // Otherwise the token takes the stamp of the account as it is now.
1288
+ revoked = sessionStampCheck(token, fresh) === 'revoked';
1289
+ // The same end, for a token issued before stamps: a short fingerprint
1290
+ // of the stored hash, never the hash. A change (a reset included)
1291
+ // signs that session out at its next refresh.
1292
+ if (!revoked && fresh) {
1293
+ const currentFingerprint = passwordFingerprint(fresh.password);
1294
+ if (typeof token[TOKEN_PASSWORD_FINGERPRINT] !== 'string') {
1295
+ token[TOKEN_PASSWORD_FINGERPRINT] = currentFingerprint;
1296
+ } else if (token[TOKEN_PASSWORD_FINGERPRINT] !== currentFingerprint) {
1297
+ revoked = true;
1298
+ }
1299
+ }
1300
+ const safe = !revoked && fresh && typeof sanitizeUser === 'function' ? sanitizeUser(fresh) : null;
1301
+ if (safe && typeof safe === 'object') {
1302
+ const fk = Object.keys(safe);
1303
+ for (let i = 0; i < fk.length; i++) {
1304
+ token[fk[i]] = safe[fk[i]];
1305
+ }
1306
+ }
1307
+ }
1308
+ `;
1309
+ /**
1310
+ * auth-options helpers for password sign-in: the sign-in throttle (failures
1311
+ * per visitor and email, counted after a wrong password, checked by the
1312
+ * NextAuth route before the next attempt) and the session stamp
1313
+ * (`utils/auth/session-revocation.js`).
1314
+ */
1315
+ const CREDENTIAL_SESSION_HELPERS = `// Sign-in throttle. The NextAuth route refuses a visitor's next sign-in for an
1316
+ // email once SIGN_IN_FAILURE_LIMIT failures for it are in the window, once the
1317
+ // visitor has SIGN_IN_VISITOR_FAILURE_LIMIT failures across all emails, or once
1318
+ // they tried it SIGN_IN_ATTEMPT_LIMIT times (so a burst of parallel guesses
1319
+ // cannot all start before the first failure is counted). The route writes who
1320
+ // the visitor is on the request (SIGN_IN_VISITOR_HEADER, replacing whatever the
1321
+ // request carried), because NextAuth hands authorize() the headers only.
1322
+ var SIGN_IN_VISITOR_HEADER = 'x-teleport-signin-visitor';
1323
+ var SIGN_IN_FAILURE_SCOPE = 'auth-signin-failures';
1324
+ var SIGN_IN_FAILURE_LIMIT = ${SIGN_IN_FAILURE_LIMIT};
1325
+ var SIGN_IN_ATTEMPT_SCOPE = 'auth-signin-attempts';
1326
+ var SIGN_IN_ATTEMPT_LIMIT = ${SIGN_IN_ATTEMPT_LIMIT};
1327
+ var SIGN_IN_WINDOW_SECONDS = ${SIGN_IN_WINDOW_SECONDS};
1328
+ // Failures one visitor may make across every email (credential stuffing tries
1329
+ // many addresses once each), counted the same way: after a failure only.
1330
+ var SIGN_IN_VISITOR_FAILURE_SCOPE = 'auth-signin-visitor-failures';
1331
+ var SIGN_IN_VISITOR_FAILURE_LIMIT = ${SIGN_IN_VISITOR_FAILURE_LIMIT};
1332
+
1333
+ function signInVisitorRequest(req) {
1334
+ var headers = (req && req.headers) || {};
1335
+ var visitor = headers[SIGN_IN_VISITOR_HEADER];
1336
+ return { headers: {}, socket: { remoteAddress: typeof visitor === 'string' ? visitor : '' } };
1337
+ }
1338
+
1339
+ function signInEmailKey(email) {
1340
+ return String(email == null ? '' : email).trim().toLowerCase();
1341
+ }
1342
+
1343
+ // { allowed, retryAfter } for the sign-in the request is about to make.
1344
+ async function checkSignInAllowed(req) {
1345
+ var security = require('../security-runtime');
1346
+ var visitor = signInVisitorRequest(req);
1347
+ var email = signInEmailKey(req && req.body ? req.body.email : '');
1348
+ var failures = await security.peekRateLimitRequest(visitor, {
1349
+ scope: SIGN_IN_FAILURE_SCOPE,
1350
+ limit: SIGN_IN_FAILURE_LIMIT,
1351
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1352
+ keyParts: [email],
1353
+ });
1354
+ if (!failures.allowed) {
1355
+ return failures;
1356
+ }
1357
+ var visitorFailures = await security.peekRateLimitRequest(visitor, {
1358
+ scope: SIGN_IN_VISITOR_FAILURE_SCOPE,
1359
+ limit: SIGN_IN_VISITOR_FAILURE_LIMIT,
1360
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1361
+ });
1362
+ if (!visitorFailures.allowed) {
1363
+ return visitorFailures;
1364
+ }
1365
+ var attemptAllowed = await security.rateLimitRequest(visitor, null, {
1366
+ scope: SIGN_IN_ATTEMPT_SCOPE,
1367
+ limit: SIGN_IN_ATTEMPT_LIMIT,
1368
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1369
+ keyParts: [email],
1370
+ });
1371
+ if (!attemptAllowed) {
1372
+ var nowSec = Math.floor(Date.now() / 1000);
1373
+ return { allowed: false, retryAfter: Math.max(1, SIGN_IN_WINDOW_SECONDS - (nowSec % SIGN_IN_WINDOW_SECONDS)) };
1374
+ }
1375
+ return { allowed: true, retryAfter: 0 };
1376
+ }
1377
+
1378
+ async function countSignInFailure(req, email) {
1379
+ try {
1380
+ var security = require('../security-runtime');
1381
+ var visitor = signInVisitorRequest(req);
1382
+ await security.rateLimitRequest(visitor, null, {
1383
+ scope: SIGN_IN_FAILURE_SCOPE,
1384
+ limit: SIGN_IN_FAILURE_LIMIT,
1385
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1386
+ keyParts: [signInEmailKey(email)],
1387
+ });
1388
+ await security.rateLimitRequest(visitor, null, {
1389
+ scope: SIGN_IN_VISITOR_FAILURE_SCOPE,
1390
+ limit: SIGN_IN_VISITOR_FAILURE_LIMIT,
1391
+ windowSeconds: SIGN_IN_WINDOW_SECONDS,
1392
+ });
1393
+ } catch (err) {
1394
+ console.error('[auth] Could not count a failed sign-in:', err && err.message ? err.message : err);
1395
+ }
1396
+ }
1397
+
1398
+ // The shared session-stamp check (utils/auth/session-revocation.js).
1399
+ function sessionRevocationModule() {
1400
+ try {
1401
+ var revocation = require('./${SESSION_REVOCATION_FILE_NAME}');
1402
+ return revocation && typeof revocation.stampVerdict === 'function' ? revocation : null;
1403
+ } catch (e) {
1404
+ return null;
1405
+ }
1406
+ }
1407
+
1408
+ // A signed-in user's session carries the stamp of the account it was issued for.
1409
+ function withSessionStamp(safeUser, row) {
1410
+ var revocation = sessionRevocationModule();
1411
+ var stamp = revocation ? revocation.credentialStamp(row) : null;
1412
+ if (safeUser && stamp) {
1413
+ safeUser[revocation.SESSION_STAMP_KEY] = stamp;
1414
+ }
1415
+ if (safeUser) {
1416
+ safeUser[TOKEN_PASSWORD_FINGERPRINT] = passwordFingerprint(row ? row.password : null);
1417
+ }
1418
+ return safeUser;
1419
+ }
1420
+
1421
+ // 'revoked' when the stored account no longer matches the token's stamp;
1422
+ // otherwise the token takes the account's current stamp.
1423
+ function sessionStampCheck(token, row) {
1424
+ var revocation = sessionRevocationModule();
1425
+ if (!revocation) {
1426
+ return 'unchecked';
1427
+ }
1428
+ var verdict = revocation.stampVerdict(token, row || null);
1429
+ if (verdict !== 'revoked' && row) {
1430
+ var stamp = revocation.credentialStamp(row);
1431
+ if (stamp) {
1432
+ token[revocation.SESSION_STAMP_KEY] = stamp;
1433
+ }
1434
+ }
1435
+ return verdict;
1436
+ }`;
1437
+ /**
1438
+ * The user stores whose own account ids can never equal an OAuth provider's id:
1439
+ * MongoDB (`_id`, a 24-hex ObjectId), Airtable (`rec…` record ids) and
1440
+ * Firestore (20-character auto ids). Read from `auth.dataSourceType`, the same
1441
+ * value that picks the auth driver.
1442
+ */
1443
+ const STORES_WITH_DISJOINT_IDS = new Set(['mongodb', 'airtable', 'firestore']);
1444
+ /**
1445
+ * Whether an OAuth session's id must be namespaced (`oauth:<provider>:<id>`)
1446
+ * because the provider's raw account id could equal another account's id:
1447
+ * - the project has more than one OAuth provider: two providers' id spaces
1448
+ * can collide, whatever the store;
1449
+ * - otherwise a store whose ids are its own (STORES_WITH_DISJOINT_IDS) keeps
1450
+ * the raw id;
1451
+ * - any other store (SQL or not) is decided by the declared `users` id type:
1452
+ * a UUID keeps the raw id; any other type (a provider's integer id can equal
1453
+ * a local integer id on every owner rule), or none declared, namespaces.
1454
+ * The editor declares the type the database reported for its `users` table
1455
+ * (teleport-gui `liveUsersIdType`), and no type when none was recorded.
1456
+ * Where the raw id stays it never equals a local id, and every record a
1457
+ * published site wrote under it (entitlements, cart, favourites, chats,
1458
+ * downloads) stays the visitor's. Wherever a collision cannot be ruled out the
1459
+ * id is namespaced: a collision hands one person another's records, which no
1460
+ * later fix undoes; lost continuity leaves the records in place under the old
1461
+ * id.
1462
+ */
1463
+ export const oauthIdsNeedNamespace = (auth) => {
1464
+ if ((auth.providers || []).length > 1) {
1465
+ return true;
1466
+ }
1467
+ if (auth.dataSourceType && STORES_WITH_DISJOINT_IDS.has(auth.dataSourceType)) {
1468
+ return false;
1469
+ }
1470
+ const idColumn = ((auth.tables && auth.tables.users) || []).find((column) => !!column && String(column.name || '').toLowerCase() === 'id');
1471
+ return !(idColumn && /^\s*uuid\b/i.test(String(idColumn.type || '')));
1472
+ };
1473
+ /**
1474
+ * auth-options helpers for a project with password sign-in AND an OAuth
1475
+ * provider: whether the provider vouches for the email an OAuth sign-in
1476
+ * presents. Only then may that sign-in become the local account with the same
1477
+ * email (its id and role); otherwise it is a session of its own.
1478
+ */
1479
+ const generateOAuthEmailVerificationHelpers = (auth) => {
1480
+ const tenants = microsoftTenantEnvKeys(auth);
1481
+ const tenantEntries = Object.keys(tenants)
1482
+ .map((id) => `${JSON.stringify(id)}: process.env.${tenants[id]}`)
1483
+ .join(', ');
1484
+ return `// Providers that only ever hand out an email its owner proved. Any other
1485
+ // provider must say so in the profile (email_verified); an explicit "not
1486
+ // verified" outweighs the list.
1487
+ var VERIFIED_EMAIL_PROVIDERS = { google: true, apple: true };
1488
+ var OAUTH_UNVERIFIED = '__oauthUnverified';
1489
+ // A provider's raw account id could equal another account's id here (see
1490
+ // oauthIdsNeedNamespace in the code generator): sessions without a local
1491
+ // account take the provider's id as "oauth:<provider>:<id>".
1492
+ var OAUTH_IDS_NAMESPACED = ${JSON.stringify(oauthIdsNeedNamespace(auth))};
1493
+
1494
+ // Microsoft (Azure AD / Entra ID) tokens carry no email_verified, and on the
1495
+ // multi-tenant endpoint the email claim is whatever the signing-in tenant's
1496
+ // administrator set (the "nOAuth" class). An email counts only when the token
1497
+ // says its domain is verified (xms_edov), or when the provider is configured
1498
+ // for one specific tenant (an id or a domain, never common / organizations /
1499
+ // consumers): the site owner's own directory.
1500
+ var MICROSOFT_PROVIDERS = { 'azure-ad': true, 'microsoft-entra-id': true };
1501
+ var MICROSOFT_TENANTS = { ${tenantEntries} };
1502
+ var MICROSOFT_TENANT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
1503
+
1504
+ // The one tenant a Microsoft provider is configured for, or '' (multi-tenant).
1505
+ function microsoftTenantOf(value) {
1506
+ var raw = String(value == null ? '' : value).trim().toLowerCase();
1507
+ if (!raw || raw.indexOf('teleporthq.secrets.') === 0) {
1508
+ return '';
1509
+ }
1510
+ var fromIssuer = /^https:\\/\\/login\\.microsoftonline\\.com\\/([^\\/?#]+)/.exec(raw);
1511
+ var tenant = fromIssuer ? fromIssuer[1] : raw;
1512
+ if (tenant === 'common' || tenant === 'organizations' || tenant === 'consumers') {
1513
+ return '';
1514
+ }
1515
+ return MICROSOFT_TENANT_ID.test(tenant) || /^[a-z0-9-]+(\\.[a-z0-9-]+)+$/.test(tenant) ? tenant : '';
1516
+ }
1517
+
1518
+ function microsoftEmailIsVerified(provider, claims) {
1519
+ if (claims.xms_edov === true || claims.xms_edov === 'true' || claims.xms_edov === 1) {
1520
+ return true;
1521
+ }
1522
+ var tenant = microsoftTenantOf(MICROSOFT_TENANTS[provider]);
1523
+ if (!tenant) {
1524
+ return false;
1525
+ }
1526
+ // A tenant given by id must be the one the token was issued in.
1527
+ if (MICROSOFT_TENANT_ID.test(tenant) && claims.tid != null && String(claims.tid).toLowerCase() !== tenant) {
1528
+ return false;
1529
+ }
1530
+ return true;
1531
+ }
1532
+
1533
+ // GitHub's profile email is not always a verified one: ask GitHub (the
1534
+ // provider requests the user:email scope) whether this address is.
1535
+ async function githubEmailIsVerified(account, email) {
1536
+ if (!account || !account.access_token || !email) {
1537
+ return false;
1538
+ }
1539
+ try {
1540
+ var res = await fetch('https://api.github.com/user/emails', {
1541
+ headers: {
1542
+ Authorization: 'Bearer ' + account.access_token,
1543
+ Accept: 'application/vnd.github+json',
1544
+ 'User-Agent': 'teleporthq-auth',
1545
+ },
1546
+ });
1547
+ if (!res.ok) {
1548
+ return false;
1549
+ }
1550
+ var list = await res.json();
1551
+ var wanted = String(email).toLowerCase();
1552
+ return Array.isArray(list) && list.some(function (entry) {
1553
+ return !!entry && entry.verified === true && String(entry.email || '').toLowerCase() === wanted;
1554
+ });
1555
+ } catch (e) {
1556
+ return false;
1557
+ }
1558
+ }
1559
+
1560
+ async function oauthEmailIsVerified(account, profile, token) {
1561
+ var claims = profile || {};
1562
+ if (claims.email_verified === false || claims.email_verified === 'false') {
1563
+ return false;
1564
+ }
1565
+ if (claims.email_verified === true || claims.email_verified === 'true') {
1566
+ return true;
1567
+ }
1568
+ var provider = String((account && account.provider) || '');
1569
+ if (provider === 'github') {
1570
+ return githubEmailIsVerified(account, token && token.email);
1571
+ }
1572
+ if (MICROSOFT_PROVIDERS[provider] === true) {
1573
+ return microsoftEmailIsVerified(provider, claims);
1574
+ }
1575
+ return VERIFIED_EMAIL_PROVIDERS[provider] === true;
1576
+ }
1577
+
1578
+ // The provider's own account id as "oauth:<provider>:<id>": a namespace no
1579
+ // local account id can share (a provider's integer ids would otherwise match
1580
+ // local integer ids on owner rules). Where no id can collide, the raw id stays.
1581
+ function namespaceOAuthId(token, account) {
1582
+ if (!OAUTH_IDS_NAMESPACED) {
1583
+ return;
1584
+ }
1585
+ var accountId = String((account && account.providerAccountId) || token.sub || token.id || '');
1586
+ var id = 'oauth:' + String((account && account.provider) || 'provider') + ':' + accountId;
1587
+ token.id = id;
1588
+ token.sub = id;
1589
+ }
1590
+
1591
+ // Not vouched for: the visitor keeps a session under an id no local account can
1592
+ // have (namespaced where one could), with no email to be matched by and no role.
1593
+ function asDistinctOAuthIdentity(token, account) {
1594
+ namespaceOAuthId(token, account);
1595
+ delete token.email;
1596
+ delete token.role;
1597
+ delete token.roleName;
1598
+ delete token.roles;
1599
+ token[OAUTH_UNVERIFIED] = true;
1600
+ }`;
1601
+ };
814
1602
  /**
815
1603
  * Why a sign-in failed, in words, plus the one-line codes `authorize` throws.
816
1604
  *
@@ -831,6 +1619,7 @@ const AUTH_ERROR_MESSAGES = {
831
1619
  InvalidCredentials: 'That email and password do not match an account.',
832
1620
  ServiceUnavailable:
833
1621
  '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.',
1622
+ TooManyAttempts: 'Too many sign-in attempts. Please wait a few minutes and try again.',
834
1623
 
835
1624
  // NextAuth's own.
836
1625
  CredentialsSignin: 'That email and password do not match an account.',
@@ -928,36 +1717,155 @@ module.exports = {
928
1717
  };
929
1718
  `;
930
1719
  };
1720
+ /** The password a site accepts when one is set (sign-up, reset, a change). */
1721
+ export const MIN_PASSWORD_LENGTH = 8;
1722
+ export const MAX_PASSWORD_BYTES = 128;
931
1723
  export const generateHashPasswordFile = () => {
932
1724
  return `const bcrypt = require('bcryptjs');
933
1725
  const crypto = require('crypto');
934
1726
 
935
- const PEPPER = process.env.AUTH_PEPPER || '';
936
1727
  const COST_FACTOR = 12;
1728
+ const MIN_PASSWORD_LENGTH = ${MIN_PASSWORD_LENGTH};
1729
+ const MAX_PASSWORD_BYTES = ${MAX_PASSWORD_BYTES};
1730
+
1731
+ // Two peppers. AUTH_PEPPER_SECRET is the project's own random secret, which the
1732
+ // deploy step provisions; every new hash uses it. AUTH_PEPPER (the project id,
1733
+ // no secret) is the one every hash was made with before it existed: such a hash
1734
+ // still verifies, and the sign-in replaces it. Without the secret, hashing and
1735
+ // verifying stay on the old pepper — never on none.
1736
+ function pepperSecret() {
1737
+ var value = process.env.AUTH_PEPPER_SECRET;
1738
+ return typeof value === 'string' && value && value.indexOf('teleporthq.secrets.') !== 0 ? value : '';
1739
+ }
1740
+
1741
+ function legacyPepper() {
1742
+ return process.env.AUTH_PEPPER || '';
1743
+ }
937
1744
 
938
- function prepare(password) {
1745
+ // SHA-256 first, so bcrypt (which reads at most 72 bytes) sees all of it.
1746
+ function prepare(password, pepper) {
939
1747
  const str = String(password);
940
1748
  if (str.length > 1000) {
941
1749
  throw new Error('Password exceeds maximum length');
942
1750
  }
943
- const sha = crypto.createHash('sha256').update(str + PEPPER).digest('base64');
944
- return sha;
1751
+ return crypto.createHash('sha256').update(str + pepper).digest('base64');
945
1752
  }
946
1753
 
947
1754
  function hashPassword(password) {
948
- return bcrypt.hashSync(prepare(password), COST_FACTOR);
1755
+ return bcrypt.hashSync(prepare(password, pepperSecret() || legacyPepper()), COST_FACTOR);
1756
+ }
1757
+
1758
+ // A hash no password matches, made once per process with the project pepper
1759
+ // at the same cost. An address without an account, or a row without a
1760
+ // password (a subscriber, a guest), is checked against it, so every failed
1761
+ // sign-in does the bcrypt work a wrong password does: the time never tells
1762
+ // them apart.
1763
+ var __standInHash = null;
1764
+ function standInHash() {
1765
+ if (!__standInHash) {
1766
+ __standInHash = bcrypt.hashSync(prepare(crypto.randomBytes(32).toString('hex'), pepperSecret() || legacyPepper()), COST_FACTOR);
1767
+ }
1768
+ return __standInHash;
1769
+ }
1770
+
1771
+ // { ok, needsRehash }: ok when the password matches; needsRehash when it
1772
+ // matched through the old pepper while the project has its own.
1773
+ function checkPassword(password, hash) {
1774
+ var known = typeof hash === 'string' && hash !== '';
1775
+ var against = known ? hash : standInHash();
1776
+ var secret = pepperSecret();
1777
+ if (secret && bcrypt.compareSync(prepare(password, secret), against) && known) {
1778
+ return { ok: true, needsRehash: false };
1779
+ }
1780
+ // Run on every miss, whatever the hash was.
1781
+ if (bcrypt.compareSync(prepare(password, legacyPepper()), against) && known) {
1782
+ return { ok: true, needsRehash: !!secret };
1783
+ }
1784
+ return { ok: false, needsRehash: false };
949
1785
  }
950
1786
 
951
1787
  function verifyPassword(password, hash) {
952
- return bcrypt.compareSync(prepare(password), hash);
1788
+ return checkPassword(password, hash).ok;
1789
+ }
1790
+
1791
+ // Why a password may not be set, or '' when it may.
1792
+ function passwordPolicyError(password) {
1793
+ if (typeof password !== 'string' || password.length < MIN_PASSWORD_LENGTH) {
1794
+ return 'Password must be at least ' + MIN_PASSWORD_LENGTH + ' characters';
1795
+ }
1796
+ if (Buffer.byteLength(password, 'utf8') > MAX_PASSWORD_BYTES) {
1797
+ return 'Password is too long (at most ' + MAX_PASSWORD_BYTES + ' bytes)';
1798
+ }
1799
+ return '';
953
1800
  }
954
1801
 
955
1802
  module.exports = hashPassword;
956
1803
  module.exports.hashPassword = hashPassword;
957
1804
  module.exports.verifyPassword = verifyPassword;
1805
+ module.exports.checkPassword = checkPassword;
1806
+ module.exports.passwordPolicyError = passwordPolicyError;
958
1807
  `;
959
1808
  };
960
- export const generateNextAuthRouteFile = () => {
1809
+ // Answered to a credentials sign-in the throttle refuses, in the shape
1810
+ // next-auth/react's signIn() reads (it parses \`url\` for the error code, which
1811
+ // describeAuthError turns into copy).
1812
+ const SIGN_IN_THROTTLE_CODE = `var __security = require('${securityRuntimeSpecifier('../../..')}');
1813
+
1814
+ function isCredentialsSignIn(req) {
1815
+ var parts = req && req.query ? req.query.nextauth : null;
1816
+ return (
1817
+ req && req.method === 'POST' && Array.isArray(parts) && parts[0] === 'callback' && parts[1] === 'credentials'
1818
+ );
1819
+ }
1820
+
1821
+ function refuseSignIn(res, status, code, message, retryAfter) {
1822
+ var origin = process.env.NEXTAUTH_URL || 'http://localhost:3000';
1823
+ var url;
1824
+ try {
1825
+ url = new URL('/api/auth/error?error=' + code, origin).toString();
1826
+ } catch (e) {
1827
+ url = 'http://localhost:3000/api/auth/error?error=' + code;
1828
+ }
1829
+ if (retryAfter) {
1830
+ res.setHeader('Retry-After', String(retryAfter));
1831
+ }
1832
+ res.status(status).json({ url: url, error: message });
1833
+ }
1834
+
1835
+ // Too many failed (or attempted) sign-ins for this email from this visitor:
1836
+ // refused before the password is even looked at.
1837
+ async function throttleCredentialsSignIn(req, res) {
1838
+ if (req && req.headers) {
1839
+ delete req.headers[authOptions.SIGN_IN_VISITOR_HEADER];
1840
+ }
1841
+ if (!isCredentialsSignIn(req)) {
1842
+ return false;
1843
+ }
1844
+ req.headers[authOptions.SIGN_IN_VISITOR_HEADER] = __security.clientIp(req);
1845
+ var verdict;
1846
+ try {
1847
+ verdict = await authOptions.checkSignInAllowed(req);
1848
+ } catch (err) {
1849
+ console.error('[auth] The sign-in throttle failed:', err && err.message ? err.message : err);
1850
+ refuseSignIn(res, 503, 'ServiceUnavailable', 'Sign-in is unavailable right now. Please try again in a moment.', 0);
1851
+ return true;
1852
+ }
1853
+ if (verdict && verdict.allowed) {
1854
+ return false;
1855
+ }
1856
+ refuseSignIn(
1857
+ res,
1858
+ 429,
1859
+ 'TooManyAttempts',
1860
+ 'Too many sign-in attempts. Try again later.',
1861
+ verdict && verdict.retryAfter ? verdict.retryAfter : ${SIGN_IN_WINDOW_SECONDS}
1862
+ );
1863
+ return true;
1864
+ }
1865
+
1866
+ `;
1867
+ export const generateNextAuthRouteFile = (options = {}) => {
1868
+ const throttled = options.passwordAuthEnabled === true;
961
1869
  return `let NextAuth = require('next-auth');
962
1870
  if (NextAuth.default) NextAuth = NextAuth.default;
963
1871
  const authOptions = require('../../../utils/auth/auth-options');
@@ -1052,45 +1960,287 @@ function resolveRequestOrigin(req) {
1052
1960
  return proto + '://' + host;
1053
1961
  }
1054
1962
 
1055
- module.exports = function nextAuthRoute(req, res) {
1963
+ ${throttled ? SIGN_IN_THROTTLE_CODE : ''}module.exports = ${throttled ? 'async ' : ''}function nextAuthRoute(req, res) {
1056
1964
  try {
1057
1965
  process.env.NEXTAUTH_URL = resolveRequestOrigin(req);
1058
1966
  } catch (e) {
1059
1967
  /* fall back to whatever NEXTAUTH_URL holds */
1060
1968
  }
1061
- return authHandler(req, res);
1969
+ ${throttled
1970
+ ? ` if (await throttleCredentialsSignIn(req, res)) {
1971
+ return;
1972
+ }
1973
+ `
1974
+ : ''} return authHandler(req, res);
1975
+ };
1976
+ `;
1062
1977
  };
1978
+ /**
1979
+ * `recordAccountEvent(type, user, source, req)`, for the account routes of a
1980
+ * project with automations: records `user-signed-up` / `user-deleted` on the
1981
+ * in-app event bus, which writes the `teleport_events` row and wakes the
1982
+ * automations off the request path, on the app's own origin as `req` reached
1983
+ * it. Only the profile fields go into the event, never a credential. It never
1984
+ * throws, so the event cannot fail the request it records. `relativePrefix`
1985
+ * leads from the route to the project root.
1986
+ */
1987
+ export const generateAccountEventRecorder = (options) => `
1988
+ // The project has automations: the account event wakes them. Best effort,
1989
+ // like the emails: recording it can never fail the request.
1990
+ function accountEventTime(value) {
1991
+ var date = value ? new Date(value) : new Date();
1992
+ return isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString();
1993
+ }
1994
+
1995
+ async function recordAccountEvent(type, user, source, req) {
1996
+ try {
1997
+ var userId = user ? user.id || user._id : null;
1998
+ if (!userId) { return; }
1999
+ var id = String(userId);
2000
+ var email = user.email ? String(user.email) : '';
2001
+ var bus = require('${options.relativePrefix}/${AUTOMATIONS_PATH.join('/')}/event-bus');
2002
+ await bus.emitBusinessEvent({
2003
+ type: type,
2004
+ entityType: 'user',
2005
+ entityId: id,
2006
+ payload: {
2007
+ user: {
2008
+ id: id,
2009
+ email: email || null,
2010
+ name: user.name || null,
2011
+ role: user.role || null,
2012
+ source: source || user.source || null,
2013
+ createdAt: accountEventTime(user.created_at || user.createdAt),
2014
+ },
2015
+ },
2016
+ actor: email,
2017
+ actorType: 'customer',
2018
+ dedupeKey: type + ':' + id,
2019
+ }, req);
2020
+ } catch (eventErr) {
2021
+ var reason = eventErr && eventErr.message ? eventErr.message : eventErr;
2022
+ console.error('${options.logTag} could not record the ' + type + ' event:', reason);
2023
+ }
2024
+ }
1063
2025
  `;
2026
+ /**
2027
+ * A user column that grants something — a role, an admin or staff flag, a
2028
+ * verified email, credit, a plan or an entitlement — in any spelling
2029
+ * (`is_admin`, `isAdmin`, `Email-Verified`). Only the server sets these; a
2030
+ * sign-up never takes them from the visitor. The one shared rule
2031
+ * (`AccountFields.isPrivilegedAccountField`).
2032
+ */
2033
+ export const isPrivilegedUserField = (key) => AccountFields.isPrivilegedAccountField(key);
2034
+ /** Config keys of an `account-signup` node that are not user fields. */
2035
+ const SIGNUP_NODE_NON_FIELD_KEYS = new Set([
2036
+ 'email',
2037
+ 'password',
2038
+ 'name',
2039
+ 'image',
2040
+ 'role',
2041
+ ...WELCOME_EMAIL_CONFIG_KEYS,
2042
+ ]);
2043
+ /**
2044
+ * The fields a sign-up may write besides email, password and name: the avatar
2045
+ * (`image`) and each declared custom account property that a sign-up form of
2046
+ * the project collects (a key of an `account-signup` node), never a
2047
+ * privileged one.
2048
+ */
2049
+ export const resolveSignupFields = (auth, signupNodeConfigs) => {
2050
+ const declared = new Set((auth.customUserProperties || []).map((prop) => prop.key));
2051
+ const collected = new Set();
2052
+ for (const config of signupNodeConfigs) {
2053
+ for (const key of Object.keys(config || {})) {
2054
+ if (!SIGNUP_NODE_NON_FIELD_KEYS.has(key) &&
2055
+ declared.has(key) &&
2056
+ !isPrivilegedUserField(key)) {
2057
+ collected.add(key);
2058
+ }
2059
+ }
2060
+ }
2061
+ return ['image', ...Array.from(collected).sort()];
1064
2062
  };
1065
- export const generateSignupRouteFile = (auth, welcome = {}) => {
2063
+ /**
2064
+ * After a new account with a ticked consent box: the newsletter helper adds it
2065
+ * (double opt-in, the `newsletter-subscribed` event, the newsletter's welcome
2066
+ * unless the account's own went out). Best effort, like the welcome email.
2067
+ */
2068
+ const SIGNUP_NEWSLETTER_CODE = ` // The ticked box also subscribes the person to the newsletter.
2069
+ if (userData.marketing_consent) {
2070
+ try {
2071
+ const __newsletter = require('../../../utils/newsletter/newsletter');
2072
+ await __newsletter.withNewsletterDb(function (db) {
2073
+ return __newsletter.subscribeNewsletterPerson({ db: db, email: email, signUpPoint: 'signup', req: req });
2074
+ });
2075
+ } catch (newsletterErr) {
2076
+ console.error('[account-signup] newsletter sign-up failed:', newsletterErr && newsletterErr.message ? newsletterErr.message : newsletterErr);
2077
+ }
2078
+ }
2079
+ `;
2080
+ /**
2081
+ * The answer to a sign-up for an address the site already knows (an account,
2082
+ * or a row without a password) takes at least this long, as the
2083
+ * forgot-password answer does: the two are answered alike, and the time must
2084
+ * not tell them apart either.
2085
+ */
2086
+ export const KNOWN_ADDRESS_MIN_RESPONSE_MS = 1200;
2087
+ /**
2088
+ * The sign-up route's emails to an address the site already knows, sent
2089
+ * through `sender` (the sign-up node's, else the forgot-password node's):
2090
+ * `sendAccountNotice(emailType, msg, logged)`, which sends and records the
2091
+ * email under its own purpose (with what the log may keep), and
2092
+ * `sendSetPasswordEmail(user, siteName, req)`, the link for an address without
2093
+ * a password, built on the forgot-password token flow (a CSPRNG token whose
2094
+ * SHA-256 alone is stored against the account, the same lifetime, origin rule
2095
+ * and reset page).
2096
+ */
2097
+ const generateKnownAddressEmailCode = (options) => {
2098
+ const { sender } = options;
2099
+ const senderConstants = `
2100
+ // Who sends the emails to an address the site already knows: the sign-up
2101
+ // node's email settings, else the forgot-password node's.
2102
+ const NOTICE_EMAIL_PROVIDER = ${JSON.stringify(sender.provider)};
2103
+ const NOTICE_EMAIL_FROM = ${JSON.stringify(sender.from)};
2104
+ const NOTICE_EMAIL_SECRET_ENV_NAME = ${JSON.stringify(sender.secretEnv)};`;
2105
+ if (!sender.provider) {
2106
+ return `${senderConstants}
2107
+
2108
+ // No email provider: nothing is sent to an address the site already knows.
2109
+ async function sendAccountNotice() {}
2110
+
2111
+ // A sign-up for an address the site knows without a password mails its owner
2112
+ // a link to set one; this project has no email provider, so none is sent.
2113
+ async function sendSetPasswordEmail() {
2114
+ console.warn('[account-signup] set-password link not sent: no email provider is configured');
2115
+ }`;
2116
+ }
2117
+ const ttlMinutes = Math.round(PASSWORD_RESET_TOKEN_TTL_SECONDS / 60);
2118
+ // Where the link carries the token, as the forgot-password link does.
2119
+ const tokenLinkPrefix = options.tokenInFragment ? '#token=' : '?token=';
2120
+ const noticeSend = generateProviderSendFunction(sender.provider).replace('async function __sendProviderEmail(', 'async function __sendNoticeEmail(');
2121
+ return `${senderConstants}
2122
+
2123
+ ${noticeSend}
2124
+
2125
+ var __noticeEmailLog = require('../../../utils/email/sent-email-log');
2126
+
2127
+ // Sends one of these emails and records it under its own purpose, with what
2128
+ // the log may keep of it (\`logged\`: a link's token hidden).
2129
+ async function sendAccountNotice(emailType, msg, logged) {
2130
+ var failure = null;
2131
+ try {
2132
+ await __sendNoticeEmail(msg);
2133
+ } catch (err) {
2134
+ failure = err;
2135
+ }
2136
+ __noticeEmailLog.recordSentEmail({
2137
+ emailType: emailType,
2138
+ audience: 'customer',
2139
+ to: msg.to,
2140
+ from: msg.from,
2141
+ subject: logged.subject,
2142
+ html: logged.html,
2143
+ payload: logged.payload,
2144
+ provider: NOTICE_EMAIL_PROVIDER,
2145
+ status: failure ? 'failed' : 'sent',
2146
+ error: failure ? (failure.message || String(failure)) : null,
2147
+ source: 'signup',
2148
+ sourceRef: 'api/auth/signup',
2149
+ userId: msg.userId,
2150
+ });
2151
+ if (failure) { throw failure; }
2152
+ }
2153
+
2154
+ // A sign-up for an address the site knows without a password (a newsletter
2155
+ // subscriber, a checkout or booking guest, a contact the owner added) never
2156
+ // takes that row: whoever typed the address may not own it. Its owner is mailed
2157
+ // a link to set a password instead, a password-reset link minted and stored as
2158
+ // the forgot-password route mints it, at most ${EXISTING_ACCOUNT_EMAIL_LIMIT} an hour per address
2159
+ // (counted with the "already have an account" email).
2160
+ var SET_PASSWORD_SUBJECT = 'Set your password to finish creating your account';
2161
+ var SET_PASSWORD_BODY_HTML =
2162
+ '<p>Someone, hopefully you, tried to create an account{{siteNameSuffix}} with this email address.</p>' +
2163
+ '<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>' +
2164
+ '<p><a href="{{resetUrl}}">Set your password</a></p>' +
2165
+ '<p>The link works for ${ttlMinutes} minutes. If this was not you, you can ignore this email: nothing has changed.</p>';
2166
+ var SET_PASSWORD_PAGE_PATH = ${JSON.stringify(options.pagePath)};
2167
+ var SET_PASSWORD_TOKEN_LINK_PREFIX = ${JSON.stringify(tokenLinkPrefix)};
2168
+ var SET_PASSWORD_TOKEN_TTL_SECONDS = ${PASSWORD_RESET_TOKEN_TTL_SECONDS};
2169
+
2170
+ ${TRUSTED_ORIGIN_CODE}
2171
+
2172
+ // The token, wherever it appears, for what the sent-email log keeps: whoever
2173
+ // can read the log must not be able to set the password with it.
2174
+ function hideToken(text, token) {
2175
+ return String(text == null ? '' : text).split(token).join('[hidden]');
2176
+ }
2177
+
2178
+ async function sendSetPasswordEmail(user, siteName, req) {
2179
+ var toEmail = String(user.email || '');
2180
+ var userId = user.id != null ? user.id : user._id;
2181
+ var apiKey = NOTICE_EMAIL_SECRET_ENV_NAME ? process.env[NOTICE_EMAIL_SECRET_ENV_NAME] : '';
2182
+ if (apiKey && String(apiKey).indexOf('teleporthq.secrets.') === 0) { apiKey = ''; }
2183
+ var from = NOTICE_EMAIL_FROM || process.env.EMAIL_FROM || '';
2184
+ if (!apiKey || !from) { console.warn('[account-signup] set-password link not sent: the email credential or sender is not set'); return; }
2185
+ if (!toEmail || userId == null) { return; }
2186
+ var allowed = await __security.rateLimit({
2187
+ key: 'auth-signup-existing:' + toEmail.trim().toLowerCase(),
2188
+ limit: ${EXISTING_ACCOUNT_EMAIL_LIMIT},
2189
+ windowSeconds: 3600,
2190
+ });
2191
+ if (!allowed.allowed) { return; }
2192
+ var crypto = require('crypto');
2193
+ var token = crypto.randomBytes(32).toString('hex');
2194
+ await authUtils.storePasswordReset(userId, crypto.createHash('sha256').update(token).digest('hex'), SET_PASSWORD_TOKEN_TTL_SECONDS);
2195
+ var resetUrl = trustedOrigin(req) + SET_PASSWORD_PAGE_PATH + SET_PASSWORD_TOKEN_LINK_PREFIX + token;
2196
+ var html = fillTemplate(SET_PASSWORD_BODY_HTML, { siteNameSuffix: siteName ? ' on ' + siteName : '', resetUrl: resetUrl });
2197
+ await sendAccountNotice(
2198
+ ${JSON.stringify(SET_PASSWORD_EMAIL)},
2199
+ { from: from, to: toEmail, subject: SET_PASSWORD_SUBJECT, html: html, apiKey: apiKey, userId: userId },
2200
+ {
2201
+ subject: SET_PASSWORD_SUBJECT,
2202
+ html: hideToken(html, token),
2203
+ payload: { resetUrl: hideToken(resetUrl, token), recipientEmail: toEmail },
2204
+ }
2205
+ );
2206
+ }`;
2207
+ };
2208
+ export const generateSignupRouteFile = (auth, welcome = {}, events = {}, signup = {}) => {
1066
2209
  const needsDb = !!auth.dataSourceType;
2210
+ const recordsSignup = needsDb && events.withAutomations === true;
1067
2211
  const welcomeProvider = welcome.emailProvider && SUPPORTED_EMAIL_PROVIDERS.has(welcome.emailProvider)
1068
2212
  ? welcome.emailProvider
1069
2213
  : null;
1070
- // Reserved keys that must NOT be copied from the request body onto the new
1071
- // user row — the auth fields plus every welcome-email config key (a stale
1072
- // client could otherwise inject them as bogus user columns).
1073
- const reservedKeysObj = { email: 1, password: 1, name: 1, role: 1 };
1074
- for (const key of WELCOME_EMAIL_CONFIG_KEYS) {
1075
- reservedKeysObj[key] = 1;
1076
- }
1077
- // A custom account property the session reads a role from (`roles`,
1078
- // `roleName`, or `role` in another case, which Postgres folds onto the same
1079
- // column) is set by the server alone — a signup body naming it would pick
1080
- // its own role.
1081
- for (const prop of auth.customUserProperties || []) {
1082
- if (ROLE_BEARING_USER_KEY.test(prop.key)) {
1083
- reservedKeysObj[prop.key] = 1;
2214
+ // An ALLOW-list: the only body keys copied onto the new user row. Whatever
2215
+ // else the body carries (a role, `is_admin`, `email_verified`, credits, a
2216
+ // plan, a welcome-email config key) never reaches createUser. The columns
2217
+ // the route sets itself (source, consent) are never copied from it either.
2218
+ const signupFields = (signup.fields || ['image']).filter((field) => field && !isPrivilegedUserField(field) && SIGNUP_OWN_COLUMNS.indexOf(field) === -1);
2219
+ const setPasswordPagePath = resolveResetPagePath(signup.resetPagePath);
2220
+ // The emails to an address the site already knows go through the sign-up
2221
+ // node's sender, else the forgot-password node's.
2222
+ const fallbackSender = signup.noticeEmail || {};
2223
+ const noticeSender = welcomeProvider
2224
+ ? {
2225
+ provider: welcomeProvider,
2226
+ from: welcome.fromEmail || '',
2227
+ secretEnv: welcome.emailSecretEnvName || '',
1084
2228
  }
1085
- }
2229
+ : {
2230
+ provider: fallbackSender.emailProvider &&
2231
+ SUPPORTED_EMAIL_PROVIDERS.has(fallbackSender.emailProvider)
2232
+ ? fallbackSender.emailProvider
2233
+ : null,
2234
+ from: fallbackSender.fromEmail || '',
2235
+ secretEnv: fallbackSender.emailSecretEnvName || '',
2236
+ };
1086
2237
  let dbImport = '';
1087
2238
  let createUserCall = '';
1088
2239
  let welcomeHelpers = '';
1089
2240
  if (needsDb) {
1090
2241
  dbImport = `const authUtils = require('../../../utils/auth/auth-options');
1091
2242
  const createUser = authUtils.createUser;
1092
- const userExistsByEmail = authUtils.userExistsByEmail;
1093
- const sanitizeUser = authUtils.sanitizeUser;`;
2243
+ const findSignupUserByEmail = authUtils.findSignupUserByEmail;`;
1094
2244
  // Baked welcome-email helpers + config (no-op send when no provider set).
1095
2245
  welcomeHelpers = `
1096
2246
  const WELCOME_EMAIL_PROVIDER = ${JSON.stringify(welcomeProvider)};
@@ -1129,18 +2279,90 @@ async function sendWelcomeEmail(toEmail, tokenValues, userId, locale) {
1129
2279
  var from = WELCOME_EMAIL_FROM || process.env.EMAIL_FROM || '';
1130
2280
  if (!from) { console.warn('[account-signup] welcome email skipped: sender not configured'); return; }
1131
2281
  var copy = resolveWelcomeEmailCopy(locale);
1132
- var subject = fillTemplate(copy.subject, tokenValues);
2282
+ var subject = fillSubjectTemplate(copy.subject, tokenValues);
1133
2283
  var html = fillTemplate(copy.body, tokenValues);
1134
2284
  await __sendProviderEmail({ from: from, fromName: WELCOME_EMAIL_FROM_NAME, to: toEmail, subject: subject, html: html, apiKey: apiKey, tokenValues: tokenValues, userId: userId });
1135
2285
  }
1136
- `;
1137
- createUserCall = ` const exists = await userExistsByEmail(email);
1138
- if (exists) {
1139
- // A newsletter subscriber or a contact the owner added has a row but no
1140
- // password. Signing up must not hand that row — and what the site knows
1141
- // about the person — to whoever types the address first; the password
1142
- // reset proves the mailbox is theirs.
1143
- res.status(409).json({ error: 'An account with this email already exists. Sign in, or use "Forgot password" to set a password.' });
2286
+
2287
+ // A sign-up for an address that already has an account gets the same status,
2288
+ // body and headers as a new one; its time differs from a new address's, which
2289
+ // the account a new sign-up makes reveals anyway. The address's owner is told
2290
+ // by email instead (only the mailbox owner reads it), at most
2291
+ // ${EXISTING_ACCOUNT_EMAIL_LIMIT} times an hour per address, through the known-address sender.
2292
+ var EXISTING_ACCOUNT_SUBJECT = 'You already have an account';
2293
+ var EXISTING_ACCOUNT_BODY_HTML =
2294
+ '<p>Someone, hopefully you, tried to create an account{{siteNameSuffix}} with this email address.</p>' +
2295
+ '<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>' +
2296
+ '<p>If this was not you, you can ignore this email: nothing has changed.</p>';
2297
+
2298
+ async function sendExistingAccountEmail(toEmail, siteName, userId) {
2299
+ if (!NOTICE_EMAIL_PROVIDER || !toEmail) { return; }
2300
+ var apiKey = NOTICE_EMAIL_SECRET_ENV_NAME ? process.env[NOTICE_EMAIL_SECRET_ENV_NAME] : '';
2301
+ if (apiKey && String(apiKey).indexOf('teleporthq.secrets.') === 0) { apiKey = ''; }
2302
+ var from = NOTICE_EMAIL_FROM || process.env.EMAIL_FROM || '';
2303
+ if (!apiKey || !from) { return; }
2304
+ var allowed = await __security.rateLimit({
2305
+ key: 'auth-signup-existing:' + String(toEmail).trim().toLowerCase(),
2306
+ limit: ${EXISTING_ACCOUNT_EMAIL_LIMIT},
2307
+ windowSeconds: 3600,
2308
+ });
2309
+ if (!allowed.allowed) { return; }
2310
+ var tokenValues = { siteNameSuffix: siteName ? ' on ' + siteName : '' };
2311
+ var html = fillTemplate(EXISTING_ACCOUNT_BODY_HTML, tokenValues);
2312
+ await sendAccountNotice(
2313
+ ${JSON.stringify(EXISTING_ACCOUNT_EMAIL)},
2314
+ { from: from, to: toEmail, subject: EXISTING_ACCOUNT_SUBJECT, html: html, apiKey: apiKey, userId: userId },
2315
+ { subject: EXISTING_ACCOUNT_SUBJECT, html: html, payload: tokenValues }
2316
+ );
2317
+ }
2318
+ ${generateKnownAddressEmailCode({
2319
+ sender: noticeSender,
2320
+ pagePath: setPasswordPagePath,
2321
+ tokenInFragment: signup.tokenInFragment === true,
2322
+ })}
2323
+
2324
+ function waitUntilElapsed(startedAt, ms) {
2325
+ var left = ms - (Date.now() - startedAt);
2326
+ return left > 0 ? new Promise(function (resolve) { setTimeout(resolve, left); }) : Promise.resolve();
2327
+ }
2328
+ ${recordsSignup
2329
+ ? generateAccountEventRecorder({ relativePrefix: '../../..', logTag: '[account-signup]' })
2330
+ : ''}`;
2331
+ createUserCall = ` // The answer is the same for a new account and for an address that already
2332
+ // has one (see sendExistingAccountEmail): built from what the visitor sent.
2333
+ const answer = { user: { email: email, name: name || null } };
2334
+ const __siteName = WELCOME_EMAIL_SITE_NAME ||
2335
+ (req.headers && req.headers.host ? String(req.headers.host).replace(/^www\\./, '').split(':')[0] : '');
2336
+ // In any letter case: \`Ava@site.test\` is the \`ava@site.test\` row.
2337
+ const existing = await findSignupUserByEmail(email);
2338
+ if (existing) {
2339
+ // A newsletter subscriber, a checkout or booking guest or a contact the
2340
+ // owner added has a row but no password (and no OAuth sign-in). Signing
2341
+ // up must not hand that row — and what the site knows about the person —
2342
+ // to whoever types the address first: its owner is mailed a link to set
2343
+ // a password, which proves the mailbox is theirs. An account's owner is
2344
+ // told it already has one. Either way the page is answered alike, so it
2345
+ // never tells a subscriber or a guest from an account.
2346
+ const knownEmail = String(existing.email || email);
2347
+ const existingId = existing.id != null ? existing.id : existing._id;
2348
+ try {
2349
+ if (!existing.password && !existing.provider && authUtils.PASSWORD_RESET_SUPPORTED) {
2350
+ await sendSetPasswordEmail(existing, __siteName, req);
2351
+ } else {
2352
+ // An account; or a row without a password where the store cannot
2353
+ // keep reset links (not Postgres): told it is already known here.
2354
+ await sendExistingAccountEmail(knownEmail, __siteName, existingId);
2355
+ }
2356
+ } catch (existingErr) {
2357
+ console.error('[account-signup] existing-account email failed:', existingErr && existingErr.message ? existingErr.message : existingErr);
2358
+ }
2359
+ ${noticeSender.provider
2360
+ ? ` await __noticeEmailLog.settleSentEmailLog();
2361
+ `
2362
+ : ''} // At least ${KNOWN_ADDRESS_MIN_RESPONSE_MS} ms, like the forgot-password answer: the time tells
2363
+ // neither which email went out nor whether one did.
2364
+ await waitUntilElapsed(startedAt, ${KNOWN_ADDRESS_MIN_RESPONSE_MS});
2365
+ res.status(201).json(answer);
1144
2366
  return;
1145
2367
  }
1146
2368
 
@@ -1149,12 +2371,16 @@ async function sendWelcomeEmail(toEmail, tokenValues, userId, locale) {
1149
2371
  email: email,
1150
2372
  password: hashedPassword,
1151
2373
  role: 'user',
2374
+ // Where the person came from, and their consent as they gave it: the
2375
+ // "Email me news and offers" box ticked ('true') or not. Never assumed.
2376
+ source: 'signup',
2377
+ marketing_consent: body.marketing_consent === 'true',
1152
2378
  };
1153
- const reservedKeys = ${JSON.stringify(reservedKeysObj)};
1154
- const bodyKeys = Object.keys(body);
1155
- for (let i = 0; i < bodyKeys.length; i++) {
1156
- if (!reservedKeys[bodyKeys[i]]) {
1157
- userData[bodyKeys[i]] = body[bodyKeys[i]];
2379
+ // Only the fields this project's sign-up forms collect.
2380
+ const signupFields = ${JSON.stringify(signupFields)};
2381
+ for (let i = 0; i < signupFields.length; i++) {
2382
+ if (Object.prototype.hasOwnProperty.call(body, signupFields[i])) {
2383
+ userData[signupFields[i]] = body[signupFields[i]];
1158
2384
  }
1159
2385
  }
1160
2386
 
@@ -1167,12 +2393,10 @@ async function sendWelcomeEmail(toEmail, tokenValues, userId, locale) {
1167
2393
 
1168
2394
  // Best-effort welcome email — a failed send must never fail the signup.
1169
2395
  try {
1170
- const __welcomeSiteName = WELCOME_EMAIL_SITE_NAME ||
1171
- (req.headers && req.headers.host ? String(req.headers.host).replace(/^www\\./, '').split(':')[0] : '');
1172
2396
  await sendWelcomeEmail(email, {
1173
2397
  userName: name || (newUser && newUser.name) || 'there',
1174
2398
  userEmail: email,
1175
- siteName: __welcomeSiteName,
2399
+ siteName: __siteName,
1176
2400
  }, newUser && newUser.id, __emailLocale.resolveRequestLocale(req));
1177
2401
  } catch (welcomeErr) {
1178
2402
  console.error('[account-signup] welcome email failed:', welcomeErr && welcomeErr.message ? welcomeErr.message : welcomeErr);
@@ -1181,13 +2405,18 @@ ${welcomeProvider
1181
2405
  ? ` // Land the welcome email's ledger row before replying.
1182
2406
  if (typeof __sentEmailLog !== 'undefined') { await __sentEmailLog.settleSentEmailLog(); }
1183
2407
  `
1184
- : ''}
1185
- res.status(201).json({ user: sanitizeUser(newUser) });`;
2408
+ : ''}${recordsSignup
2409
+ ? ` // The account exists: the last thing the signup does is record it.
2410
+ await recordAccountEvent('user-signed-up', newUser, 'signup', req);
2411
+ `
2412
+ : ''}${signup.newsletter === true ? SIGNUP_NEWSLETTER_CODE : ''}
2413
+ res.status(201).json(answer);`;
1186
2414
  }
1187
2415
  else {
1188
2416
  createUserCall = ` res.status(501).json({ error: 'No data source configured for user storage' });`;
1189
2417
  }
1190
2418
  return `const hashPassword = require('../../../utils/auth/hash-password');
2419
+ const __security = require('${securityRuntimeSpecifier('../../..')}');
1191
2420
  ${dbImport}
1192
2421
  ${welcomeHelpers}
1193
2422
 
@@ -1197,11 +2426,16 @@ module.exports = async function handler(req, res) {
1197
2426
  return;
1198
2427
  }
1199
2428
 
2429
+ // ${SIGN_UP_LIMIT} sign-ups per visitor per hour.
2430
+ if (!(await __security.rateLimitRequest(req, res, { scope: 'auth-signup', limit: ${SIGN_UP_LIMIT}, windowSeconds: ${SIGN_UP_WINDOW_SECONDS} }))) {
2431
+ return;
2432
+ }
2433
+ ${needsDb ? ' const startedAt = Date.now();\n' : ''}
1200
2434
  try {
1201
- const body = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;
1202
- const email = body.email;
1203
- const password = body.password;
1204
- const name = body.name;
2435
+ const body = (typeof req.body === 'string' ? JSON.parse(req.body) : req.body) || {};
2436
+ const email = typeof body.email === 'string' ? body.email : '';
2437
+ const password = typeof body.password === 'string' ? body.password : '';
2438
+ const name = typeof body.name === 'string' ? body.name : '';
1205
2439
 
1206
2440
  if (!email || !password) {
1207
2441
  res.status(400).json({ error: 'Email and password are required' });
@@ -1214,13 +2448,9 @@ module.exports = async function handler(req, res) {
1214
2448
  return;
1215
2449
  }
1216
2450
 
1217
- if (password.length < 6) {
1218
- res.status(400).json({ error: 'Password must be at least 6 characters' });
1219
- return;
1220
- }
1221
-
1222
- if (password.length > 128) {
1223
- res.status(400).json({ error: 'Password must not exceed 128 characters' });
2451
+ const policyError = hashPassword.passwordPolicyError(password);
2452
+ if (policyError) {
2453
+ res.status(400).json({ error: policyError });
1224
2454
  return;
1225
2455
  }
1226
2456
 
@@ -1228,8 +2458,7 @@ module.exports = async function handler(req, res) {
1228
2458
 
1229
2459
  ${createUserCall}
1230
2460
  } catch (error) {
1231
- console.error('Signup error:', error);
1232
- res.status(500).json({ error: 'Internal server error' });
2461
+ __security.sendClientError(res, 500, 'Sign-up failed. Please try again.', error);
1233
2462
  }
1234
2463
  };
1235
2464
  `;
@@ -1480,40 +2709,19 @@ function getUserRoleFromToken(token) {
1480
2709
  return null;
1481
2710
  }
1482
2711
 
1483
- // Reads a single cookie value, tolerating both the Next 12 string shape and the
1484
- // newer { name, value } object shape returned by request.cookies.get().
1485
- function readCookie(request, name) {
1486
- try {
1487
- var c = request.cookies.get(name);
1488
- if (!c) return null;
1489
- return typeof c === 'string' ? c : (c.value || null);
1490
- } catch (e) {
1491
- return null;
1492
- }
1493
- }
1494
-
1495
- // next-auth stores the session token under a secure-prefixed cookie on https
1496
- // and a plain one on http, and splits large JWTs into ".0"/".1" chunks. The
2712
+ // The session token lives in the "__Host-" cookie on https and the plain one on
2713
+ // http (see the auth options), split into ".0"/".1" chunks when large. The
1497
2714
  // Edge runtime's getToken() can return null for a session the Node runtime
1498
2715
  // considers valid (e.g. NEXTAUTH_SECRET not identical in the Edge runtime, or
1499
2716
  // the JWE simply failing to decode at the edge), which previously redirected
1500
2717
  // logged-in users to sign-in. So cookie PRESENCE is the source of truth for
1501
2718
  // "is there a session"; getToken is only trusted for the optional role check.
1502
- // Server-side (getServerSideProps / API routes) remain the authoritative
1503
- // validators of the session and role.
2719
+ // Only the cookie the request's protocol allows counts — the same one
2720
+ // __tqSessionTokenCandidates names: a cookie a sibling site planted under
2721
+ // another name is never a session. Server-side (getServerSideProps / API
2722
+ // routes) remain the authoritative validators of the session and role.
1504
2723
  function hasSessionCookie(request) {
1505
- var names = [
1506
- '__Secure-next-auth.session-token',
1507
- 'next-auth.session-token',
1508
- '__Secure-authjs.session-token',
1509
- 'authjs.session-token'
1510
- ];
1511
- for (var i = 0; i < names.length; i++) {
1512
- if (readCookie(request, names[i]) || readCookie(request, names[i] + '.0')) {
1513
- return true;
1514
- }
1515
- }
1516
- return false;
2724
+ return __tqSessionTokenCandidates(request).length > 0;
1517
2725
  }
1518
2726
 
1519
2727
  // Turns a Next.js route pattern into an anchored matcher: "[param]" matches a
@@ -1776,8 +2984,10 @@ export const config = {
1776
2984
  // Next.js does NOT run the second (negative-lookahead) matcher for the root
1777
2985
  // path, which would leave a page published at "/" (e.g. a protected dashboard)
1778
2986
  // publicly reachable. '/' compiles to ^/$ and covers exactly the home route;
1779
- // the second entry covers every deeper path.
1780
- matcher: ['/', '/((?!api|_next/static|_next/image|favicon\\\\.ico).*)'],
2987
+ // the second entry covers every deeper path. Only the API routes are left
2988
+ // out — "/api" and "/api/..." — never a page whose path merely starts with
2989
+ // "api" (a protected "/api-keys" page).
2990
+ matcher: ['/', '/((?!api(?:/|$)|_next/static|_next/image|favicon\\\\.ico).*)'],
1781
2991
  };
1782
2992
  `;
1783
2993
  };