vybekiit 0.7.33 → 0.7.35
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.
- package/dist/bin.js +818 -92
- package/dist/global-skills/eas-app-stores/SKILL.md +2 -2
- package/dist/global-skills/eas-hosting/SKILL.md +2 -2
- package/dist/global-skills/eas-observe/SKILL.md +7 -15
- package/dist/global-skills/eas-observe/references/queries.md +51 -10
- package/dist/global-skills/eas-observe/references/setup.md +60 -7
- package/dist/global-skills/eas-simulator/SKILL.md +2 -2
- package/dist/global-skills/eas-simulator/references/run-your-app.md +2 -0
- package/dist/global-skills/eas-update/SKILL.md +2 -2
- package/dist/global-skills/eas-update-insights/SKILL.md +2 -2
- package/dist/global-skills/eas-workflows/SKILL.md +2 -2
- package/dist/global-skills/expo-animation/SKILL.md +2 -2
- package/dist/global-skills/expo-app-clip/SKILL.md +2 -2
- package/dist/global-skills/expo-brownfield/SKILL.md +2 -2
- package/dist/global-skills/expo-data-fetching/SKILL.md +2 -2
- package/dist/global-skills/expo-design-system/SKILL.md +2 -2
- package/dist/global-skills/expo-dev-client/SKILL.md +4 -2
- package/dist/global-skills/expo-dom/SKILL.md +2 -2
- package/dist/global-skills/expo-examples/SKILL.md +2 -2
- package/dist/global-skills/expo-migrate-module/SKILL.md +2 -2
- package/dist/global-skills/expo-module/SKILL.md +2 -2
- package/dist/global-skills/expo-native-ui/SKILL.md +2 -2
- package/dist/global-skills/expo-overview/SKILL.md +9 -4
- package/dist/global-skills/expo-overview/references/launch-without-dev-menu.md +24 -0
- package/dist/global-skills/expo-project-structure/SKILL.md +2 -2
- package/dist/global-skills/expo-router/SKILL.md +2 -2
- package/dist/global-skills/expo-ui/SKILL.md +2 -2
- package/dist/global-skills/expo-upgrade/SKILL.md +2 -2
- package/dist/global-skills/expo-web-to-native/SKILL.md +2 -2
- package/dist/global-skills/expo-web-to-native/references/verify-on-device.md +1 -1
- package/dist/global-skills/firebase-app-hosting-basics/SKILL.md +16 -3
- package/dist/global-skills/firebase-app-hosting-basics/references/cli_commands.md +10 -12
- package/dist/global-skills/firebase-app-hosting-basics/references/configuration.md +2 -1
- package/dist/global-skills/firebase-basics/SKILL.md +6 -4
- package/dist/global-skills/firebase-basics/references/web_setup.md +3 -3
- package/dist/global-skills/instrument-feature-flags/references/adding-feature-flag-code.md +81 -333
- package/dist/global-skills/instrument-feature-flags/references/android.md +19 -13
- package/dist/global-skills/instrument-feature-flags/references/api.md +17 -13
- package/dist/global-skills/instrument-feature-flags/references/best-practices.md +35 -35
- package/dist/global-skills/instrument-feature-flags/references/django.md +120 -72
- package/dist/global-skills/instrument-feature-flags/references/dotnet.md +48 -102
- package/dist/global-skills/instrument-feature-flags/references/elixir.md +4 -10
- package/dist/global-skills/instrument-feature-flags/references/flask.md +55 -39
- package/dist/global-skills/instrument-feature-flags/references/flutter.md +19 -13
- package/dist/global-skills/instrument-feature-flags/references/go.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/ios.md +19 -13
- package/dist/global-skills/instrument-feature-flags/references/java.md +4 -12
- package/dist/global-skills/instrument-feature-flags/references/laravel.md +18 -16
- package/dist/global-skills/instrument-feature-flags/references/next-js.md +44 -54
- package/dist/global-skills/instrument-feature-flags/references/nodejs.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/php.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/python.md +22 -14
- package/dist/global-skills/instrument-feature-flags/references/react-native.md +18 -13
- package/dist/global-skills/instrument-feature-flags/references/react.md +21 -14
- package/dist/global-skills/instrument-feature-flags/references/ruby-on-rails.md +31 -68
- package/dist/global-skills/instrument-feature-flags/references/ruby.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/rust.md +10 -34
- package/dist/global-skills/instrument-feature-flags/references/usage.md +94 -114
- package/dist/global-skills/instrument-feature-flags/references/web.md +21 -13
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-android.md +7 -7
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-expo.md +2 -2
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-fastapi.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-flask.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-laravel.md +2 -2
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-php.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-python.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-swift.md +4 -4
- package/dist/global-skills/instrument-product-analytics/references/android.md +64 -109
- package/dist/global-skills/instrument-product-analytics/references/angular.md +32 -28
- package/dist/global-skills/instrument-product-analytics/references/astro.md +29 -34
- package/dist/global-skills/instrument-product-analytics/references/configuration.md +27 -42
- package/dist/global-skills/instrument-product-analytics/references/django.md +120 -72
- package/dist/global-skills/instrument-product-analytics/references/dotnet.md +48 -102
- package/dist/global-skills/instrument-product-analytics/references/elixir.md +25 -50
- package/dist/global-skills/instrument-product-analytics/references/flask.md +55 -39
- package/dist/global-skills/instrument-product-analytics/references/flutter.md +94 -96
- package/dist/global-skills/instrument-product-analytics/references/go.md +39 -77
- package/dist/global-skills/instrument-product-analytics/references/identify-users.md +24 -26
- package/dist/global-skills/instrument-product-analytics/references/ios.md +22 -22
- package/dist/global-skills/instrument-product-analytics/references/laravel.md +18 -16
- package/dist/global-skills/instrument-product-analytics/references/next-js.md +44 -54
- package/dist/global-skills/instrument-product-analytics/references/nuxt-js-3-6.md +32 -34
- package/dist/global-skills/instrument-product-analytics/references/nuxt-js.md +36 -36
- package/dist/global-skills/instrument-product-analytics/references/php.md +42 -87
- package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +15 -12
- package/dist/global-skills/instrument-product-analytics/references/python.md +106 -154
- package/dist/global-skills/instrument-product-analytics/references/react-native.md +97 -176
- package/dist/global-skills/instrument-product-analytics/references/react-router-v6.md +29 -40
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-data-mode.md +29 -38
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +29 -40
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +32 -37
- package/dist/global-skills/instrument-product-analytics/references/ruby-on-rails.md +31 -68
- package/dist/global-skills/instrument-product-analytics/references/ruby.md +40 -96
- package/dist/global-skills/instrument-product-analytics/references/svelte.md +34 -34
- package/dist/global-skills/instrument-product-analytics/references/tanstack-start.md +19 -19
- package/dist/global-skills/instrument-product-analytics/references/usage.md +94 -114
- package/dist/global-skills/instrument-product-analytics/references/vue-js.md +33 -45
- package/dist/global-skills/manifest.json +2 -1
- package/dist/global-skills/mongodb-search-and-ai/SKILL.md +40 -22
- package/dist/global-skills/mongodb-search-and-ai/references/automated-embedding.md +8 -2
- package/dist/global-skills/mongodb-search-and-ai/references/quick-start.md +725 -0
- package/dist/global-skills/mongodb-search-and-ai/scripts/quickstart_complete.py +386 -0
- package/dist/global-skills/neon/SKILL.md +15 -10
- package/dist/global-skills/neon/references/claimable-neon.md +2 -0
- package/dist/global-skills/neon-functions/SKILL.md +12 -11
- package/dist/global-skills/neon-functions/references/sse.md +2 -2
- package/dist/global-skills/neon-object-storage/SKILL.md +5 -4
- package/dist/global-skills/neon-postgres/SKILL.md +4 -1
- package/dist/global-skills/neon-realtime/SKILL.md +207 -0
- package/dist/global-skills/neon-realtime/references/mutations.md +743 -0
- package/dist/global-skills/neon-realtime/references/queries.md +509 -0
- package/dist/global-skills/neon-realtime/references/reactivity.md +407 -0
- package/dist/global-skills/neon-realtime/references/ssr.md +695 -0
- package/dist/global-skills/neon-realtime/references/subscribing.md +485 -0
- package/dist/global-skills/resend/SKILL.md +4 -2
- package/dist/global-skills/resend/references/inboxes.md +377 -0
- package/dist/global-skills/resend/references/webhooks.md +9 -0
- package/dist/global-skills/stripe-best-practices/SKILL.md +1 -1
- package/dist/global-skills/stripe-best-practices/references/connect.md +1 -1
- package/dist/global-skills/stripe-best-practices/references/security.md +9 -9
- package/dist/global-skills/vybekiitReferences/backend/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/backend/agent/goal-routes.json +303 -18
- package/dist/global-skills/vybekiitReferences/extension/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/extension/agent/goal-routes.json +352 -18
- package/dist/global-skills/vybekiitReferences/mobile/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/mobile/agent/goal-routes.json +413 -22
- package/dist/global-skills/vybekiitReferences/spa/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/spa/agent/goal-routes.json +391 -21
- package/dist/global-skills/vybekiitReferences/web/AGENTS.md +14 -2
- package/dist/global-skills/vybekiitReferences/web/agent/goal-routes.json +490 -32
- package/package.json +8 -8
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# /// script
|
|
3
|
+
# dependencies = [
|
|
4
|
+
# "pymongo>=4.6.0",
|
|
5
|
+
# ]
|
|
6
|
+
# ///
|
|
7
|
+
|
|
8
|
+
# MongoDB Search Quickstart — Complete Script
|
|
9
|
+
# ─────────────────────────────────────────────────────────────
|
|
10
|
+
# Written for the Atlas `sample_mflix.movies` sample collection. The
|
|
11
|
+
# schema is hard-coded throughout: the `plot`, `genres`, and `title`
|
|
12
|
+
# fields, the index definitions, and the sample query text.
|
|
13
|
+
#
|
|
14
|
+
# The connection string comes from the environment: set MONGODB_URI, or
|
|
15
|
+
# MDB_MCP_CONNECTION_STRING, which the MongoDB MCP server already uses.
|
|
16
|
+
#
|
|
17
|
+
# To run against your own data, change the two values below AND
|
|
18
|
+
# update the index definitions, `$project` stages, and query strings
|
|
19
|
+
# to match your own field names.
|
|
20
|
+
|
|
21
|
+
DB_NAME = "sample_mflix"
|
|
22
|
+
COLLECTION_NAME = "movies"
|
|
23
|
+
|
|
24
|
+
# Index names. The walkthrough uses these defaults, but creates `<name>_2` when
|
|
25
|
+
# the default is already taken by an incompatible definition. If that happened,
|
|
26
|
+
# set the matching constant to the name it created, so this script reuses that
|
|
27
|
+
# index instead of stopping on the conflicting one.
|
|
28
|
+
SEMANTIC_INDEX_NAME = "quickstart_semantic"
|
|
29
|
+
TEXT_INDEX_NAME = "quickstart_text"
|
|
30
|
+
AUTOCOMPLETE_INDEX_NAME = "quickstart_autocomplete"
|
|
31
|
+
|
|
32
|
+
INDEX_WAIT_TIMEOUT_SECONDS = 600
|
|
33
|
+
|
|
34
|
+
# ─────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
import os
|
|
37
|
+
import time
|
|
38
|
+
from pymongo import MongoClient
|
|
39
|
+
from pymongo.operations import SearchIndexModel
|
|
40
|
+
|
|
41
|
+
CONNECTION_STRING = (os.environ.get("MONGODB_URI")
|
|
42
|
+
or os.environ.get("MDB_MCP_CONNECTION_STRING"))
|
|
43
|
+
|
|
44
|
+
if not CONNECTION_STRING:
|
|
45
|
+
raise SystemExit("\n ERROR: no connection string. Set MONGODB_URI (or"
|
|
46
|
+
" MDB_MCP_CONNECTION_STRING) to your cluster's SRV"
|
|
47
|
+
" string, then rerun.")
|
|
48
|
+
|
|
49
|
+
client = MongoClient(CONNECTION_STRING)
|
|
50
|
+
db = client[DB_NAME]
|
|
51
|
+
collection = db[COLLECTION_NAME]
|
|
52
|
+
|
|
53
|
+
def fail(message):
|
|
54
|
+
print(f"\n ERROR: {message}")
|
|
55
|
+
client.close()
|
|
56
|
+
raise SystemExit(1)
|
|
57
|
+
|
|
58
|
+
def wait_for_index(name):
|
|
59
|
+
print(f" Waiting for index '{name}' to be ready...", end="", flush=True)
|
|
60
|
+
deadline = time.monotonic() + INDEX_WAIT_TIMEOUT_SECONDS
|
|
61
|
+
while True:
|
|
62
|
+
indexes = list(collection.list_search_indexes(name))
|
|
63
|
+
if not indexes:
|
|
64
|
+
fail(f"Index '{name}' does not exist.")
|
|
65
|
+
status = indexes[0].get("status")
|
|
66
|
+
if status == "READY":
|
|
67
|
+
print(" ready.")
|
|
68
|
+
return
|
|
69
|
+
if status == "STALE":
|
|
70
|
+
fail(f"Index '{name}' is stale because embedding sync is paused. "
|
|
71
|
+
"Free disk space, wait for READY, then rerun.")
|
|
72
|
+
if status == "FAILED":
|
|
73
|
+
fail(f"Index '{name}' failed to build. Check the tier index cap"
|
|
74
|
+
" (3 on Free, 10 on Flex) and the index definition.")
|
|
75
|
+
if time.monotonic() > deadline:
|
|
76
|
+
fail(f"Index '{name}' is still '{status}' after"
|
|
77
|
+
f" {INDEX_WAIT_TIMEOUT_SECONDS}s. Check its status in Atlas,"
|
|
78
|
+
" then rerun.")
|
|
79
|
+
print(".", end="", flush=True)
|
|
80
|
+
time.sleep(5)
|
|
81
|
+
|
|
82
|
+
def covers(expected, actual):
|
|
83
|
+
# True when `actual` contains everything `expected` asks for. Atlas adds
|
|
84
|
+
# its own defaults to a stored definition, so an exact match is too strict.
|
|
85
|
+
if isinstance(expected, dict):
|
|
86
|
+
# A field can be stored as a list of types (a multi-type field), which
|
|
87
|
+
# still satisfies a single expected type.
|
|
88
|
+
if isinstance(actual, list):
|
|
89
|
+
return any(covers(expected, candidate) for candidate in actual)
|
|
90
|
+
return (isinstance(actual, dict)
|
|
91
|
+
and all(k in actual and covers(v, actual[k])
|
|
92
|
+
for k, v in expected.items()))
|
|
93
|
+
if isinstance(expected, list):
|
|
94
|
+
return (isinstance(actual, list)
|
|
95
|
+
and all(any(covers(item, candidate) for candidate in actual)
|
|
96
|
+
for item in expected))
|
|
97
|
+
return expected == actual
|
|
98
|
+
|
|
99
|
+
def check_definition(name, expected):
|
|
100
|
+
indexes = list(collection.list_search_indexes(name))
|
|
101
|
+
if not indexes:
|
|
102
|
+
fail(f"Index '{name}' does not exist.")
|
|
103
|
+
actual = indexes[0].get("latestDefinition", {})
|
|
104
|
+
if not covers(expected, actual):
|
|
105
|
+
fail(f"An index named '{name}' already exists, but its definition does"
|
|
106
|
+
" not match the one this script needs, so the queries below would"
|
|
107
|
+
" fail. An index created by another route (for example the MCP"
|
|
108
|
+
" walkthrough) can omit fields this script queries. Drop"
|
|
109
|
+
f" '{name}' in Atlas and rerun, or point the matching"
|
|
110
|
+
" *_INDEX_NAME constant at the top of this script at a name that"
|
|
111
|
+
f" is free or already correct.\n Existing definition: {actual}")
|
|
112
|
+
|
|
113
|
+
def ensure_index(model, name, definition):
|
|
114
|
+
try:
|
|
115
|
+
collection.create_search_index(model)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
if "already exists" not in str(e):
|
|
118
|
+
fail(f"Could not create index '{name}': {e}")
|
|
119
|
+
print(" Index already exists — checking its definition.")
|
|
120
|
+
check_definition(name, definition)
|
|
121
|
+
wait_for_index(name)
|
|
122
|
+
|
|
123
|
+
def print_results(results, fields=["title", "plot"]):
|
|
124
|
+
for i, doc in enumerate(results, 1):
|
|
125
|
+
print(f"\n {i}. {doc.get('title', 'N/A')}")
|
|
126
|
+
if "score" in doc:
|
|
127
|
+
print(f" Score: {round(doc['score'], 3)}")
|
|
128
|
+
if "plot" in fields and doc.get("plot"):
|
|
129
|
+
print(f" Plot: {doc['plot'][:120]}...")
|
|
130
|
+
if "genres" in doc:
|
|
131
|
+
print(f" Genres: {doc.get('genres', [])}")
|
|
132
|
+
|
|
133
|
+
# ─────────────────────────────────────────────────────────────
|
|
134
|
+
# 1. CREATE AUTO EMBEDDING INDEX (Semantic Search)
|
|
135
|
+
# ─────────────────────────────────────────────────────────────
|
|
136
|
+
print("\n── SEMANTIC SEARCH (Auto Embedding) ──────────────────")
|
|
137
|
+
print("Creating autoEmbed index on 'plot' field...")
|
|
138
|
+
|
|
139
|
+
semantic_definition = {
|
|
140
|
+
"fields": [
|
|
141
|
+
{
|
|
142
|
+
"type": "autoEmbed",
|
|
143
|
+
"modality": "text",
|
|
144
|
+
"path": "plot",
|
|
145
|
+
"model": "voyage-4"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"type": "filter",
|
|
149
|
+
"path": "genres"
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
ensure_index(
|
|
155
|
+
SearchIndexModel(
|
|
156
|
+
definition=semantic_definition,
|
|
157
|
+
name=SEMANTIC_INDEX_NAME,
|
|
158
|
+
type="vectorSearch"
|
|
159
|
+
),
|
|
160
|
+
SEMANTIC_INDEX_NAME,
|
|
161
|
+
semantic_definition
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# Run semantic query
|
|
165
|
+
print("\nQuery: 'a story about growing up'")
|
|
166
|
+
results = list(collection.aggregate([
|
|
167
|
+
{
|
|
168
|
+
"$vectorSearch": {
|
|
169
|
+
"index": SEMANTIC_INDEX_NAME,
|
|
170
|
+
"path": "plot",
|
|
171
|
+
"query": "a story about growing up",
|
|
172
|
+
"numCandidates": 100,
|
|
173
|
+
"limit": 3
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"$project": {
|
|
178
|
+
"_id": 0,
|
|
179
|
+
"title": 1,
|
|
180
|
+
"plot": 1,
|
|
181
|
+
"score": { "$meta": "vectorSearchScore" }
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
]))
|
|
185
|
+
print_results(results)
|
|
186
|
+
|
|
187
|
+
# Run filtered semantic query
|
|
188
|
+
print("\nFiltered query: 'a story about growing up' + Drama only")
|
|
189
|
+
results = list(collection.aggregate([
|
|
190
|
+
{
|
|
191
|
+
"$vectorSearch": {
|
|
192
|
+
"index": SEMANTIC_INDEX_NAME,
|
|
193
|
+
"path": "plot",
|
|
194
|
+
"query": "a story about growing up",
|
|
195
|
+
"filter": { "genres": { "$eq": "Drama" } },
|
|
196
|
+
"numCandidates": 150,
|
|
197
|
+
"limit": 3
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"$project": {
|
|
202
|
+
"_id": 0,
|
|
203
|
+
"title": 1,
|
|
204
|
+
"genres": 1,
|
|
205
|
+
"score": { "$meta": "vectorSearchScore" }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
]))
|
|
209
|
+
print_results(results, fields=["title", "genres"])
|
|
210
|
+
|
|
211
|
+
# ─────────────────────────────────────────────────────────────
|
|
212
|
+
# 2. CREATE TEXT SEARCH INDEX (Keyword Search)
|
|
213
|
+
# ─────────────────────────────────────────────────────────────
|
|
214
|
+
print("\n── KEYWORD SEARCH (Atlas Search) ─────────────────────")
|
|
215
|
+
print("Creating text search index on 'title', 'plot', 'genres'...")
|
|
216
|
+
|
|
217
|
+
text_definition = {
|
|
218
|
+
"mappings": {
|
|
219
|
+
"dynamic": False,
|
|
220
|
+
"fields": {
|
|
221
|
+
"title": { "type": "string" },
|
|
222
|
+
"plot": { "type": "string" },
|
|
223
|
+
"genres": { "type": "token" }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
ensure_index(
|
|
229
|
+
SearchIndexModel(
|
|
230
|
+
definition=text_definition,
|
|
231
|
+
name=TEXT_INDEX_NAME
|
|
232
|
+
),
|
|
233
|
+
TEXT_INDEX_NAME,
|
|
234
|
+
text_definition
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
# Run keyword query
|
|
238
|
+
print("\nKeyword query: 'space adventure'")
|
|
239
|
+
results = list(collection.aggregate([
|
|
240
|
+
{
|
|
241
|
+
"$search": {
|
|
242
|
+
"index": TEXT_INDEX_NAME,
|
|
243
|
+
"text": {
|
|
244
|
+
"query": "space adventure",
|
|
245
|
+
"path": ["title", "plot"]
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"$project": {
|
|
251
|
+
"_id": 0,
|
|
252
|
+
"title": 1,
|
|
253
|
+
"plot": 1,
|
|
254
|
+
"score": { "$meta": "searchScore" }
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{ "$limit": 3 }
|
|
258
|
+
]))
|
|
259
|
+
print_results(results)
|
|
260
|
+
|
|
261
|
+
# Run fuzzy query
|
|
262
|
+
print("\nFuzzy query: 'sapce adventre' (intentional typos)")
|
|
263
|
+
results = list(collection.aggregate([
|
|
264
|
+
{
|
|
265
|
+
"$search": {
|
|
266
|
+
"index": TEXT_INDEX_NAME,
|
|
267
|
+
"text": {
|
|
268
|
+
"query": "sapce adventre",
|
|
269
|
+
"path": ["title", "plot"],
|
|
270
|
+
"fuzzy": { "maxEdits": 1 }
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"$project": {
|
|
276
|
+
"_id": 0,
|
|
277
|
+
"title": 1,
|
|
278
|
+
"score": { "$meta": "searchScore" }
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
{ "$limit": 3 }
|
|
282
|
+
]))
|
|
283
|
+
print_results(results, fields=["title"])
|
|
284
|
+
|
|
285
|
+
# Autocomplete needs 'title' typed as autocomplete, which the text index does
|
|
286
|
+
# not provide. Use a dedicated index, matching the walkthrough's MCP route.
|
|
287
|
+
print("\nCreating autocomplete index on 'title'...")
|
|
288
|
+
|
|
289
|
+
autocomplete_definition = {
|
|
290
|
+
"mappings": {
|
|
291
|
+
"dynamic": False,
|
|
292
|
+
"fields": {
|
|
293
|
+
"title": { "type": "autocomplete", "tokenization": "edgeGram" }
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
ensure_index(
|
|
299
|
+
SearchIndexModel(
|
|
300
|
+
definition=autocomplete_definition,
|
|
301
|
+
name=AUTOCOMPLETE_INDEX_NAME
|
|
302
|
+
),
|
|
303
|
+
AUTOCOMPLETE_INDEX_NAME,
|
|
304
|
+
autocomplete_definition
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
# Run autocomplete
|
|
308
|
+
print("\nAutocomplete query: 'inc'")
|
|
309
|
+
results = list(collection.aggregate([
|
|
310
|
+
{
|
|
311
|
+
"$search": {
|
|
312
|
+
"index": AUTOCOMPLETE_INDEX_NAME,
|
|
313
|
+
"autocomplete": { "query": "inc", "path": "title" }
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
{ "$project": { "_id": 0, "title": 1 } },
|
|
317
|
+
{ "$limit": 5 }
|
|
318
|
+
]))
|
|
319
|
+
for doc in results:
|
|
320
|
+
print(f" - {doc['title']}")
|
|
321
|
+
|
|
322
|
+
# ─────────────────────────────────────────────────────────────
|
|
323
|
+
# 3. HYBRID SEARCH ($rankFusion)
|
|
324
|
+
# ─────────────────────────────────────────────────────────────
|
|
325
|
+
print("\n── HYBRID SEARCH ($rankFusion) ───────────────────────")
|
|
326
|
+
print("Query: 'a story about growing up' (semantic 70% + keyword 30%)")
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
results = list(collection.aggregate([
|
|
330
|
+
{
|
|
331
|
+
"$rankFusion": {
|
|
332
|
+
"input": {
|
|
333
|
+
"pipelines": {
|
|
334
|
+
"semanticPipeline": [
|
|
335
|
+
{
|
|
336
|
+
"$vectorSearch": {
|
|
337
|
+
"index": SEMANTIC_INDEX_NAME,
|
|
338
|
+
"path": "plot",
|
|
339
|
+
"query": "a story about growing up",
|
|
340
|
+
"numCandidates": 100,
|
|
341
|
+
"limit": 20
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
],
|
|
345
|
+
"keywordPipeline": [
|
|
346
|
+
{
|
|
347
|
+
"$search": {
|
|
348
|
+
"index": TEXT_INDEX_NAME,
|
|
349
|
+
"text": {
|
|
350
|
+
"query": "coming of age",
|
|
351
|
+
"path": "plot"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
{ "$limit": 20 }
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"combination": {
|
|
360
|
+
"weights": {
|
|
361
|
+
"semanticPipeline": 0.7,
|
|
362
|
+
"keywordPipeline": 0.3
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
{ "$project": { "_id": 0, "title": 1, "plot": 1 } },
|
|
368
|
+
{ "$limit": 5 }
|
|
369
|
+
]))
|
|
370
|
+
print_results(results)
|
|
371
|
+
except Exception as e:
|
|
372
|
+
message = str(e)
|
|
373
|
+
if "Unrecognized pipeline stage name: '$rankFusion'" in message:
|
|
374
|
+
print(" $rankFusion requires MongoDB 8.0+. This cluster does not"
|
|
375
|
+
" support it, so hybrid search was skipped.")
|
|
376
|
+
else:
|
|
377
|
+
fail(f"Hybrid search query failed: {message}")
|
|
378
|
+
|
|
379
|
+
print("\n── Done! ─────────────────────────────────────────────")
|
|
380
|
+
print("This script targets the sample_mflix.movies schema. To use your")
|
|
381
|
+
print("own data, set MONGODB_URI (or MDB_MCP_CONNECTION_STRING), then")
|
|
382
|
+
print("change DB_NAME and COLLECTION_NAME at the top and adjust the")
|
|
383
|
+
print("index definitions, $project stages, and query strings to match")
|
|
384
|
+
print("your own field names.")
|
|
385
|
+
|
|
386
|
+
client.close()
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
name: neon
|
|
3
3
|
description: >-
|
|
4
4
|
Overview of Neon, a complete set of cloud backend primitives around Lakebase
|
|
5
|
-
Postgres: Auth, Object Storage, Functions,
|
|
5
|
+
Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to
|
|
6
6
|
choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or
|
|
7
7
|
MCP server, and follow the branch-first workflow. Use when building an app or
|
|
8
8
|
backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child
|
|
9
9
|
skill neon-postgres wins for an existing DATABASE_URL, SQL, schema, inspect,
|
|
10
10
|
or search. Child skill neon-auth wins for login, users, sessions, identity
|
|
11
|
-
routing, and Managed Better Auth setup.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
routing, and Managed Better Auth setup. Child skill neon-realtime wins for
|
|
12
|
+
live queries in reactive apps and agents. Also use for object storage, S3,
|
|
13
|
+
buckets, serverless functions, function triggers, cron, AI gateway, LLM calls,
|
|
14
|
+
realtime, logs, Loki, Grafana, observability,
|
|
15
|
+
postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.
|
|
15
16
|
metadata:
|
|
16
17
|
source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon
|
|
17
18
|
disable-model-invocation: true
|
|
@@ -19,7 +20,7 @@ disable-model-invocation: true
|
|
|
19
20
|
|
|
20
21
|
# Neon
|
|
21
22
|
|
|
22
|
-
Neon is a complete set of cloud backend primitives around Lakebase Postgres, from Databricks — Lakebase Postgres, Auth (managed Better Auth), long-running Functions, Object Storage,
|
|
23
|
+
Neon is a complete set of cloud backend primitives around Lakebase Postgres, from Databricks — Lakebase Postgres, Auth (managed Better Auth), long-running Functions, Object Storage, an AI Gateway, and Realtime live queries, all instant, branchable, and serverless.
|
|
23
24
|
|
|
24
25
|
**Lakebase Postgres** is the database itself. It is one product, reached two ways: through Neon, with a free plan and the full set of backend primitives above, or through Databricks, alongside the rest of the Databricks suite. Same infrastructure, same features, same engineering team. Call the database Lakebase Postgres, and use "Neon" for the brand and for this access path — not as a name for the database.
|
|
25
26
|
|
|
@@ -36,11 +37,12 @@ Neon bundles several backend primitives for building apps and agents that all br
|
|
|
36
37
|
- **Object Storage** — S3-compatible object storage that branches with your projects.
|
|
37
38
|
- **Functions** — Neon's compute offering: long-running serverless functions that run close to your database, for WebSocket servers, long agent HTTP streams, APIs, and server-sent event servers. A Function Trigger POSTs to a function on a cron.
|
|
38
39
|
- **AI Gateway** — One API for frontier and open-source models, supporting the chat completions API and the responses API, powered by Databricks Unity AI Gateway.
|
|
40
|
+
- **Realtime** (beta) — Makes any SQL query live. Subscribe in realtime to Lakebase Postgres and build reactive apps and agents with type-safe live queries and optimistic mutations.
|
|
39
41
|
- **Data API** — Optional PostgREST-compatible HTTP interface. Use it only when the app already uses PostgREST or a Supabase database client, or is migrating that client. New apps query Postgres from Functions or existing handlers. There is no `neon-data-api` skill; configuration is `dataApi` in `neon.ts` (see [Type-safe config](#type-safe-config-invalid-setups-dont-compile) when you have chosen it).
|
|
40
42
|
|
|
41
43
|
### Region availability
|
|
42
44
|
|
|
43
|
-
Object Storage, Functions,
|
|
45
|
+
Object Storage, Functions, AI Gateway, and Realtime are currently available on projects in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`. Before guiding a user through any of these services, confirm they are working in one of these regions. If not, they will need to create a new project in a supported region.
|
|
44
46
|
|
|
45
47
|
## Architecture: How to Use Neon
|
|
46
48
|
|
|
@@ -64,7 +66,7 @@ Functions have public HTTPS URLs. Verify a JWT or API key at the top of the hand
|
|
|
64
66
|
|
|
65
67
|
Inspect the repo before provisioning.
|
|
66
68
|
|
|
67
|
-
1. Map requested capabilities: login, files, HTTP APIs, LLM calls, SQL.
|
|
69
|
+
1. Map requested capabilities: login, files, HTTP APIs, LLM calls, live data, SQL.
|
|
68
70
|
2. Reuse what is already there: a supplied `DATABASE_URL`, an existing ORM or driver, Better Auth, Clerk or another auth provider, S3 or another object store, an existing `.neon` / `neon.ts`, an existing Data API or PostgREST client.
|
|
69
71
|
3. Select Neon primitives for capabilities that are still undecided.
|
|
70
72
|
4. Provision only when infrastructure is missing: `neon init` / `neon link` / Claimable, then `neon.ts`, then `neon deploy`.
|
|
@@ -82,7 +84,8 @@ New projects are created in AWS regions. Prefer pooled `DATABASE_URL` for applic
|
|
|
82
84
|
| Existing Better Auth, Clerk, Supabase Auth, or another working IdP | Keep it. `neon-auth` only if they ask to migrate |
|
|
83
85
|
| User asked to migrate from Supabase Auth | `neon-auth` (Managed Better Auth; keep `SupabaseAuthAdapter()` call shapes) |
|
|
84
86
|
| Files, uploads, blobs (no existing object store) | Object Storage |
|
|
85
|
-
| HTTP APIs, cron, WebSocket
|
|
87
|
+
| HTTP APIs, cron, custom WebSocket or SSE push, long-running agents | Functions querying Postgres |
|
|
88
|
+
| Live queries for realtime, reactive apps and agents; optimistic mutations | `neon-realtime` (`preview.realtime` in `neon.ts`). Not available on Claimable projects until claimed |
|
|
86
89
|
| LLM calls | AI Gateway |
|
|
87
90
|
| SQL, schema, inspect, search | `neon-postgres` |
|
|
88
91
|
| Existing PostgREST / Supabase database client | Data API (`dataApi` in `neon.ts`) |
|
|
@@ -125,6 +128,7 @@ The skills below live in the [`neondatabase/agent-skills`](https://github.com/ne
|
|
|
125
128
|
| `neon-object-storage` | Storing and serving files (uploads, images, blobs), including branching them with the database. |
|
|
126
129
|
| `neon-functions` | Deploying long-running or streaming serverless functions — APIs, agents, SSE/WebSocket servers, and Function Triggers (cron and object-storage). |
|
|
127
130
|
| `neon-ai-gateway` | Calling an LLM or routing across model providers with one credential, including discovering the branch's servable models at runtime via the OpenAI-compatible `/v1/models` endpoint. |
|
|
131
|
+
| `neon-realtime` | Realtime makes any SQL query live, for realtime, reactive apps and agents: enabling Realtime, sealing queries, React and TanStack DB bindings, SSR, and optimistic mutations. |
|
|
128
132
|
| `neon-postgres-egress-optimizer` | Diagnosing or fixing excessive Postgres egress (network data-transfer) costs in a codebase. |
|
|
129
133
|
|
|
130
134
|
There is no `neon-data-api` skill. Configure `dataApi` in `neon.ts` only for PostgREST / Supabase database-client compatibility or a migration that already depends on it.
|
|
@@ -328,7 +332,7 @@ export default defineConfig({
|
|
|
328
332
|
|
|
329
333
|
### Provision services with neon config
|
|
330
334
|
|
|
331
|
-
Every project ships with Lakebase Postgres; `neon.ts` also declares Auth, Functions, buckets, and the AI Gateway. Data API is a compatibility toggle, not part of a default backend:
|
|
335
|
+
Every project ships with Lakebase Postgres; `neon.ts` also declares Auth, Functions, buckets, and the AI Gateway. Realtime is declared under `preview`. Data API is a compatibility toggle, not part of a default backend:
|
|
332
336
|
|
|
333
337
|
```typescript
|
|
334
338
|
// neon.ts
|
|
@@ -337,6 +341,7 @@ export default defineConfig({
|
|
|
337
341
|
functions: {},
|
|
338
342
|
buckets: {},
|
|
339
343
|
aiGateway: true, // see the neon-ai-gateway skill
|
|
344
|
+
preview: { realtime: true }, // see the neon-realtime skill
|
|
340
345
|
});
|
|
341
346
|
```
|
|
342
347
|
|
|
@@ -38,6 +38,8 @@ export default defineConfig({
|
|
|
38
38
|
neon claim create --service auth --service data-api --env-pull
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
The project is created in `aws-us-east-2` unless you pass `--region-id` (for example `neon claim create --region-id aws-eu-central-1`). Pick the region closest to where the app runs. A project's region cannot change after create.
|
|
42
|
+
|
|
41
43
|
`neon claim create` reads `neon.ts` when it is present. It writes provisioned vars to an existing `.env`, otherwise `.env.local`, and gitignores that file. If `.env` or `.env.local` already has a `DATABASE_URL` (or other Neon-managed keys), pass `--file <path>` or `--no-env-pull`. The identity assertion is the pre-claim credential.
|
|
42
44
|
|
|
43
45
|
Before claim, Postgres is always granted; Auth and the Data API are granted when requested. Functions, Object Storage, and AI Gateway come back with `granted: false` and `reason: "requires_claim"`. The CLI prints those as `denied_capabilities`. Report what you were given. Do not retry or strip them.
|
|
@@ -11,11 +11,10 @@ description: >-
|
|
|
11
11
|
a cron or an object-storage event that POSTs to a function. Triggers include
|
|
12
12
|
"serverless function", "deploy an API", "long-running function",
|
|
13
13
|
"streaming agent", "SSE server", "WebSocket server", "webhook handler",
|
|
14
|
-
"MCP server", "cron", "
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"production hardening".
|
|
14
|
+
"MCP server", "cron", "scheduled function", "object storage trigger",
|
|
15
|
+
"on upload", "function that won't time out", "function logs",
|
|
16
|
+
"Neon Functions", "Neon Compute", "DDoS protection", "rate limiting", and
|
|
17
|
+
"production hardening". For live UIs over database rows, use neon-realtime.
|
|
19
18
|
metadata:
|
|
20
19
|
parent: neon
|
|
21
20
|
source: https://github.com/neondatabase/agent-skills/tree/main/skills/neon-functions
|
|
@@ -453,13 +452,15 @@ beat.unref?.();
|
|
|
453
452
|
|
|
454
453
|
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.)
|
|
455
454
|
|
|
456
|
-
###
|
|
455
|
+
### Fan-out across isolates (do not skip this)
|
|
457
456
|
|
|
458
457
|
Under load the runtime runs **several isolates in parallel, each with its own copy of module state** — so each isolate has its own `clients` set. Broadcasting only to that local set means a client on isolate A never sees an event produced on isolate B, and the feed silently fractures. It's easy to miss: `neon dev` runs a single process (one isolate), so in-process broadcast always _looks_ fine locally but breaks in production, where concurrent connections spread across many isolates.
|
|
459
458
|
|
|
459
|
+
If the data is database rows (live dashboards, feeds, chat over stored messages), use Neon Realtime (the `neon-realtime` skill) instead of hand-rolling fan-out. Using Realtime does not prevent your database from scaling to zero. The strategies below are for push that doesn't come from database rows (presence, typing, LLM streams), and the fallback where Realtime isn't available, such as on Claimable projects until they're claimed.
|
|
460
|
+
|
|
460
461
|
Module state doesn't survive eviction anyway, so **Postgres is the shared source of truth**. Pick a fan-out strategy. In every snippet below, `pool` is a pooled `pg` client and `clients` is this isolate's `Set` of live connections.
|
|
461
462
|
|
|
462
|
-
**1. Poll Postgres — the default, and
|
|
463
|
+
**1. Poll Postgres — the default, and it 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.
|
|
463
464
|
|
|
464
465
|
```typescript
|
|
465
466
|
let lastId = "0"; // bigint id, so a string
|
|
@@ -496,7 +497,7 @@ pool
|
|
|
496
497
|
.finally(() => setInterval(poll, 1000).unref?.());
|
|
497
498
|
```
|
|
498
499
|
|
|
499
|
-
- **Latency:** up to the interval (~1s)
|
|
500
|
+
- **Latency:** up to the interval (~1s).
|
|
500
501
|
- **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.
|
|
501
502
|
- **Scale to Zero:** ✅ preserved — polling stops when no clients are connected, so the compute suspends on its normal timer.
|
|
502
503
|
- **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.
|
|
@@ -540,7 +541,7 @@ function broadcast(event: unknown) {
|
|
|
540
541
|
|
|
541
542
|
**3. External pub/sub (e.g. [Upstash](https://upstash.com) Redis) — best at scale.** For high fan-out, sub-second latency at large connection counts, or multi-region, publish/subscribe through a dedicated broker. Highest throughput, and it doesn't touch Postgres or block Scale to Zero — at the cost of another service to run.
|
|
542
543
|
|
|
543
|
-
**Rule of thumb:** start with **polling** (works with Scale to Zero, no extra infra); switch to `LISTEN`/`NOTIFY` only on always-on compute that needs sub-second latency; move to Redis when fan-out outgrows Postgres.
|
|
544
|
+
**Rule of thumb:** for database rows, use **Neon Realtime**. Otherwise start with **polling** (works with Scale to Zero, no extra infra); switch to `LISTEN`/`NOTIFY` only on always-on compute that needs sub-second latency; move to Redis when fan-out outgrows Postgres.
|
|
544
545
|
|
|
545
546
|
### Client must reconnect
|
|
546
547
|
|
|
@@ -570,7 +571,7 @@ async function connect() {
|
|
|
570
571
|
connect();
|
|
571
572
|
```
|
|
572
573
|
|
|
573
|
-
Together — `upgradeWebSocket` inside `fetch`, JWT auth over `?token=`, cross-isolate fan-out, and client backoff — these compose into a complete
|
|
574
|
+
Together — `upgradeWebSocket` inside `fetch`, JWT auth over `?token=`, cross-isolate fan-out, and client backoff — these compose into a complete WebSocket backend on a single function, for push that doesn't come from database rows (presence, typing, LLM streams) or where Realtime isn't available. For persisted chat, feeds, and other live UIs over database rows, use Neon Realtime (the `neon-realtime` skill).
|
|
574
575
|
|
|
575
576
|
## Server-Sent Events (SSE)
|
|
576
577
|
|
|
@@ -606,7 +607,7 @@ export default {
|
|
|
606
607
|
};
|
|
607
608
|
```
|
|
608
609
|
|
|
609
|
-
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 [
|
|
610
|
+
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 [fan-out strategies](#fan-out-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.
|
|
610
611
|
|
|
611
612
|
## Function Triggers
|
|
612
613
|
|
|
@@ -79,7 +79,7 @@ export default app;
|
|
|
79
79
|
|
|
80
80
|
## Push to every client, across isolates
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
If the data is database rows (live dashboards, feeds, chat over stored messages), use Neon Realtime (the `neon-realtime` skill) instead of hand-rolling fan-out. Otherwise, the fan-out rule is identical to WebSockets ([Fan-out across isolates](../SKILL.md#fan-out-across-isolates-do-not-skip-this)): each isolate keeps its **own** set of open streams, so broadcasting in-process only reaches the clients on that isolate. Hold a `Set` of stream controllers and pick a strategy there — **poll Postgres** by default (keeps Scale to Zero), or `LISTEN`/`NOTIFY` (shown below) for lowest latency on always-on compute. Keep the source-of-truth state in Postgres — module state doesn't survive eviction.
|
|
83
83
|
|
|
84
84
|
```typescript
|
|
85
85
|
import { attachDatabasePool } from "@neon/functions";
|
|
@@ -160,4 +160,4 @@ source.onerror = () => {
|
|
|
160
160
|
- **CORS.** A SPA hits the function cross-origin, so set `Access-Control-Allow-Origin`. `EventSource` sends no credentials by default, so `*` is fine for public streams.
|
|
161
161
|
- **One-way only.** SSE is server → client. For client → server, the browser makes normal `fetch`/`POST` calls (often to the same function); reach for [WebSockets](../SKILL.md#websocket-servers) only when you need bidirectional, low-latency frames.
|
|
162
162
|
|
|
163
|
-
Together — a Hono `fetch` SSE endpoint, cross-isolate fan-out, heartbeat, a counter persisted in Postgres, and a client-only TanStack Router SPA consuming it with `EventSource` — these compose into a complete
|
|
163
|
+
Together — a Hono `fetch` SSE endpoint, cross-isolate fan-out, heartbeat, a counter persisted in Postgres, and a client-only TanStack Router SPA consuming it with `EventSource` — these compose into a complete push backend on a single function, for push that doesn't come from database rows (presence, typing, LLM streams) or where Realtime isn't available. For persisted chat, feeds, and other live UIs over database rows, use Neon Realtime (the `neon-realtime` skill).
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: neon-object-storage
|
|
3
3
|
description: >-
|
|
4
|
-
S3-compatible object storage that branches with your
|
|
5
|
-
|
|
4
|
+
S3-compatible object storage that branches with your database, so each
|
|
5
|
+
branch gets its own copy of the files and the rows that point at them.
|
|
6
|
+
Use when a user wants
|
|
6
7
|
object storage, a bucket, blob/file storage, or somewhere to put uploads,
|
|
7
8
|
images, documents, avatars, or user-generated files for their app or agent —
|
|
8
9
|
especially when they already use (or are setting up) Lakebase Postgres and don't
|
|
@@ -30,7 +31,7 @@ neon skills -s neon -y
|
|
|
30
31
|
|
|
31
32
|
Currently available in `aws-us-east-2`, `aws-us-east-1`, `aws-eu-central-1`, and `aws-ap-southeast-1`.
|
|
32
33
|
|
|
33
|
-
Neon Object Storage is S3-compatible
|
|
34
|
+
Neon Object Storage is S3-compatible file storage built into your Neon project. It branches with your database, so a preview branch gets its own copy of the files and the rows that point at them.
|
|
34
35
|
|
|
35
36
|
Use this skill to help the user store and serve files that branch alongside their database. Deliver a working bucket and upload/download flow, a branch-aware S3 client wired to the injected env vars, or a precise answer from the official Neon docs.
|
|
36
37
|
|
|
@@ -39,7 +40,7 @@ Use this skill to help the user store and serve files that branch alongside thei
|
|
|
39
40
|
Reach for Neon Object Storage for the files an app and its users produce — uploads, attachments, avatars, images, documents, generated assets, backups. It is the default place to put them when the app is already on Neon:
|
|
40
41
|
|
|
41
42
|
- **They already use Lakebase Postgres and don't want a second provider.** One backend, one bill, one CLI, one set of branches — instead of standing up and wiring a separate AWS S3 / R2 / Supabase Storage account. The same Neon credential that backs the database backs storage.
|
|
42
|
-
- **Files must
|
|
43
|
+
- **Files must branch with the database across environments.** Storage branches _together with_ your Postgres data. Fork a branch and the child instantly inherits the parent's buckets and objects at that point in time — copy-on-write, so no data is duplicated. This is what makes agent, dev, preview, and test environments seamless: a preview branch gets a consistent snapshot of _both_ the rows and the files they reference, and writes on the child never touch the parent.
|
|
43
44
|
- **They want safe, throwaway environments.** Upload, overwrite, and delete files in a preview/CI branch without any risk to production data, then drop the branch.
|
|
44
45
|
- **They want standard S3 tooling.** It's built on S3 semantics and speaks the S3 API, so the AWS SDKs, `boto3`, the AWS CLI, and presigned URLs all work — reliable and familiar, with no proprietary client.
|
|
45
46
|
|
|
@@ -6,7 +6,8 @@ description: >-
|
|
|
6
6
|
scale-to-zero, instant restore, read replicas, IP allow lists, logical
|
|
7
7
|
replication, and Lakebase Search. Use when the work is an existing
|
|
8
8
|
DATABASE_URL, SQL, schema, inspect, or search. New backends, Auth, files,
|
|
9
|
-
Functions, and LLM calls go to the parent `neon` skill.
|
|
9
|
+
Functions, and LLM calls go to the parent `neon` skill. Live queries, reactive
|
|
10
|
+
UIs, and realtime data go to `neon-realtime`. Also use for
|
|
10
11
|
"@neondatabase/serverless", "@neondatabase/neon-js", "neon inspect db",
|
|
11
12
|
"semantic search", "vector search", "full-text search", "BM25", or
|
|
12
13
|
"hybrid search".
|
|
@@ -32,6 +33,8 @@ It is the same database whether you reach it through Neon or through Databricks;
|
|
|
32
33
|
|
|
33
34
|
Login, users, sessions, and `@neondatabase/auth` belong in `neon-auth`.
|
|
34
35
|
|
|
36
|
+
Live queries, reactive UIs, and realtime data belong in `neon-realtime`.
|
|
37
|
+
|
|
35
38
|
## Setup Flow
|
|
36
39
|
|
|
37
40
|
### 1. Select the organization and project
|