vybekiit 0.7.26 → 0.7.28

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 (274) hide show
  1. package/dist/bin.js +3910 -1300
  2. package/dist/global-guidance/language.md +443 -0
  3. package/dist/global-skills/add-ai/SKILL.md +1 -1
  4. package/dist/global-skills/add-analytics/SKILL.md +1 -1
  5. package/dist/global-skills/add-blog/SKILL.md +1 -1
  6. package/dist/global-skills/add-crud/SKILL.md +1 -1
  7. package/dist/global-skills/add-files/SKILL.md +1 -1
  8. package/dist/global-skills/add-images/SKILL.md +1 -1
  9. package/dist/global-skills/add-language/SKILL.md +1 -1
  10. package/dist/global-skills/add-notifications/SKILL.md +1 -1
  11. package/dist/global-skills/add-realtime/SKILL.md +1 -1
  12. package/dist/global-skills/add-route/SKILL.md +1 -1
  13. package/dist/global-skills/add-search/SKILL.md +1 -1
  14. package/dist/global-skills/add-signin/SKILL.md +1 -1
  15. package/dist/global-skills/add-teams/SKILL.md +1 -1
  16. package/dist/global-skills/add-upload/SKILL.md +1 -1
  17. package/dist/global-skills/aws-cdk/SKILL.md +19 -5
  18. package/dist/global-skills/aws-cdk/references/fast-deployments.md +191 -0
  19. package/dist/global-skills/aws-cdk/references/troubleshooting-deployment.md +16 -0
  20. package/dist/global-skills/aws-cloudformation/SKILL.md +16 -26
  21. package/dist/global-skills/aws-cloudformation/references/check-cloudformation-template-compliance.script.md +7 -3
  22. package/dist/global-skills/aws-cloudformation/references/cloudformation-language-server.md +177 -0
  23. package/dist/global-skills/aws-cloudformation/references/cloudformation-pre-deploy-validation.script.md +8 -2
  24. package/dist/global-skills/aws-cloudformation/references/persist-template-context.script.md +5 -8
  25. package/dist/global-skills/aws-cloudformation/references/retrieve-template-context.script.md +1 -1
  26. package/dist/global-skills/aws-cloudformation/references/security-considerations.md +51 -0
  27. package/dist/global-skills/aws-cloudformation/references/troubleshoot-failed-stack.script.md +138 -0
  28. package/dist/global-skills/aws-cloudformation/references/{validate-cloudformation-template.script.md → validate-with-cfn-lint.script.md} +15 -27
  29. package/dist/global-skills/aws-cloudformation/references/validate-with-cloudformation-validate.script.md +181 -0
  30. package/dist/global-skills/aws-cloudformation/references/validation-tool-selection.md +44 -0
  31. package/dist/global-skills/aws-serverless/SKILL.md +9 -1
  32. package/dist/global-skills/aws-serverless/references/architecture.md +3 -1
  33. package/dist/global-skills/aws-serverless/references/lambda.md +3 -1
  34. package/dist/global-skills/aws-serverless/references/orchestration.md +1 -0
  35. package/dist/global-skills/back-up-my-code/SKILL.md +1 -1
  36. package/dist/global-skills/better-auth-best-practices/SKILL.md +18 -8
  37. package/dist/global-skills/buy-domain/SKILL.md +1 -1
  38. package/dist/global-skills/check-safety/SKILL.md +1 -1
  39. package/dist/global-skills/configure-capabilities/SKILL.md +1 -1
  40. package/dist/global-skills/connect-account/SKILL.md +1 -1
  41. package/dist/global-skills/connect-account-backend/SKILL.md +1 -1
  42. package/dist/global-skills/design-my-data/SKILL.md +1 -1
  43. package/dist/global-skills/doctor/SKILL.md +1 -1
  44. package/dist/global-skills/eas-app-stores/SKILL.md +31 -15
  45. package/dist/global-skills/eas-app-stores/agents/openai.yaml +2 -2
  46. package/dist/global-skills/eas-app-stores/references/ios-app-store.md +37 -32
  47. package/dist/global-skills/eas-app-stores/references/native-ios.md +167 -0
  48. package/dist/global-skills/eas-app-stores/references/play-store.md +3 -7
  49. package/dist/global-skills/eas-app-stores/references/testflight.md +39 -35
  50. package/dist/global-skills/eas-simulator/SKILL.md +48 -26
  51. package/dist/global-skills/eas-simulator/references/controllers.md +32 -3
  52. package/dist/global-skills/eas-simulator/references/run-your-app.md +34 -4
  53. package/dist/global-skills/eas-simulator/references/troubleshooting.md +8 -4
  54. package/dist/global-skills/eas-update/SKILL.md +146 -0
  55. package/dist/global-skills/eas-update/agents/openai.yaml +4 -0
  56. package/dist/global-skills/expo-animation/RECIPES.md +2 -2
  57. package/dist/global-skills/expo-animation/SKILL.md +9 -2
  58. package/dist/global-skills/expo-brownfield/SKILL.md +18 -11
  59. package/dist/global-skills/expo-brownfield/agents/openai.yaml +2 -2
  60. package/dist/global-skills/expo-brownfield/references/brownfield-integrated.md +94 -69
  61. package/dist/global-skills/expo-brownfield/references/brownfield-isolated.md +40 -42
  62. package/dist/global-skills/expo-brownfield/references/comparison.md +5 -5
  63. package/dist/global-skills/expo-brownfield/references/feature-integration.md +163 -0
  64. package/dist/global-skills/expo-brownfield/references/troubleshooting.md +17 -17
  65. package/dist/global-skills/expo-brownfield/references/version-compatibility.md +40 -0
  66. package/dist/global-skills/expo-data-fetching/SKILL.md +27 -6
  67. package/dist/global-skills/expo-design-system/SKILL.md +27 -7
  68. package/dist/global-skills/expo-design-system/references/audit.md +7 -2
  69. package/dist/global-skills/expo-design-system/references/native-slop.md +74 -0
  70. package/dist/global-skills/expo-examples/SKILL.md +0 -1
  71. package/dist/global-skills/expo-examples/references/catalog.md +1 -1
  72. package/dist/global-skills/expo-migrate-module/SKILL.md +21 -10
  73. package/dist/global-skills/expo-migrate-module/references/compatibility.md +80 -23
  74. package/dist/global-skills/expo-migrate-module/references/migration-map.md +162 -11
  75. package/dist/global-skills/expo-native-ui/SKILL.md +25 -16
  76. package/dist/global-skills/expo-native-ui/agents/openai.yaml +2 -2
  77. package/dist/global-skills/expo-native-ui/references/controls.md +5 -46
  78. package/dist/global-skills/expo-native-ui/references/icons.md +21 -2
  79. package/dist/global-skills/expo-native-ui/references/media.md +15 -20
  80. package/dist/global-skills/expo-native-ui/references/visual-effects.md +12 -11
  81. package/dist/global-skills/expo-overview/SKILL.md +17 -12
  82. package/dist/global-skills/expo-router/SKILL.md +5 -3
  83. package/dist/global-skills/expo-router/references/tabs.md +5 -5
  84. package/dist/global-skills/expo-upgrade/SKILL.md +3 -1
  85. package/dist/global-skills/expo-web-to-native/references/false-friends.md +2 -2
  86. package/dist/global-skills/expo-web-to-native/references/native-patterns.md +1 -1
  87. package/dist/global-skills/firebase-ai-logic-basics/SKILL.md +13 -16
  88. package/dist/global-skills/firebase-ai-logic-basics/references/ios_setup.md +4 -5
  89. package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_android.md +4 -4
  90. package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_web.md +3 -3
  91. package/dist/global-skills/firebase-auth-basics/SKILL.md +11 -6
  92. package/dist/global-skills/firebase-auth-basics/references/client_sdk_android.md +4 -5
  93. package/dist/global-skills/firebase-auth-basics/references/client_sdk_web.md +3 -3
  94. package/dist/global-skills/firebase-auth-basics/references/flutter_setup.md +24 -25
  95. package/dist/global-skills/firebase-auth-basics/references/security_rules.md +4 -2
  96. package/dist/global-skills/firebase-crashlytics/references/android_setup.md +7 -4
  97. package/dist/global-skills/firebase-crashlytics/references/ios_setup.md +2 -3
  98. package/dist/global-skills/firebase-data-connect/SKILL.md +2 -1
  99. package/dist/global-skills/firebase-data-connect/examples.md +4 -4
  100. package/dist/global-skills/firebase-data-connect/reference/config.md +5 -4
  101. package/dist/global-skills/firebase-data-connect/reference/realtime.md +1 -2
  102. package/dist/global-skills/firebase-data-connect/reference/sdk_flutter.md +2 -2
  103. package/dist/global-skills/firebase-data-connect/reference/sdk_ios.md +2 -2
  104. package/dist/global-skills/firebase-data-connect/reference/sdk_web.md +17 -6
  105. package/dist/global-skills/firebase-data-connect/reference/security.md +5 -5
  106. package/dist/global-skills/firebase-data-connect/templates.md +2 -1
  107. package/dist/global-skills/firebase-firestore/SKILL.md +20 -8
  108. package/dist/global-skills/firebase-firestore/references/enterprise/android_sdk_usage.md +5 -4
  109. package/dist/global-skills/firebase-firestore/references/enterprise/data_model.md +12 -3
  110. package/dist/global-skills/firebase-firestore/references/enterprise/indexes.md +16 -18
  111. package/dist/global-skills/firebase-firestore/references/enterprise/provisioning.md +1 -1
  112. package/dist/global-skills/firebase-firestore/references/enterprise/python_sdk_usage.md +5 -1
  113. package/dist/global-skills/firebase-firestore/references/enterprise/web_sdk_usage.md +7 -7
  114. package/dist/global-skills/firebase-firestore/references/standard/android_sdk_usage.md +5 -5
  115. package/dist/global-skills/firebase-firestore/references/standard/flutter_setup.md +4 -4
  116. package/dist/global-skills/firebase-firestore/references/standard/indexes.md +16 -18
  117. package/dist/global-skills/firebase-firestore/references/standard/provisioning.md +1 -1
  118. package/dist/global-skills/firebase-remote-config-basics/SKILL.md +0 -5
  119. package/dist/global-skills/firebase-remote-config-basics/references/android_setup.md +36 -8
  120. package/dist/global-skills/firebase-remote-config-basics/references/ios_setup.md +1 -7
  121. package/dist/global-skills/firebase-security-rules-auditor/SKILL.md +17 -6
  122. package/dist/global-skills/{firebase-firestore/references/standard/security_rules.md → firestore-rules-creation/SKILL.md} +24 -13
  123. package/dist/global-skills/go-live/SKILL.md +1 -1
  124. package/dist/global-skills/grow-my-customers/SKILL.md +23 -0
  125. package/dist/global-skills/harden/SKILL.md +1 -1
  126. package/dist/global-skills/instrument-feature-flags/SKILL.md +25 -25
  127. package/dist/global-skills/instrument-feature-flags/references/adding-feature-flag-code.md +141 -285
  128. package/dist/global-skills/instrument-feature-flags/references/android.md +6 -15
  129. package/dist/global-skills/instrument-feature-flags/references/api.md +4 -11
  130. package/dist/global-skills/instrument-feature-flags/references/best-practices.md +1 -13
  131. package/dist/global-skills/instrument-feature-flags/references/django.md +14 -27
  132. package/dist/global-skills/instrument-feature-flags/references/dotnet.md +20 -79
  133. package/dist/global-skills/instrument-feature-flags/references/elixir.md +1 -9
  134. package/dist/global-skills/instrument-feature-flags/references/flask.md +13 -13
  135. package/dist/global-skills/instrument-feature-flags/references/flutter.md +3 -24
  136. package/dist/global-skills/instrument-feature-flags/references/go.md +3 -15
  137. package/dist/global-skills/instrument-feature-flags/references/ios.md +4 -17
  138. package/dist/global-skills/instrument-feature-flags/references/java.md +5 -13
  139. package/dist/global-skills/instrument-feature-flags/references/laravel.md +13 -17
  140. package/dist/global-skills/instrument-feature-flags/references/next-js.md +25 -32
  141. package/dist/global-skills/instrument-feature-flags/references/nodejs.md +8 -15
  142. package/dist/global-skills/instrument-feature-flags/references/php.md +1 -15
  143. package/dist/global-skills/instrument-feature-flags/references/python.md +2 -15
  144. package/dist/global-skills/instrument-feature-flags/references/react-native.md +13 -15
  145. package/dist/global-skills/instrument-feature-flags/references/react.md +17 -21
  146. package/dist/global-skills/instrument-feature-flags/references/ruby-on-rails.md +37 -83
  147. package/dist/global-skills/instrument-feature-flags/references/ruby.md +2 -15
  148. package/dist/global-skills/instrument-feature-flags/references/rust.md +13 -25
  149. package/dist/global-skills/instrument-feature-flags/references/usage.md +14 -63
  150. package/dist/global-skills/instrument-feature-flags/references/web.md +9 -14
  151. package/dist/global-skills/instrument-product-analytics/SKILL.md +29 -29
  152. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-hybrid.md +3 -1
  153. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-ssr.md +3 -1
  154. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-static.md +3 -1
  155. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-view-transitions.md +3 -1
  156. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby-on-rails.md +3 -1
  157. package/dist/global-skills/instrument-product-analytics/references/android.md +72 -107
  158. package/dist/global-skills/instrument-product-analytics/references/angular.md +26 -28
  159. package/dist/global-skills/instrument-product-analytics/references/astro.md +13 -24
  160. package/dist/global-skills/instrument-product-analytics/references/configuration.md +45 -63
  161. package/dist/global-skills/instrument-product-analytics/references/django.md +14 -27
  162. package/dist/global-skills/instrument-product-analytics/references/dotnet.md +20 -79
  163. package/dist/global-skills/instrument-product-analytics/references/elixir.md +47 -49
  164. package/dist/global-skills/instrument-product-analytics/references/flask.md +13 -13
  165. package/dist/global-skills/instrument-product-analytics/references/flutter.md +60 -90
  166. package/dist/global-skills/instrument-product-analytics/references/go.md +17 -56
  167. package/dist/global-skills/instrument-product-analytics/references/identify-users.md +15 -15
  168. package/dist/global-skills/instrument-product-analytics/references/ios.md +11 -15
  169. package/dist/global-skills/instrument-product-analytics/references/laravel.md +13 -17
  170. package/dist/global-skills/instrument-product-analytics/references/next-js.md +25 -32
  171. package/dist/global-skills/instrument-product-analytics/references/nuxt-js-3-6.md +13 -27
  172. package/dist/global-skills/instrument-product-analytics/references/nuxt-js.md +14 -28
  173. package/dist/global-skills/instrument-product-analytics/references/php.md +33 -84
  174. package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +229 -9
  175. package/dist/global-skills/instrument-product-analytics/references/python.md +415 -106
  176. package/dist/global-skills/instrument-product-analytics/references/react-native.md +161 -155
  177. package/dist/global-skills/instrument-product-analytics/references/react-router-v6.md +12 -33
  178. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-data-mode.md +15 -33
  179. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +12 -33
  180. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +26 -41
  181. package/dist/global-skills/instrument-product-analytics/references/ruby-on-rails.md +37 -83
  182. package/dist/global-skills/instrument-product-analytics/references/ruby.md +48 -108
  183. package/dist/global-skills/instrument-product-analytics/references/svelte.md +18 -24
  184. package/dist/global-skills/instrument-product-analytics/references/tanstack-start.md +17 -19
  185. package/dist/global-skills/instrument-product-analytics/references/usage.md +14 -63
  186. package/dist/global-skills/instrument-product-analytics/references/vue-js.md +29 -28
  187. package/dist/global-skills/manifest.json +8 -2
  188. package/dist/global-skills/mongodb-search-and-ai/SKILL.md +28 -37
  189. package/dist/global-skills/mongodb-search-and-ai/references/automated-embedding.md +438 -0
  190. package/dist/global-skills/mongodb-search-and-ai/references/hybrid-search.md +60 -4
  191. package/dist/global-skills/mongodb-search-and-ai/references/vector-search.md +46 -108
  192. package/dist/global-skills/neon/SKILL.md +207 -213
  193. package/dist/global-skills/neon/references/auth.md +12 -0
  194. package/dist/global-skills/neon/references/claimable-neon.md +10 -14
  195. package/dist/global-skills/neon/references/function-triggers.md +53 -0
  196. package/dist/global-skills/neon/references/logs-loki.md +61 -0
  197. package/dist/global-skills/neon/references/parse-env.md +32 -0
  198. package/dist/global-skills/neon/references/sdk.md +7 -0
  199. package/dist/global-skills/neon-ai-gateway/SKILL.md +14 -16
  200. package/dist/global-skills/neon-auth/SKILL.md +155 -0
  201. package/dist/global-skills/neon-auth/references/managed-auth.md +173 -0
  202. package/dist/global-skills/neon-auth/references/self-managed.md +25 -0
  203. package/dist/global-skills/neon-functions/SKILL.md +159 -84
  204. package/dist/global-skills/neon-functions/references/ai-sdk.md +4 -6
  205. package/dist/global-skills/neon-functions/references/function-triggers.md +249 -0
  206. package/dist/global-skills/neon-functions/references/mastra-studio.md +3 -3
  207. package/dist/global-skills/neon-functions/references/mcp.md +1 -1
  208. package/dist/global-skills/neon-functions/references/production-hardening.md +340 -0
  209. package/dist/global-skills/neon-functions/references/sse.md +8 -5
  210. package/dist/global-skills/neon-object-storage/SKILL.md +10 -11
  211. package/dist/global-skills/neon-postgres/SKILL.md +120 -17
  212. package/dist/global-skills/neon-postgres/references/full-text-search.md +99 -0
  213. package/dist/global-skills/neon-postgres/references/hybrid-search.md +90 -0
  214. package/dist/global-skills/neon-postgres/references/lakebase-search-drizzle.md +172 -0
  215. package/dist/global-skills/neon-postgres/references/vector-search.md +137 -0
  216. package/dist/global-skills/neon-postgres-branches/SKILL.md +3 -3
  217. package/dist/global-skills/neon-postgres-egress-optimizer/SKILL.md +1 -1
  218. package/dist/global-skills/onboarding/SKILL.md +16 -14
  219. package/dist/global-skills/plan-my-idea/SKILL.md +1 -1
  220. package/dist/global-skills/publish-app/SKILL.md +1 -1
  221. package/dist/global-skills/publish-extension/SKILL.md +1 -1
  222. package/dist/global-skills/resend/SKILL.md +4 -2
  223. package/dist/global-skills/resend/references/broadcasts.md +6 -1
  224. package/dist/global-skills/resend/references/receiving.md +29 -10
  225. package/dist/global-skills/resend/references/sending/email-management.md +14 -4
  226. package/dist/global-skills/resend/references/topics.md +9 -6
  227. package/dist/global-skills/resend/references/usage.md +117 -0
  228. package/dist/global-skills/resend/references/webhooks.md +59 -2
  229. package/dist/global-skills/reset-password/SKILL.md +1 -1
  230. package/dist/global-skills/save-data/SKILL.md +1 -1
  231. package/dist/global-skills/setup-email/SKILL.md +1 -1
  232. package/dist/global-skills/setup-payments/SKILL.md +1 -1
  233. package/dist/global-skills/setup-sms/SKILL.md +1 -1
  234. package/dist/global-skills/sign-in-with-email-link/SKILL.md +1 -1
  235. package/dist/global-skills/sign-in-with-google/SKILL.md +1 -1
  236. package/dist/global-skills/sign-in-with-phone/SKILL.md +1 -1
  237. package/dist/global-skills/stripe-best-practices/SKILL.md +35 -29
  238. package/dist/global-skills/stripe-best-practices/references/billing.md +9 -2
  239. package/dist/global-skills/stripe-best-practices/references/payments.md +4 -2
  240. package/dist/global-skills/stripe-best-practices/references/security.md +3 -1
  241. package/dist/global-skills/stripe-best-practices/references/tax.md +39 -20
  242. package/dist/global-skills/supabase/SKILL.md +6 -0
  243. package/dist/global-skills/track-errors/SKILL.md +1 -1
  244. package/dist/global-skills/update-kit/SKILL.md +1 -1
  245. package/dist/global-skills/use-railway/SKILL.md +42 -22
  246. package/dist/global-skills/use-railway/references/analyze-db.md +7 -6
  247. package/dist/global-skills/use-railway/references/cloud-agents.md +70 -0
  248. package/dist/global-skills/use-railway/references/configure.md +17 -2
  249. package/dist/global-skills/use-railway/references/databases.md +107 -0
  250. package/dist/global-skills/use-railway/references/deploy.md +5 -5
  251. package/dist/global-skills/use-railway/references/feature-flags.md +25 -13
  252. package/dist/global-skills/use-railway/references/iac.md +66 -77
  253. package/dist/global-skills/use-railway/references/operate.md +26 -3
  254. package/dist/global-skills/use-railway/references/request.md +31 -23
  255. package/dist/global-skills/use-railway/references/setup.md +16 -5
  256. package/dist/global-skills/use-railway/references/tracing.md +261 -0
  257. package/dist/global-skills/use-railway/references/usage.md +52 -0
  258. package/dist/global-skills/validate-my-idea/SKILL.md +54 -0
  259. package/dist/global-skills/{feedback → vybekiit-feedback}/SKILL.md +17 -13
  260. package/dist/global-skills/watch-my-app/SKILL.md +53 -0
  261. package/dist/global-skills/wire-auth/SKILL.md +1 -1
  262. package/dist/global-skills/wire-database/SKILL.md +1 -1
  263. package/dist/global-skills/wire-email/SKILL.md +1 -1
  264. package/dist/global-skills/wire-payments/SKILL.md +1 -1
  265. package/dist/global-skills/workers-best-practices/SKILL.md +36 -103
  266. package/dist/global-skills/workers-best-practices/references/configuration.md +139 -0
  267. package/dist/global-skills/workers-best-practices/references/platform-apis.md +51 -0
  268. package/dist/global-skills/workers-best-practices/references/{rules.md → runtime-patterns.md} +13 -137
  269. package/dist/global-skills/wrangler/SKILL.md +48 -901
  270. package/dist/global-skills/xcode-project-setup/scripts/xcode_spm_setup/Sources/main.swift +19 -15
  271. package/package.json +9 -8
  272. package/dist/global-skills/expo-native-ui/references/animations.md +0 -220
  273. package/dist/global-skills/firebase-firestore/references/enterprise/security_rules.md +0 -577
  274. package/dist/global-skills/workers-best-practices/references/review.md +0 -174
@@ -7,11 +7,15 @@ description: >-
7
7
  streaming responses, a WebSocket or server-sent-events (SSE) server, a
8
8
  webhook handler, a Discord bot, an MCP server, or any request/response
9
9
  workload that risks timing out on short, lambda-style serverless functions —
10
- and wants it to branch with their database. Triggers include "serverless
11
- function", "deploy an API", "long-running function", "streaming agent",
12
- "SSE server", "WebSocket server", "webhook handler", "MCP server",
13
- "run code next to my database", "function that won't time out",
14
- "function logs", "Neon Functions", and "Neon Compute".
10
+ and wants it to branch with their database. Also use for Function Triggers:
11
+ a cron or an object-storage event that POSTs to a function. Triggers include
12
+ "serverless function", "deploy an API", "long-running function",
13
+ "streaming agent", "SSE server", "WebSocket server", "webhook handler",
14
+ "MCP server", "cron", "function trigger", "scheduled function", "cron job",
15
+ "object storage trigger", "on upload", "run code next to my database",
16
+ "function that won't time out", "function logs", "Neon Functions",
17
+ "Neon Compute", "DDoS protection", "rate limiting", and
18
+ "production hardening".
15
19
  metadata:
16
20
  parent: neon
17
21
  source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-functions
@@ -22,12 +26,12 @@ metadata:
22
26
  If the `neon` skill is not installed, fetch it from https://neon.com/docs/ai/skills/neon/SKILL.md or install it with:
23
27
 
24
28
  ```bash
25
- npx skills add neondatabase/agent-skills --skill neon
29
+ neon skills -s neon -y
26
30
  ```
27
31
 
28
32
  # Neon Functions
29
33
 
30
- This is a public beta feature and only available in `us-east-2`.
34
+ Currently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`.
31
35
 
32
36
  Neon Functions are long-running Node.js HTTP handlers deployed onto a Neon branch. Each function gets a public HTTPS URL, runs in the same region as your database, and — if the branch has Postgres — gets `DATABASE_URL` injected automatically. You deploy and manage them through the same Neon CLI, `neon.ts`, and API you already use.
33
37
 
@@ -41,9 +45,11 @@ Reach for Neon Functions when the workload is a request/response handler that be
41
45
  - **Stateful streaming without bolting on Redis.** Because a function stays alive across a request, it can host an SSE endpoint or a WebSocket server and hold the connection open in-process — no external state store (Redis, etc.) needed just to keep a stream coherent. Module-scope state (a `pg` pool, an in-memory counter) persists across requests on the same isolate.
42
46
  - **Compute that must sit next to Postgres.** The function runs in the same region as the branch's database, so there are no cross-region round trips on every query. `DATABASE_URL` is injected for you.
43
47
  - **A backend that branches with your data.** Each branch runs its own version of the function at its own URL, against its own isolated database (and storage, and gateway) state. Preview deployments, CI, and dev environments each get a self-contained backend — deploying to a child never affects the parent.
48
+ - **Query Postgres from the Function (or an existing framework handler).** Prefer that over the Data API. Use the Data API when the application already uses PostgREST or Supabase-js database calls, or is migrating that client.
44
49
  - **Webhooks, bots, and post-response work.** Webhook handlers that fan out into multiple DB writes, Discord/WebSocket bots, and fire-and-forget follow-ups via `waitUntil` (analytics, audit logs) all fit.
50
+ - **Recurring HTTP work.** A Function Trigger POSTs to the function on a cron (`type: "schedule"`) or when an object is created in Object Storage (`type: "storage_object_created"`). Same `fetch` handler, same 15-minute time-to-first-byte limit. See [Function Triggers](#function-triggers).
45
51
 
46
- If the workload is a pure static site, a cron/background job that needs its own lifecycle and cancellation, or something that must run outside `us-east-2` today, this isn't the right tool yet (see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits) and [Availability](#availability)).
52
+ If the workload is a pure static site, or something that must run outside the supported regions (`aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`) today, this isn't the right tool yet (see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits) and [Availability](#availability)).
47
53
 
48
54
  ## What It Does
49
55
 
@@ -52,36 +58,43 @@ If the workload is a pure static site, a cron/background job that needs its own
52
58
  - **Close to your database** — Runs in the branch's region; `DATABASE_URL` injected automatically when the branch has Postgres.
53
59
  - **Branchable** — Each branch runs its own function version at its own URL against its own isolated state.
54
60
  - **Same CLI/API** — Deploy and manage via `neon`, `neon.ts`, or the Neon API.
61
+ - **Function Triggers** — Neon POSTs to the function on a cron or an object-storage upload. See [Function Triggers](#function-triggers).
55
62
 
56
63
  ## Availability
57
64
 
58
- Check this precondition before setting anything up: Neon Functions is a public beta feature available in the `us-east-2` region. Confirm the user's Neon project is in `us-east-2`. Functions usage isn't billed during the public beta.
65
+ Check this precondition before setting anything up: Neon Functions is currently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`. Confirm the user's Neon project is in one of these regions.
59
66
 
60
67
  ## Architecture: Where Functions Fit
61
68
 
62
69
  Neon (Functions included) is **backend primitives, not full-stack app hosting**. Host your app on **Vercel** (or Netlify, or another frontend/app host); Functions are the long-running, stateful slice of your backend that lives next to your data. They compose with that platform in two ways:
63
70
 
64
- - **Add a Function to a full-stack app.** Your Next.js / TanStack Start app on Vercel (or Netlify) owns UI, auth (e.g. Neon Auth), and talks directly to Lakebase Postgres and Object Storage. When one workload outgrows the host's short serverless limits — a WebSocket or SSE server, or a long-running agent that would time out — move just that piece onto a Neon Function. (See [Functions as an Agent Backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks) for the client-direct pattern.)
71
+ - **Add a Function to a full-stack app.** Your Next.js / TanStack Start app on Vercel (or Netlify) owns UI, auth (Managed Auth, Better Auth, Clerk, or another IdP), and talks directly to Lakebase Postgres and Object Storage. Add a Function as a Hono API layer for the web app and other clients, or for one job next to the data: Object Storage uploads, AI agents, Discord bots, WebSocket or SSE servers. (See [Functions as an Agent Backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks) for the client-direct pattern.)
65
72
  - **Run the whole backend control plane on Functions.** Especially when the frontend is **client-only** — TanStack Router, React Router in client mode, and similar SPAs hosted on Vercel or Netlify — the client calls Functions **directly**. Build REST APIs and request/response agents, host **MCP servers**, and run anything stateful or that belongs close to Postgres and Object Storage.
66
73
 
67
- Either way, secure a Function like any standalone REST API: verify a JWT or API key at the top of the handler (see the WARNING under [Functions as an Agent Backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks)). Because a Function is just your backend, you can **move pieces between your host and Neon** — relocate an agent or a stateful WebSocket server onto a Function when it needs more runtime, and back if needed.
74
+ Either way, authenticate by caller: JWT or API key for app and public HTTP (see the WARNING under [Functions as an Agent Backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks)); `parseTriggerDelivery` for Function Trigger routes; production hardening in [Production hardening](references/production-hardening.md). Because a Function is just your backend, you can **move pieces between your host and Neon** — relocate an agent or a stateful WebSocket server onto a Function when it needs more runtime, and back if needed.
75
+
76
+ Prefer a Function, or an existing framework handler, that queries Postgres. Use Data API when the application already uses PostgREST/Supabase-js database calls or is migrating that client.
77
+
78
+ ## Production hardening
79
+
80
+ Before exposing production routes, read [Production hardening](references/production-hardening.md).
81
+
82
+ Pick by caller: trusted app server, Function Trigger, or public consumer. Keep long browser streams on the client-direct JWT path unless a verified streaming-compatible proxy is required. Authentication rejects application work; requests to the native URL still reach the Function.
68
83
 
69
84
  ## Setup
70
85
 
71
- Functions are declared in `neon.ts` (see the `neon` skill for the branch-first workflow and `neon.ts` basics). Add `@neon/config` and declare functions under `preview.functions`, keyed by **slug**:
86
+ Functions are declared in `neon.ts` (see the `neon` skill for the branch-first workflow and `neon.ts` basics). Add `@neon/config` and declare functions under `functions`, keyed by **slug**:
72
87
 
73
88
  ```typescript
74
89
  // neon.ts
75
90
  import { defineConfig } from "@neon/config/v1";
76
91
 
77
92
  export default defineConfig({
78
- preview: {
79
- functions: {
80
- todos: {
81
- // slug: ^[a-z0-9]{1,20}$ — lowercase letters/digits, no hyphens
82
- name: "todo api", // display label only
83
- source: "src/index.ts", // entry file, relative to neon.ts
84
- },
93
+ functions: {
94
+ todos: {
95
+ // slug: ^[a-z0-9]{1,20}$ — lowercase letters/digits, no hyphens
96
+ name: "todo api", // display label only
97
+ source: "src/index.ts", // entry file, relative to neon.ts
85
98
  },
86
99
  },
87
100
  });
@@ -132,34 +145,34 @@ attachDatabasePool(pool);
132
145
 
133
146
  ```bash
134
147
  neon dev # serves every function in neon.ts with hot reload; injects DATABASE_URL & friends
135
- neon deploy # bundles with esbuild, uploads, and applies neon.ts to the linked branch
148
+ neon deploy --env <file> # preferred full deploy from neon.ts; --env is the file Function env is read from
136
149
  ```
137
150
 
138
- To deploy a single function without `neon.ts`: `neon functions deploy <slug> --src src/index.ts` (`--src` takes either the entry file or a directory containing `index.ts`, `index.mjs`, or `index.js`). Retrieve the public URL with `neon functions get <slug>` (the `invocation_url` field, of the form `https://<branch_id>-<slug>.compute.<cell>.us-east-2.aws.neon.tech`). Manage with `neon functions list|get|delete`.
151
+ Keep `.env` or `.env.local` up to date with every key under `functions.*.env`. `neon env pull` writes Neon-managed vars only; add Function secrets to that file, then pass it as `--env`. `neon deploy --env <file>` loads that file into `process.env` each time, then uploads those values. A missing value is `undefined` and `defineConfig` throws. Omit the key from `neon.ts` if you do not want to write it. Never coerce a missing `process.env` value to an empty string (that uploads `""` and deletes the live key). An empty assignment (`KEY=`) is also `""`. Use `process.env.X!` when TypeScript needs an assertion.
152
+
153
+ To deploy a single function without applying `neon.ts`: `neon functions deploy <slug> --src src/index.ts` (`--src` takes either the entry file or a directory containing `index.ts`, `index.mjs`, or `index.js`). That command's `--env` is `KEY=VALUE` (repeatable), not a file path. Use it for a targeted env update. Retrieve the public URL with `neon functions get <slug>` (the `invocation_url` field, of the form `https://<branch_id>-<slug>.compute.<cell>.us-east-2.aws.neon.tech`). Manage with `neon functions list|get|delete`.
139
154
 
140
- When `neon checkout` _creates_ a new branch and a `neon.ts` is present, it applies the policy automatically — deploying the function to the fresh branch. Checking out an existing branch does not re-deploy; run `neon deploy` explicitly.
155
+ When `neon checkout` _creates_ a new branch and a `neon.ts` is present, it applies the policy automatically. Pass `--env <file>` on that create so Function env that reads `process.env` resolves (`neon checkout feat --create --env .env.local`). Existing process env wins over the file. Checking out an existing branch never reconciles it — apply config changes with `neon deploy --env <file>` (add `--update-existing` only after reviewing those changes).
141
156
 
142
157
  ## Neon Infrastructure as Code (`neon.ts`)
143
158
 
144
- The `preview.functions` block from [Setup](#setup) is part of `neon.ts`, Neon's infrastructure-as-code file — one TypeScript file declares every function (its `source`, display `name`, and `env`) alongside any other branch services, in version control (see the `neon` skill for the full reference). Treat it like Terraform for your branch:
159
+ The `functions` block from [Setup](#setup) is part of `neon.ts`, Neon's infrastructure-as-code file — one TypeScript file declares every function (its `source`, display `name`, and `env`) alongside any other branch services, in version control (see the `neon` skill for the full reference). Treat it like Terraform for your branch:
145
160
 
146
161
  ```bash
147
162
  neon config status # print the branch's live config (deployed functions)
148
163
  neon config plan # dry-run diff of what apply would change
149
- neon config apply # bundle + deploy the declared functions (neon deploy is an alias)
164
+ neon config apply --env <file> # bundle + deploy the declared functions (neon deploy is an alias; pass --env when Function env reads process.env)
150
165
  ```
151
166
 
152
- Functions are **branch-scoped**: each branch runs its own deployment at its own URL. When a `neon.ts` is present, `neon checkout` applies the policy as it _creates_ a branch, so a fresh preview/CI branch comes up with the function already deployed. Checking out an _existing_ branch doesn't redeploy — run `neon deploy` to apply changes.
167
+ Functions are **branch-scoped**: each branch runs its own deployment at its own URL. When a `neon.ts` is present, `neon checkout` applies the policy as it _creates_ a branch. Pass `--env <file>` on that create when Function env reads `process.env`. Checking out an _existing_ branch doesn't redeploy — run `neon deploy --env <file>` to apply changes.
153
168
 
154
169
  Per-branch deploy tuning (e.g. `runtime`) lives in the `branch` closure, keyed by slug, so it can vary by branch without changing which functions exist:
155
170
 
156
171
  ```typescript
157
172
  export default defineConfig({
158
- preview: {
159
- functions: { todos: { name: "todo api", source: "src/index.ts" } },
160
- },
173
+ functions: { todos: { name: "todo api", source: "src/index.ts" } },
161
174
  branch: (branch) => ({
162
- preview: { functions: { todos: { runtime: "nodejs24" } } },
175
+ functions: { todos: { runtime: "nodejs24" } },
163
176
  }),
164
177
  });
165
178
  ```
@@ -174,13 +187,14 @@ Neon injects branch-scoped connection strings and service URLs at runtime — yo
174
187
  | `DATABASE_URL` | Pooled connection string. Use for most queries. Present only if the branch has Postgres. |
175
188
  | `DATABASE_URL_UNPOOLED` | Direct connection. Use for migrations, `LISTEN`/`NOTIFY`, multi-round-trip transactions. |
176
189
  | `NEON_AUTH_BASE_URL` | Present when Neon Auth is enabled on the branch. |
190
+ | `NEON_AUTH_JWKS_URL` | Present when Neon Auth is enabled on the branch. JWKS for verifying Managed Auth JWTs. |
177
191
  | `NEON_DATA_API_URL` | Present when the Data API is enabled on the branch. |
178
192
 
179
193
  Object storage (`AWS_*`) and AI Gateway (`NEON_AI_GATEWAY_*`) vars are also injected when those services are declared — see the `neon-object-storage` and `neon-ai-gateway` skills.
180
194
 
181
195
  `neon env pull` / `neon-env run` / `neon dev` emit `NEON_BRANCH` (and the connection strings) into your local dev environment too, so local runs mirror the deployed runtime.
182
196
 
183
- **Your own secrets** are per-deployment. Set them with `--env KEY=VALUE` on `neon functions deploy` (repeatable; `--env KEY=` deletes a key, unmentioned keys carry over), or declare them in `neon.ts` under the function's `env` (resolved at deploy time, so read from `process.env` to avoid hardcoding):
197
+ **Your own secrets** are per-deployment. Preferred path: declare them in `neon.ts` and run `neon deploy --env <file>`. `<file>` is the gitignored file env pull already writes (`.env` if that file exists, otherwise `.env.local`). Env pull writes Neon-managed vars only; add Function secrets to that file. All declared Function env keys must be present. Omit a key from `neon.ts` if you do not want to write it. `undefined` means you asked to write the key and the value is missing (`defineConfig` throws). Never coerce a missing `process.env` value to an empty string: that uploads `""` and deletes the live key. An empty assignment in the file (`KEY=`) is also `""`. If TypeScript needs an assertion, use `process.env.X!` and make sure the file has the value:
184
198
 
185
199
  ```typescript
186
200
  functions: {
@@ -192,7 +206,9 @@ functions: {
192
206
  }
193
207
  ```
194
208
 
195
- Load a `.env` before deploy with `neon deploy --env .env.production`. Pull the branch's Neon-managed vars onto disk for local dev with `neon env pull` (`link`/`checkout` do this automatically; pass `--no-env-pull` to skip and use `neon-env run -- <cmd>` for runtime injection). Limits: ≤1,000 vars, ≤64 KiB total, and the `NEON_` prefix is reserved.
209
+ `neon functions deploy --env KEY=VALUE` is the manual path (repeatable; `--env KEY=` deletes a key; unmentioned keys carry over). Use it for a targeted env update, not a full `neon.ts` apply.
210
+
211
+ Load Function secrets into the same file env pull wrote, then `neon deploy --env <file>`. Pull the branch's Neon-managed vars onto disk for local dev with `neon env pull` (`link`/`checkout` do this automatically; pass `--no-env-pull` to skip and use `neon-env run -- <cmd>` for runtime injection). Limits: ≤1,000 vars, ≤64 KiB total, and the `NEON_` prefix is reserved.
196
212
 
197
213
  ## Connecting to Postgres
198
214
 
@@ -231,11 +247,11 @@ Functions are long-running but **still serverless** — they are a request/respo
231
247
  - **Heartbeat: 15 minutes.** Open WebSocket/SSE connections stay alive as long as data flows. The timeout only fires when a connection goes silent — send at least one byte every 15 minutes to keep a quiet stream alive.
232
248
  - **`waitUntil`: 15 minutes.** Work registered with `waitUntil` (from `@neon/functions`) keeps the invocation alive after the response is sent, up to 15 minutes — for cleanup like analytics writes and audit logs, **not** a background job runner. Off the Neon runtime (local `neon dev`, tests) it's a no-op: the promise still runs but isn't tracked.
233
249
  - **Idle eviction.** With no active connections Neon shuts the function down; it may also evict/restart for operational reasons — e.g. maintenance, or moving the function to a different compute node (active functions can run for hours first). Treat eviction like a process restart — WebSocket/SSE clients must reconnect. Neon sends `SIGINT` before evicting, so a `process.on("SIGINT", ...)` handler lets you detect that the function is about to be evicted and run any last-minute cleanup. You don't need one just to close Postgres connections — Neon's pooler reclaims those on its own.
234
- - **Runtime:** Node.js 24, memory fixed at 2048 MiB during the preview. Slugs must match `^[a-z0-9]{1,20}$`. **An isolate is reused across many requests** — multiple requests can be in flight on the same isolate at once (interleaved on Node's single-threaded event loop), and under load the runtime runs several isolates in parallel, each with its own copy of module state. State held in module scope is therefore per-isolate (shared by every request that isolate handles) and in-memory only — persist anything that must survive eviction in Postgres. This reuse is exactly why you create a connection pool once at module scope rather than per request (see [Connecting to Postgres](#connecting-to-postgres)).
250
+ - **Runtime:** Node.js 24, memory fixed at 2048 MiB. Slugs must match `^[a-z0-9]{1,20}$`. **An isolate is reused across many requests** — multiple requests can be in flight on the same isolate at once (interleaved on Node's single-threaded event loop), and under load the runtime runs several isolates in parallel, each with its own copy of module state. State held in module scope is therefore per-isolate (shared by every request that isolate handles) and in-memory only — persist anything that must survive eviction in Postgres. This reuse is exactly why you create a connection pool once at module scope rather than per request (see [Connecting to Postgres](#connecting-to-postgres)).
235
251
 
236
252
  ## Functions as an Agent Backend (Next.js and Similar Frameworks)
237
253
 
238
- A Neon Function is a great home for an AI agent precisely because it **doesn't time out** the way lambda-style serverless does (15-minute budget, see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits)). But that advantage disappears the moment you **proxy the agent stream through your web app's backend** — a Next.js route handler, Remix/SvelteKit/Nuxt action, etc. hosted on Vercel, Netlify, Cloudflare, and the like. Those platforms cap serverless/edge execution at short windows (often ~10–60s, sometimes up to ~300s), so a long agent or image/video generation stream gets cut off mid-response even though the Neon Function would happily keep going.
254
+ A Neon Function is a great home for an AI agent precisely because it **doesn't time out** the way lambda-style serverless does (15-minute budget, see [Timeouts and Runtime Limits](#timeouts-and-runtime-limits)). Proxying that stream through a Next.js route handler, Remix/SvelteKit/Nuxt action, or similar hosted on Vercel, Netlify, and the like **cuts the stream when it exceeds that host's configured duration or transport limits**, even though the Function would keep going. Keep the client-direct JWT path below as the default. A streaming-compatible proxy (HTTP-triggered Cloudflare Worker, after you verify the stream) is the public-consumer exception in [Production hardening](references/production-hardening.md).
239
255
 
240
256
  **Building the agent itself.** The [Vercel AI SDK](https://ai-sdk.dev) and [Mastra](https://mastra.ai) are the recommended ways to build the agent — point either at the Neon AI Gateway (see the `neon-ai-gateway` skill) for one credential across every model, with no extra provider keys. For a complete AI SDK agent running as a Function (streaming `toUIMessageStreamResponse`, multi-step tool calling next to Postgres, and persisting generated images to Object Storage), see [references/ai-sdk.md](https://neon.com/docs/ai/skills/neon-functions/references/ai-sdk.md); for the Mastra equivalent with built-in tracing, see [references/mastra-studio.md](https://neon.com/docs/ai/skills/neon-functions/references/mastra-studio.md).
241
257
 
@@ -246,20 +262,23 @@ Browser ──(Authorization: Bearer <JWT>)──▶ Neon Function (agent)
246
262
  Browser ──▶ your app backend ──▶ Neon Function ❌ host cuts the stream
247
263
  ```
248
264
 
249
- - Mint a **short-lived JWT** on your app backend (e.g. better-auth's `jwt` plugin, NextAuth, or your own signer) — that call is fast and well within host limits.
250
- - Hand the token to the client and have it call the Neon Function **directly** (cross-origin), e.g. with the Vercel AI SDK: `new DefaultChatTransport({ api: NEON_FUNCTION_URL, fetch })` where `fetch` attaches `Authorization: Bearer <token>`. Your app server is never in the path of the long stream.
265
+ - Get a **short-lived bearer token** from the identity the app already uses. Do not switch Clerk, Better Auth, Auth.js, Supabase Auth, or Managed Auth in order to call a Function.
266
+ - Managed Auth, default client (`createAuthClient` / Next wrapper): `authClient.token()`, then `data.token`. Verify with injected `NEON_AUTH_JWKS_URL` and issuer `new URL(process.env.NEON_AUTH_BASE_URL!).origin`.
267
+ - Managed Auth with `SupabaseAuthAdapter()`: that client has no `.token()`. Use `getSession()`, then `data.session.access_token`. Same JWKS/issuer as above.
268
+ - Existing Better Auth / Auth.js / other signer that already publishes JWKS: use that JWKS URL, issuer, and audience. Inspect the installed contract; cookie or database sessions are not a JWKS.
269
+ - Cookie/database sessions only: mint a short token on the existing app backend (that call is fast and stays within host limits), then the browser calls the Function **directly** with `Authorization: Bearer`. The Function stream must not go through the app host.
270
+ - Hand the token to the client, e.g. with the Vercel AI SDK: `new DefaultChatTransport({ api: NEON_FUNCTION_URL, fetch })` where `fetch` attaches `Authorization: Bearer <token>`. Your app server is never in the path of the long stream.
251
271
  - Add **CORS** so the browser can reach it (handle `OPTIONS`, set `Access-Control-Allow-Origin`/`-Headers`).
252
272
 
253
273
  > [!WARNING]
254
- > A Neon Function has a **public HTTPS URL — it is reachable by anyone.** A direct client→function call means there is no app backend in front of it to gate access, so **you must authenticate the function yourself.** Verify a JWT (e.g. against your app's JWKS), check a shared secret / API key, or validate a session token at the top of the handler and reject anything else. Never deploy an unauthenticated agent.
274
+ > A Neon Function has a **public HTTPS URL — it is reachable by anyone.** A direct client→function call means there is no app backend in front of it to gate access, so **you must authenticate the function yourself.** Verify a JWT against the caller's JWKS, check a shared secret / API key, or reject the request. Never deploy an unauthenticated agent. Browser callers use short-lived user tokens. Server or proxy origin secrets (`X-Secret`) stay server-side; see [Production hardening](references/production-hardening.md).
255
275
 
256
276
  ```typescript
257
277
  // src/index.ts — verify the caller before doing any work
258
278
  import { createRemoteJWKSet, jwtVerify } from "jose";
259
279
 
260
- const jwks = createRemoteJWKSet(
261
- new URL(`${process.env.AUTH_BASE_URL}/api/auth/jwks`),
262
- );
280
+ const jwks = createRemoteJWKSet(new URL(process.env.NEON_AUTH_JWKS_URL!));
281
+ const issuer = new URL(process.env.NEON_AUTH_BASE_URL!).origin;
263
282
 
264
283
  export default {
265
284
  async fetch(request: Request) {
@@ -273,30 +292,39 @@ export default {
273
292
  headers: cors(request),
274
293
  });
275
294
  }
295
+ let userId: string;
276
296
  try {
277
- const { payload } = await jwtVerify(auth.slice(7), jwks, {
278
- issuer: process.env.AUTH_BASE_URL,
279
- audience: process.env.AUTH_BASE_URL,
280
- });
281
- const userId = payload.sub; // scope the agent to this user
282
- // ... run the agent, return result.toUIMessageStreamResponse({ headers: cors(request) })
297
+ const { payload } = await jwtVerify(auth.slice(7), jwks, { issuer });
298
+ if (!payload.sub) {
299
+ return new Response("Unauthorized", {
300
+ status: 401,
301
+ headers: cors(request),
302
+ });
303
+ }
304
+ userId = payload.sub;
283
305
  } catch {
284
306
  return new Response("Unauthorized", {
285
307
  status: 401,
286
308
  headers: cors(request),
287
309
  });
288
310
  }
311
+ // Authorize resource access by userId, then run the agent scoped to that user.
312
+ // ... return result.toUIMessageStreamResponse({ headers: cors(request) })
289
313
  },
290
314
  };
291
315
  ```
292
316
 
293
- Pass the JWKS/issuer URL to the function via its `env` (see [Environment Variables](#environment-variables)). Persist anything you need to keep (generated images, history) in Postgres — module state doesn't survive eviction.
317
+ That snippet is Managed Auth verification. Mint the bearer token with `.token()` (`data.token`) on the default client, or `getSession()` then `data.session.access_token` on `SupabaseAuthAdapter()`. For another identity, pass that app's JWKS URL and issuer through Function `env` (see [Environment Variables](#environment-variables)) and include `audience` only when that token contract requires it. https://neon.com/docs/compute/functions/authentication.md
318
+
319
+ A valid token is not permission to read another user's rows. Exercise two users: each can access their own data; cross-user access is denied. Repeat after restarting the Function against stored rows. A request-supplied owner id cannot grant access.
320
+
321
+ Persist anything you need to keep (generated images, history) in Postgres — module state doesn't survive eviction.
294
322
 
295
323
  ## WebSocket Servers
296
324
 
297
325
  A WebSocket server is the canonical Functions workload: a long-running handler holds connections open in-process, with no external state store needed to keep a stream coherent. The connection stays alive as long as bytes flow (15-minute heartbeat, see [Timeouts](#timeouts-and-runtime-limits)).
298
326
 
299
- **Upgrade from inside `fetch`.** Call `upgradeWebSocket(request)` from [`@neon/functions`](https://www.npmjs.com/package/@neon/functions) and return the response it gives you. There is one entrypoint and no WebSocket dependency to install:
327
+ **Upgrade from inside `fetch`.** Call `upgradeWebSocket(request)` from [`@neon/functions`](https://www.npmjs.com/package/@neon/functions) and return the response it gives you. Hono apps use the same primitive via `@neon/functions/hono` (see [Hono](#hono) below). There is one entrypoint and no WebSocket dependency to install:
300
328
 
301
329
  ```typescript
302
330
  import { upgradeWebSocket } from "@neon/functions";
@@ -319,7 +347,7 @@ export default {
319
347
  Three rules that matter:
320
348
 
321
349
  - **Return `response` unchanged.** A `101` can't be built as a plain `Response` (the fetch spec caps constructed responses at 200–599), so the runtime hands back an object carrying the pending upgrade. `clone()`, or rebuilding it with `new Response(res.body, res)` as response-rewriting middleware does, discards the upgrade and fails the request.
322
- - **Refuse a handshake by returning an ordinary `Response`.** A `401`, `403` or `404` is relayed to the client as-is. That is how you gate a socket.
350
+ - **Refuse a handshake by returning an ordinary `Response`.** Return a `401`, `403`, or `404` from `fetch`, before you upgrade, to gate a socket. A browser client can't read why a handshake was refused; it sees only a generic connection failure, not your status or body. Refuse to keep clients out, but send any detail the client needs over a separate authenticated request.
323
351
  - **`binaryType` defaults to `"arraybuffer"`**, not the browser's `"blob"`. `event.data` is a `string` for text frames and an `ArrayBuffer` for binary ones, so branch on `typeof`.
324
352
 
325
353
  **With auth.** Browsers can't set headers on a WebSocket, so authenticate with a `?token=` query param (verify it the same way as the [agent backend](#functions-as-an-agent-backend-nextjs-and-similar-frameworks): `jwtVerify` against your JWKS) and refuse before upgrading:
@@ -354,37 +382,52 @@ export default {
354
382
 
355
383
  **Subprotocols.** Pass `{ protocol }` to select one the client offered; it is echoed in `Sec-WebSocket-Protocol` and exposed as `socket.protocol`. Selecting one the client did not offer throws a `TypeError`. Omit it and no protocol is negotiated. No extensions are negotiated either — `socket.extensions` is always `""` and `permessage-deflate` is not available.
356
384
 
357
- **Hono.** Nothing special is needed: `upgradeWebSocket` takes a `Request`, so call it inside a route with `c.req.raw` and return the response. Auth and everything else is ordinary middleware.
385
+ **Hono.** Use `upgradeWebSocket` from `@neon/functions/hono` — the same primitive as Hono's own WebSocket helper, with no `ws` dependency and not the deprecated `@hono/node-ws`. Auth is ordinary middleware; gate upgrade requests before `next()`:
358
386
 
359
387
  ```typescript
360
388
  // src/index.ts
361
389
  import { Hono } from "hono";
362
- import { upgradeWebSocket } from "@neon/functions";
390
+ import { upgradeWebSocket } from "@neon/functions/hono";
363
391
 
364
- const app = new Hono();
392
+ const clients = new Set<WebSocket>();
365
393
 
366
- app.get("/", (c) => c.text("ok"));
394
+ const app = new Hono<{ Variables: { userId: string } }>();
367
395
 
368
- app.get("/ws", async (c) => {
396
+ app.use("/ws", async (c, next) => {
369
397
  const identity = await verifyToken(c.req.query("token"));
370
398
  if (!identity) return c.text("Unauthorized", 401);
371
-
372
- const { socket, response } = upgradeWebSocket(c.req.raw);
373
- socket.addEventListener("open", () => socket.send("welcome"));
374
- socket.addEventListener("message", (event) =>
375
- socket.send(`echo: ${event.data}`),
376
- );
377
- return response;
399
+ c.set("userId", identity.id);
400
+ await next();
378
401
  });
379
402
 
380
- export default { fetch: (request: Request) => app.fetch(request) };
403
+ app.get(
404
+ "/ws",
405
+ upgradeWebSocket((c) => ({
406
+ onOpen(_event, ws) {
407
+ clients.add(ws.raw);
408
+ ws.send("welcome");
409
+ },
410
+ onClose(_event, ws) {
411
+ clients.delete(ws.raw);
412
+ },
413
+ onMessage(event, ws) {
414
+ ws.send(`echo: ${event.data}`);
415
+ },
416
+ })),
417
+ );
418
+
419
+ export default app;
381
420
  ```
382
421
 
422
+ Connect from the browser with the function's `wss://` URL (from `neon functions get <slug>`), for example `new WebSocket("wss://<branch>-<slug>.compute.<region>.aws.neon.tech/ws?token=<jwt>")`. Reconnect on close — isolates are evictable and idle connections may be terminated after 15 minutes.
423
+
424
+ Do not put `cors()` on the upgrade route, and do not read `c.res` before `await next()` or call `c.header()` after it — both rebuild the `101` and break the upgrade. See `@neon/functions` README for the full middleware table.
425
+
383
426
  ### Heartbeat (keep the socket alive)
384
427
 
385
428
  A connection stays open **only while bytes flow**: Neon evicts a silent stream after 15 minutes ([Timeouts and Runtime Limits](#timeouts-and-runtime-limits)), and intermediary proxies / load balancers are usually far stricter (often tens of seconds). Don't rely on the app being chatty enough — send a periodic keepalive from the server so the socket never goes quiet.
386
429
 
387
- The standard `WebSocket` interface has no `ping()`, so send an application-level message the client ignores:
430
+ The standard `WebSocket` interface has no `ping()`, so send an application-level message the client filters out:
388
431
 
389
432
  ```typescript
390
433
  const HEARTBEAT_MS = 25_000; // comfortably under proxy idle timeouts
@@ -397,7 +440,7 @@ const beat = setInterval(() => {
397
440
  beat.unref?.();
398
441
  ```
399
442
 
400
- The client should skip these when handling messages. The server does answer a client-sent ping frame with a pong automatically, so a browser client can drive the heartbeat instead if you'd rather not filter messages.
443
+ The client skips these when handling messages. There is no protocol-level shortcut here: the standard `WebSocket` from `upgradeWebSocket` has no `ping()`, and a browser can't send ping frames from JavaScript, so an application-level message is the only keepalive a browser client can use. (A Node `ws` client can send ping frames, and the server auto-replies with a pong, but a browser can't.)
401
444
 
402
445
  ### Keeping clients in sync across isolates (do not skip this)
403
446
 
@@ -408,26 +451,44 @@ Module state doesn't survive eviction anyway, so **Postgres is the shared source
408
451
  **1. Poll Postgres — the default, and the only option that keeps Scale to Zero.** Each isolate re-reads the shared state (or rows past a cursor) on a short interval and pushes changes to its own clients. One query per isolate per tick (not per client), and none when the isolate has no clients — so an idle compute still suspends.
409
452
 
410
453
  ```typescript
411
- let lastId = 0;
412
- const poller = setInterval(async () => {
413
- if (clients.size === 0) return; // no clients here → no query → compute can scale to zero
414
- const { rows } = await pool.query(
415
- "SELECT id, payload FROM events WHERE id > $1 ORDER BY id",
416
- [lastId],
417
- );
418
- for (const { id, payload } of rows) {
419
- lastId = id;
420
- for (const socket of clients) {
421
- if (socket.readyState === socket.OPEN) socket.send(payload);
454
+ let lastId = "0"; // bigint id, so a string
455
+ let polling = false;
456
+
457
+ async function poll() {
458
+ if (polling || clients.size === 0) return; // guard overlap; no clients → no query → compute can scale to zero
459
+ polling = true;
460
+ try {
461
+ const { rows } = await pool.query(
462
+ "SELECT id, payload FROM events WHERE id > $1 ORDER BY id",
463
+ [lastId],
464
+ );
465
+ for (const { id, payload } of rows) {
466
+ lastId = id;
467
+ for (const socket of clients) {
468
+ if (socket.readyState === socket.OPEN) socket.send(payload);
469
+ }
422
470
  }
471
+ } catch (err) {
472
+ console.error("[poll]", err);
473
+ } finally {
474
+ polling = false;
423
475
  }
424
- }, 1000);
425
- poller.unref?.();
476
+ }
477
+
478
+ // Seed from the latest id so a fresh isolate sends only new rows, not the whole table, then poll.
479
+ pool
480
+ .query("SELECT coalesce(max(id), 0)::text AS id FROM events")
481
+ .then((seed) => {
482
+ lastId = seed.rows[0].id;
483
+ })
484
+ .catch((err) => console.error("[seed]", err))
485
+ .finally(() => setInterval(poll, 1000).unref?.());
426
486
  ```
427
487
 
428
488
  - **Latency:** up to the interval (~1s) — fine for counters, chat, and dashboards.
429
489
  - **Scaling:** database load grows with the number of live isolates, not clients. Keep the cursor on an indexed `serial`/`bigserial` PK and the interval sane.
430
490
  - **Scale to Zero:** ✅ preserved — polling stops when no clients are connected, so the compute suspends on its normal timer.
491
+ - **Ordering:** `WHERE id > cursor` can skip a row that commits out of sequence: a transaction that took a lower id but commits after a higher one is already behind the cursor, so the poll never returns it. For a broadcast feed occasional loss is usually fine; when you need every row, use `LISTEN`/`NOTIFY` or poll by `created_at` with a small overlap window and dedupe by id.
431
492
 
432
493
  **2. `LISTEN`/`NOTIFY` — lowest latency, but requires disabling Scale to Zero.** Each isolate `LISTEN`s on a channel over a dedicated **unpooled** connection; broadcasting is `NOTIFY`, so every isolate (including the sender's) re-pushes to its sockets. Near-instant — but the listener holds an idle connection that **does not count as active**, so [Scale to Zero](https://neon.com/docs/introduction/scale-to-zero) suspends the compute and drops it, silently killing the feed. Only use it on an **always-on** compute (Scale to Zero disabled — a paid-plan setting).
433
494
 
@@ -442,7 +503,7 @@ const CHANNEL = "chat_events";
442
503
  // One dedicated DIRECT connection per isolate, just to receive events.
443
504
  // Use DATABASE_URL_UNPOOLED — LISTEN needs a real session, not a pooled one.
444
505
  // Don't call attachDatabasePool here: it would silence the idle drop that killed the feed.
445
- // An error listener keeps the isolate alive; the feed stays down until the isolate restarts.
506
+ // The error listener keeps the process alive; reconnect the client on error in production (omitted here).
446
507
  const listener = new Client({
447
508
  connectionString: process.env.DATABASE_URL_UNPOOLED,
448
509
  });
@@ -508,16 +569,19 @@ When you only need **server → client** streaming (live counters, notifications
508
569
  // src/index.ts — minimal SSE endpoint
509
570
  const encoder = new TextEncoder();
510
571
  export default {
511
- fetch: () =>
512
- new Response(
572
+ fetch: () => {
573
+ let t: ReturnType<typeof setInterval>;
574
+ return new Response(
513
575
  new ReadableStream<Uint8Array>({
514
576
  start(controller) {
515
577
  controller.enqueue(encoder.encode("data: hello\n\n"));
516
- const t = setInterval(
578
+ t = setInterval(
517
579
  () => controller.enqueue(encoder.encode(": ping\n\n")),
518
580
  25_000,
519
581
  );
520
- return () => clearInterval(t); // fires when the client disconnects
582
+ },
583
+ cancel() {
584
+ clearInterval(t); // fires when the client disconnects
521
585
  },
522
586
  }),
523
587
  {
@@ -526,12 +590,19 @@ export default {
526
590
  "Cache-Control": "no-cache, no-transform",
527
591
  },
528
592
  },
529
- ),
593
+ );
594
+ },
530
595
  };
531
596
  ```
532
597
 
533
598
  The same rules as WebSockets apply. **Heartbeat:** a stream stays open only while bytes flow — Neon's window is 15 minutes ([Timeouts and Runtime Limits](#timeouts-and-runtime-limits)) but proxies are usually far stricter, so emit a `: ping\n\n` comment every ~25–30s (shown above) to keep idle streams from being dropped. Keep state in Postgres, and fan out across isolates using one of the [sync strategies](#keeping-clients-in-sync-across-isolates-do-not-skip-this) (hold a `Set` of stream controllers and `enqueue` to each). `EventSource` is GET-only and can't set headers, so authenticate with a `?token=` query param or cookie, exactly like the WebSocket case. [references/sse.md](https://neon.com/docs/ai/skills/neon-functions/references/sse.md) has the full pattern — Hono variant, cross-isolate fan-out, wire format, client, and caveats.
534
599
 
600
+ ## Function Triggers
601
+
602
+ A Function Trigger POSTs JSON to your function on a cron (`schedule`) or when an object is created in Object Storage (`storage_object_created`). Declare it in `neon.ts`, apply with `neon deploy`, and authenticate the delivery with `parseTriggerDelivery` (`@neon/functions/triggers`). `parseTrigger` (Hono) and `parseTriggerInvocation` stay schedule-only. Prefer `neon.ts`; CLI and the Neon MCP trigger tools (`list_triggers`, `create_trigger`, …) are the backup.
603
+
604
+ Trigger routes must not require a user JWT or `X-Secret`; Neon POSTs to the native URL without those. Production caller shapes: [references/production-hardening.md](references/production-hardening.md). Full field list, CLI, MCP, payload, inheritance, and both handler shapes: [references/function-triggers.md](references/function-triggers.md).
605
+
535
606
  ## MCP Servers
536
607
 
537
608
  An [MCP](https://modelcontextprotocol.io) server is a natural Functions workload: a long-running HTTP handler that exposes tools to AI clients (Cursor, Claude, ChatGPT, agents), with those tools reading and writing the branch's Postgres right next to the compute. MCP's **streamable HTTP transport** is a plain `POST`/`GET` on a single endpoint (conventionally `/mcp`), so it maps onto a function's `fetch` handler with no `upgrade` method or extra protocol.
@@ -546,7 +617,7 @@ app.all("/mcp", async (c) => {
546
617
  });
547
618
  ```
548
619
 
549
- Because the function's URL is public, **authenticate before connecting the transport** — [Better Auth](https://better-auth.com) covers both OAuth (its MCP plugin makes your app the authorization server so third-party clients self-authorize per the MCP spec) and a simpler API-key / session-JWT check for your own callers. [references/mcp.md](https://neon.com/docs/ai/skills/neon-functions/references/mcp.md) has the full pattern — server with Postgres-backed tools via Drizzle, both Better Auth auth options, and testing with `mcporter` / `add-mcp`.
620
+ Because the function's URL is public, **authenticate before connecting the transport** — [Better Auth](https://better-auth.com) covers both OAuth (its MCP plugin makes your app the authorization server so third-party clients self-authorize per the MCP spec) and a simpler API-key / session-JWT check for your own callers. Public-consumer edge protection: [references/production-hardening.md](references/production-hardening.md). [references/mcp.md](https://neon.com/docs/ai/skills/neon-functions/references/mcp.md) has the full pattern — server with Postgres-backed tools via Drizzle, both Better Auth auth options, and testing with `mcporter` / `add-mcp`.
550
621
 
551
622
  ## Integrations and Observability
552
623
 
@@ -577,4 +648,8 @@ The Neon documentation is the source of truth and Functions is evolving rapidly,
577
648
  - https://neon.com/docs/compute/functions/environment-variables.md
578
649
  - https://neon.com/docs/compute/functions/reference/neon-ts.md
579
650
  - https://neon.com/docs/compute/functions/reference/runtime-limits.md
580
- - https://neon.com/docs/compute/functions/preview-access.md
651
+ - https://neon.com/docs/compute/functions/authentication.md
652
+ - https://neon.com/docs/compute/functions/custom-domains.md
653
+ - https://neon.com/docs/cli/triggers.md
654
+ - [references/function-triggers.md](references/function-triggers.md)
655
+ - [references/production-hardening.md](references/production-hardening.md)
@@ -15,12 +15,10 @@ The agent needs the AI Gateway (and, for the image example, an Object Storage bu
15
15
  import { defineConfig } from "@neon/config/v1";
16
16
 
17
17
  export default defineConfig({
18
- preview: {
19
- aiGateway: true,
20
- buckets: { images: {} },
21
- functions: {
22
- agent: { name: "ai agent", source: "src/index.ts" },
23
- },
18
+ aiGateway: true,
19
+ buckets: { images: {} },
20
+ functions: {
21
+ agent: { name: "ai agent", source: "src/index.ts" },
24
22
  },
25
23
  });
26
24
  ```