Repository navigation
Releases
Releases · TerrenoLabs/terreno
58.0.6
Immutable
release. Only release title and notes can be modified.
Fixes
@terreno/aiaccepts@ai-sdk/mcpfrom^1.0.21again. 58.0.5 required^1.0.104, a version published days earlier, which apps enforcing a minimum release age could not resolve. (#1715)
Full Changelog: 58.0.5...58.0.6
58.0.5
Immutable
release. Only release title and notes can be modified.
Fixes
- GPT chat no longer shows an image twice for Gemini image models such as
gemini-3-pro-image. Draft images Gemini returns while it reasons (thought: true) are no longer streamed or saved; the last draft is kept only when a reply has no final image. (#1713) @terreno/aiworks with Gemini and Vertex onai6 again. 58.0.0 moved the Google providers to theai7 line, whose modelsai6 rejects withUnsupported model version v4. The@ai-sdk/google-vertexpeer is back to^4.0.199, the@ai-sdk/providerpeer is removed, and@ai-sdk/mcpis back to^1.0.104. Apps should install@ai-sdk/google-vertex4.x and@ai-sdk/google3.x. (#1713)
Docs & tooling
- Agent skills moved to TerrenoLabs/terreno-skills; the bundled copies are removed. (#1712)
- Codebase audit report and approved implementation plans from the 58.0.4 audit. (#1705, #1707)
Full Changelog: 58.0.4...58.0.5
58.0.4
Immutable
release. Only release title and notes can be modified.
Fixes
- The admin consent form list loads again.
ConsentFormListsorts by-createdand by its data columns, but the/consent-formsrouter did not allow those sorts, so the list returned 400sort-field-not-allowed./consent-formsand/consent-responsesnow allow sorting by the fields their admin metadata marks sortable. (#1702)
Docs & tooling
api-ciruns its tests as one shard: both shards shared the job's single sidecarmongodand database and cleared each other's collections mid-test. (#1703)
Full Changelog: 58.0.3...58.0.4
58.0.3
Immutable
release. Only release title and notes can be modified.
Features
- @terreno/syncdb:
registerTerrenoDevClientDispatch,registerTerrenoDevStorage, andregisterTerrenoDevCommandforterreno-mcp-localdev tooling. (#1682) - @terreno/mcp-server:
read_logsgainsnetworkandnativesources, plus client action dispatch, storage read/write, dev commands, and CDP network capture with header redaction. (#1682)
Fixes
Avatarno longer freezes release builds when its image fails to load. The error handler passed the native event toconsole.warn, and Sentry hung while turning it into a breadcrumb; it now logs only the error message. (#1700)- Mongo filters built from request values reject non-string input with 400 instead of running it as a query operator, and nested-path helpers skip
__proto__,constructor, andprototype. (#1697) - Removed polynomial-time regexes from bearer-header parsing, trailing-slash trimming, prompt references, judge score ranges, AI JSON fence stripping, and the MCP import parser. Dataset schema validation stops at the first error. (#1697)
isTestUsermatchesnang.ioandexample.comas the email domain or a subdomain, not as a substring. MCP OAuth metadata sets an explicit JSON content type. (#1697)
Docs & tooling
fix-code-scanning-alertsskill; CodeQL now also scans pull requests and ignores test files. (#1697)- Package tests run as concurrent
bun test --shardprocesses, and CircleCI pins Bun 1.4.4. (#1699)
Tests & housekeeping
Chore commits
Full Changelog: 58.0.2...58.0.3
58.0.2
Immutable
release. Only release title and notes can be modified.
Fixes
- Patch the remaining critical and high dependency advisories.
@terreno/uinow asks for@react-navigation/native^7.5.1, which drops the vulnerabledecode-uri-component(high) from apps that install it. (#1693) - Docs site: tinypool 2.2.0 (critical, prototype pollution to RCE) and serialize-javascript 7.1.4 (high). (#1690, #1691)
- Dev tooling: Metro's stale nested copy no longer brings in image-size 1.x (high), and rulesync 43.8.0 drops its pinned zod 4.6.5 (high). (#1694, #1695)
Still open: zod 3.25.76 inside Expo's CLI tooling has no fixed 3.x release and waits for an Expo update.
Docs & tooling
- Dependabot opens one security PR per advisory instead of one grouped PR per package block, so each fix can merge on its own. (#1689)
- Compare options for high-churn fields in syncdb (design doc). (#1692)
Tests & housekeeping
Roadmap commits
- Reconcile roadmap entries with implementation plans
- Regenerate ROADMAP.md from the project board
Full Changelog: 58.0.1...58.0.2
58.0.1
Immutable
release. Only release title and notes can be modified.
Added
@terreno/api/sentryexportsSENTRY_V10_DATA_COLLECTION, a Sentry 11dataCollectionsetting that keeps Sentry 10's privacy defaults: no cookies, user info, database query data, HTTP bodies, or AI inputs and outputs, and IP-like headers and query params denied. Pass it toSentry.init({dataCollection}). (#1687)
Fixed
- Patch security advisories in Terreno's dependencies: Better Auth 1.7.7 (critical), multer 2.5.0,
@modelcontextprotocol/node2.1.2,@modelcontextprotocol/sdk1.32.2, markdown-it 14.3.3,@hono/node-server2.1.3, smol-toml 1.9.1, csv-parse 7, plus in-range lockfile fixes (undici, zod, dompurify, body-parser, qs, follow-redirects, and others).bun auditdrops from 111 advisories to 15, all in transitive build and dev tooling. (#1687) - Upgrade to Sentry 11 and Biome 2.5.13. (#1687)
Full Changelog: 58.0.0...58.0.1
58.0.0
Immutable
release. Only release title and notes can be modified.
Breaking
@terreno/admin-spanow server-renders every admin page in the backend's Express process, behind an access gate that runs before anything renders. The first HTML holds the login form, the shell and the screen's data. Upgrade steps: Upgrade to the server-rendered admin SPA.AdminSpaServeApp'sdistDir(and example-backend'sADMIN_SPA_DIST_DIR) now names the export root, which holdsclient/andserver/.build:webno longer writesdist/index.html. Rebuild, and copy the wholedistinto images. Withoutdist/serverthe plugin answers 503 on/console/*.basePathmust equal theexperiments.baseUrlbaked into the bundle (/consoleby default), orregister()throws. Any other mount needsexperiments.baseUrlset inadmin-spa/app.jsonand a rebuild from source; the published package ships only the/consolebuild. Mounting at the site root (basePath: "/") is no longer supported.- Terreno 58 targets Expo SDK 58 (
~58.0.14), React Native0.88.0, and React19.3.0.@terreno/uipeersreact-native0.88.0. Native catalog moves with the SDK:react-native-gesture-handler~3.3.0,react-native-reanimated4.7.1+react-native-worklets0.13.0,react-native-screens~4.30.0,react-native-webview14.0.1,@sentry/react-native~8.28.0,@shopify/flash-list2.3.2,@shopify/react-native-skia2.14.0. Rebuild dev clients and store binaries. - Expo Router 58: set
export const unstable_settings = {initialRouteName}on the layout instead of passinginitialRouteNameto<Slot>/ navigators.SidebarNavigationignores the prop. - Expo Router 58 static rendering: a custom
app/+html.tsxmust renderheadNodesandbodyNodesfromuseServerDocumentContext()(expo-router/html), or exported pages ship without their JavaScript.example-frontendis updated. - React Native 0.88 generated types: type refs as
ViewInstance,TextInstance,ScrollViewInstance, andTextInputInstance(Box.scrollRef,TextField.inputRef,Textref). create-terreno-appscaffolds Expo~58.0.14, React Native0.88.0, and React19.3.0.- The Terreno 58 native module baseline lands in
example-frontendanddemo:@stripe/stripe-react-native0.81.0,react-native-purchasesandreact-native-purchases-ui10.12.2,expo-device,expo-crypto,expo-local-authentication,expo-system-ui, andexpo-build-properties(Android Kotlin 2.2.21 andcompileSdkVersion37 pins). Rebuild every dev client and store binary.react-native-otp-verifyis left out because it does not support the New Architecture. The demo has a hidden Native Modules page that shows each module's version and whether the running binary links it. See the 58.0.0 upgrade note. TerrenoAppturns HTTP rate limiting on by default. OmittingrateLimitnow mounts the limiter with the memory store (auth 20 / 15 min, api 600 / 15 min). PassrateLimit: falseto turn it off. On Cloud Run passrateLimit: {trustProxy: 1}so unauthenticated traffic keys by client IP. See the 58.0.0 upgrade note.@terreno/admin-frontendno longer takes an RTKapi. Theapiprop is removed from every admin component (AdminProvider,AdminShellLayout,AdminHome,AdminModelList,AdminModelTable,AdminModelForm,AdminScreenRouter,ConfigurationScreen,DocumentStorageBrowser,ConsentHistory, comms, jobs, org, consent, and announcement screens, and widget props), and admin hooks drop theirapiargument (useAdminConfig(apiBase),useAdminScripts(apiBase),useAdminRoles(apiBase),useConfigurationApi({basePath}),useDocumentStorageApi(basePath),useConsentHistory(baseUrl),useOrganizationsApi(basePath),useCommsDashboardApi(),useJobsDashboardApi(), and theuseAiObservability*Api()hooks).useAdminApi(api, routePath, modelName)is removed. UseuseAdminModelApi(routePath, modelName), which keeps the same hook names and calls the same/admin/{routePath}URLs through the admin fetch client.AdminApi,EndpointBuilder, and admininjectEndpointsare gone;@reduxjs/toolkitandreact-reduxare no longer peers of admin-frontend.AdminProvideris now the required auth binding for every admin request, including ObjectId and API-only model CRUD. Cookie SPAs passcredentials="same-origin"; embedded apps passapiOriginandgetAuthHeaders. Product screens that reuse admin components wrap them inAdminProvider. See the 58.0.0 upgrade guide.- Removed the legacy RTK realtime path. Use
synconmodelRouterwith@terreno/syncdbfor live collection updates.RealtimeApp,SyncApp, socket auth,sync:delta, and adminadmin:model.changedevents are unchanged. See the 58.0.0 upgrade note. @terreno/api:modelRouterno longer acceptsrealtime(now a TypeScript error), and the change stream no longer emits thesyncwebsocket event. RemovedRealtimeConfig,RealtimeEvent,DocumentSubscription,QuerySubscription,registerRealtime,getRealtimeRegistry,findRegistryEntryByCollection,findRegistryEntryByRoutePath,updateRealtimeRegistryOptions,clearRealtimeRegistry,RealtimeRegistryEntry, the query-subscription store (addQuerySubscription,removeQuerySubscription,removeAllSocketQueries,getQuerySubscriptionsForCollection,computeQueryId,clearQueryStore), andMAX_MODEL_SUBSCRIPTIONS/MAX_DOCUMENT_SUBSCRIPTIONS/MAX_QUERY_SUBSCRIPTIONS. Sockets no longer handlesubscribe:model,subscribe:document, orsubscribe:query.@terreno/rtk: removedrealtimeList,realtimeDocument,setRealtimeSocket,getRealtimeSocket,useSyncConnection, and theRealtimeEventtype. The rest of@terreno/rtk(includinguseSocketConnectionanduseRealtimeDebug) is removed in the same release; seeremove-rtk.md.- Removed
@terreno/rtkand every Redux dependency (@reduxjs/toolkit,react-redux,redux-persist,@rtk-query/codegen-openapi).@terreno/rtkis not published for 58.@terreno/syncdbis the only frontend data, request, and session layer. Followdocs/how-to/migrate-rtk-to-syncdb.md, which maps every removed export to its replacement, and the 58.0.0 upgrade note. @terreno/syncdbadds@terreno/syncdb/api(createApiClient,ApiError), request hooks in@terreno/syncdb/react(ApiClientProvider,useApiQuery,useLazyApiQuery,useApiMutation,useSocketEvent),@terreno/syncdb/config(baseUrl,baseWebsocketsUrl,appHeaders),@terreno/syncdb/auth(createBetterAuthClient,SessionProvider,useSession,jwtAuthAdapter,useJwtAuth, token-expiry helpers),@terreno/syncdb/flags(useFeatureFlags,useTerrenoFeatureFlagson the sync socket),@terreno/syncdb/app(useUpgradeCheck,hasPermission,canOpenAdminPage,installDevConsoleLogger),@terreno/syncdb/mcp(useMCPTools), and@terreno/syncdb/buildNumber.terreno-syncdb-codegen --api-outgenerates typed hooks for every non-synced OpenAPI operation (same names as the RTK codegen), replacing@rtk-query/codegen-openapi.bun run sdkwritesstore/apiSdk.ts.@terreno/uiConsentNavigator,AnnouncementNavigator,useConsentForms,useSubmitConsent,useAnnouncements, anduseAcknowledgeAnnouncementtake a requestclientinstead of an RTKapi.GptHistory(gpt/histories) is a synced collection and keeps its ObjectId_id(no migration).McpServiceToken(mcp/service-tokens, read-only) is a synced collection with String ids; runmcpServiceTokenStringIdsMigration(@terreno/api) before deploying 58 frontends.create-terreno-app, theterreno_bootstrapprompt, and theterreno_generate_screentool scaffold apps without Redux or@terreno/rtk. The terreno-mcp-localget_rtk_statetool, the MCP resourceterreno://docs/rtk, andterreno state --slice rtkare removed; useget_syncdb_stateandterreno state.@terreno/syncdb:useMCPTools(andMCPToolInfo,UseMCPToolsOptions,UseMCPToolsResult) moved from@terreno/syncdb/appto the new@terreno/syncdb/mcpentry point. Changeimport {useMCPTools} from "@terreno/syncdb/app"toimport {useMCPTools} from "@terreno/syncdb/mcp". The hook imports the optional@modelcontextprotocol/clientpeer at the top level, so exporting it from/appbroke every app that imported/appwithout that package installed, including apps scaffolded bycreate-terreno-app, which importinstallDevConsoleLoggerfrom/app.
Added
AdminSpaServeAppoptionsinternalOrigin(where server renders fetch API data, defaulthttp://127.0.0.1:${PORT ?? 4000}) andssrApiPrefixes(API paths a render may fetch). The plugin also serves Expo's root/_expo/loaders/*, withCache-Control: no-store, privateon pages and loader data.@terreno/syncdb:SessionProvider/ session storeinitialSession, and the request client'sprimeQuery(args, data), to start from data a server render already read.@terreno/admin-frontend:AdminRpcSeedandadminRpcSeedKeyseeduseAdminRpcQuerywith server-fetched bodies;buildAdminReadUrl,buildAdminListQueryParams,buildAdminApiListQueryRequestandhomeWidgetUrlsbuild the exact URLs the screens request.DataTablecolumns size themselves whenwidthis omitted. Each auto column starts at the wider of its header and its content (sampled from at most 50 rows, measured with a canvas on web and estimated on native), clamped to 80–360px, and auto columns grow to fill the table's container. Columns that setwidthkeep it.DataTableColumn.widthis now optional.@terreno/syncdbcreateSyncDb({idFormats})mints 24-hex ObjectIds for a collection set to"objectId", so a model that keeps Mongoose's default ObjectId_idcan sync without migrating its ids.mutate()throws on an explicit non-hex id for such a collection.generateObjectIdand theSyncIdFormattype are exported.- Sync
validationnacks carry an...
58.0.0-beta.4
Immutable
release. Only release title and notes can be modified.
Upgrade note: mcp-server/src/docs/upgrades/58.0.0-beta.4.md.
Breaking
@terreno/admin-spanow server-renders every admin page in the backend's Express process, behind an access gate that runs before anything renders. The first HTML holds the login form, the shell and the screen's data. Upgrade steps: Upgrade to the server-rendered admin SPA.AdminSpaServeApp'sdistDir(and example-backend'sADMIN_SPA_DIST_DIR) now names the export root, which holdsclient/andserver/.build:webno longer writesdist/index.html. Rebuild, and copy the wholedistinto images. Withoutdist/serverthe plugin answers 503 on/console/*.basePathmust equal theexperiments.baseUrlbaked into the bundle (/consoleby default), orregister()throws. Any other mount needsexperiments.baseUrlset inadmin-spa/app.jsonand a rebuild from source; the published package ships only the/consolebuild. Mounting at the site root (basePath: "/") is no longer supported.- Terreno 58 targets Expo SDK 58 (
~58.0.14), React Native0.88.0, and React19.3.0.@terreno/uipeersreact-native0.88.0. Native catalog moves with the SDK:react-native-gesture-handler~3.3.0,react-native-reanimated4.7.1+react-native-worklets0.13.0,react-native-screens~4.30.0,react-native-webview14.0.1,@sentry/react-native~8.28.0,@shopify/flash-list2.3.2,@shopify/react-native-skia2.14.0. Rebuild dev clients and store binaries. - Expo Router 58: set
export const unstable_settings = {initialRouteName}on the layout instead of passinginitialRouteNameto<Slot>/ navigators.SidebarNavigationignores the prop. - Expo Router 58 static rendering: a custom
app/+html.tsxmust renderheadNodesandbodyNodesfromuseServerDocumentContext()(expo-router/html), or exported pages ship without their JavaScript.example-frontendis updated. - React Native 0.88 generated types: type refs as
ViewInstance,TextInstance,ScrollViewInstance, andTextInputInstance(Box.scrollRef,TextField.inputRef,Textref). create-terreno-appscaffolds Expo~58.0.14, React Native0.88.0, and React19.3.0.- The Terreno 58 native module baseline lands in
example-frontendanddemo:@stripe/stripe-react-native0.81.0,react-native-purchasesandreact-native-purchases-ui10.12.2,expo-device,expo-crypto,expo-local-authentication,expo-system-ui, andexpo-build-properties(Android Kotlin 2.2.21 andcompileSdkVersion37 pins). Rebuild every dev client and store binary.react-native-otp-verifyis left out because it does not support the New Architecture. The demo has a hidden Native Modules page that shows each module's version and whether the running binary links it. See the 58.0.0 upgrade note. TerrenoAppturns HTTP rate limiting on by default. OmittingrateLimitnow mounts the limiter with the memory store (auth 20 / 15 min, api 600 / 15 min). PassrateLimit: falseto turn it off. On Cloud Run passrateLimit: {trustProxy: 1}so unauthenticated traffic keys by client IP. See the 58.0.0 upgrade note.@terreno/admin-frontendno longer takes an RTKapi. Theapiprop is removed from every admin component (AdminProvider,AdminShellLayout,AdminHome,AdminModelList,AdminModelTable,AdminModelForm,AdminScreenRouter,ConfigurationScreen,DocumentStorageBrowser,ConsentHistory, comms, jobs, org, consent, and announcement screens, and widget props), and admin hooks drop theirapiargument (useAdminConfig(apiBase),useAdminScripts(apiBase),useAdminRoles(apiBase),useConfigurationApi({basePath}),useDocumentStorageApi(basePath),useConsentHistory(baseUrl),useOrganizationsApi(basePath),useCommsDashboardApi(),useJobsDashboardApi(), and theuseAiObservability*Api()hooks).useAdminApi(api, routePath, modelName)is removed. UseuseAdminModelApi(routePath, modelName), which keeps the same hook names and calls the same/admin/{routePath}URLs through the admin fetch client.AdminApi,EndpointBuilder, and admininjectEndpointsare gone;@reduxjs/toolkitandreact-reduxare no longer peers of admin-frontend.AdminProvideris now the required auth binding for every admin request, including ObjectId and API-only model CRUD. Cookie SPAs passcredentials="same-origin"; embedded apps passapiOriginandgetAuthHeaders. Product screens that reuse admin components wrap them inAdminProvider. See the 58.0.0 upgrade guide.- Removed the legacy RTK realtime path. Use
synconmodelRouterwith@terreno/syncdbfor live collection updates.RealtimeApp,SyncApp, socket auth,sync:delta, and adminadmin:model.changedevents are unchanged. See the 58.0.0 upgrade note. @terreno/api:modelRouterno longer acceptsrealtime(now a TypeScript error), and the change stream no longer emits thesyncwebsocket event. RemovedRealtimeConfig,RealtimeEvent,DocumentSubscription,QuerySubscription,registerRealtime,getRealtimeRegistry,findRegistryEntryByCollection,findRegistryEntryByRoutePath,updateRealtimeRegistryOptions,clearRealtimeRegistry,RealtimeRegistryEntry, the query-subscription store (addQuerySubscription,removeQuerySubscription,removeAllSocketQueries,getQuerySubscriptionsForCollection,computeQueryId,clearQueryStore), andMAX_MODEL_SUBSCRIPTIONS/MAX_DOCUMENT_SUBSCRIPTIONS/MAX_QUERY_SUBSCRIPTIONS. Sockets no longer handlesubscribe:model,subscribe:document, orsubscribe:query.@terreno/rtk: removedrealtimeList,realtimeDocument,setRealtimeSocket,getRealtimeSocket,useSyncConnection, and theRealtimeEventtype. The rest of@terreno/rtk(includinguseSocketConnectionanduseRealtimeDebug) is removed in the same release; seeremove-rtk.md.- Removed
@terreno/rtkand every Redux dependency (@reduxjs/toolkit,react-redux,redux-persist,@rtk-query/codegen-openapi).@terreno/rtkis not published for 58.@terreno/syncdbis the only frontend data, request, and session layer. Followdocs/how-to/migrate-rtk-to-syncdb.md, which maps every removed export to its replacement, and the 58.0.0 upgrade note. @terreno/syncdbadds@terreno/syncdb/api(createApiClient,ApiError), request hooks in@terreno/syncdb/react(ApiClientProvider,useApiQuery,useLazyApiQuery,useApiMutation,useSocketEvent),@terreno/syncdb/config(baseUrl,baseWebsocketsUrl,appHeaders),@terreno/syncdb/auth(createBetterAuthClient,SessionProvider,useSession,jwtAuthAdapter,useJwtAuth, token-expiry helpers),@terreno/syncdb/flags(useFeatureFlags,useTerrenoFeatureFlagson the sync socket),@terreno/syncdb/app(useUpgradeCheck,hasPermission,canOpenAdminPage,installDevConsoleLogger),@terreno/syncdb/mcp(useMCPTools), and@terreno/syncdb/buildNumber.terreno-syncdb-codegen --api-outgenerates typed hooks for every non-synced OpenAPI operation (same names as the RTK codegen), replacing@rtk-query/codegen-openapi.bun run sdkwritesstore/apiSdk.ts.@terreno/uiConsentNavigator,AnnouncementNavigator,useConsentForms,useSubmitConsent,useAnnouncements, anduseAcknowledgeAnnouncementtake a requestclientinstead of an RTKapi.GptHistory(gpt/histories) is a synced collection and keeps its ObjectId_id(no migration).McpServiceToken(mcp/service-tokens, read-only) is a synced collection with String ids; runmcpServiceTokenStringIdsMigration(@terreno/api) before deploying 58 frontends.create-terreno-app, theterreno_bootstrapprompt, and theterreno_generate_screentool scaffold apps without Redux or@terreno/rtk. The terreno-mcp-localget_rtk_statetool, the MCP resourceterreno://docs/rtk, andterreno state --slice rtkare removed; useget_syncdb_stateandterreno state.@terreno/syncdb:useMCPTools(andMCPToolInfo,UseMCPToolsOptions,UseMCPToolsResult) moved from@terreno/syncdb/appto the new@terreno/syncdb/mcpentry point. Changeimport {useMCPTools} from "@terreno/syncdb/app"toimport {useMCPTools} from "@terreno/syncdb/mcp". The hook imports the optional@modelcontextprotocol/clientpeer at the top level, so exporting it from/appbroke every app that imported/appwithout that package installed, including apps scaffolded bycreate-terreno-app, which importinstallDevConsoleLoggerfrom/app.
Added
AdminSpaServeAppoptionsinternalOrigin(where server renders fetch API data, defaulthttp://127.0.0.1:${PORT ?? 4000}) andssrApiPrefixes(API paths a render may fetch). The plugin also serves Expo's root/_expo/loaders/*, withCache-Control: no-store, privateon pages and loader data.@terreno/syncdb:SessionProvider/ session storeinitialSession, and the request client'sprimeQuery(args, data), to start from data a server render already read.@terreno/admin-frontend:AdminRpcSeedandadminRpcSeedKeyseeduseAdminRpcQuerywith server-fetched bodies;buildAdminReadUrl,buildAdminListQueryParams,buildAdminApiListQueryRequestandhomeWidgetUrlsbuild the exact URLs the screens request.DataTablecolumns size themselves whenwidthis omitted. Each auto column starts at the wider of its header and its content (sampled from at most 50 rows, measured with a canvas on web and estimated on native), clamped to 80–360px, and auto columns grow to fill the table's container. Columns that setwidthkeep it.DataTableColumn.widthis now optional.@terreno/syncdbcreateSyncDb({idFormats})mints 24-hex ObjectIds for a collection set to"objectId", so a model that keeps Mongoose's default ObjectId_idcan sync without migrating its ids.mutate()throws on an explicit non-hex id for s...
57.22.0
Immutable
release. Only release title and notes can be modified.
Upgrade note: mcp-server/src/docs/upgrades/57.22.0.md.
Breaking
@terreno/aino longer integrates with Langfuse. The built-in observability prompt registry, traces, and review queue (ObservabilityAppwithcreateLocalObservabilityPlugin()) replace it. Removed exports:LangfuseApp,LangfuseCache,getCached,setCached,invalidateCache,initLangfuseClient,getLangfuseClient,isLangfuseInitialized,shutdownLangfuseClient,compilePrompt,createPrompt,getPrompt,invalidatePromptCache,initTracing,shutdownTracing,createTelemetryConfig,preparePromptForAI, and the typesChatMessage,GetPromptOptions,LangfuseAppOptions,LangfuseCachedPrompt,PaginatedResult,PreparePromptResult,PromptListItem,ScoreSubmission,ScoringFunction,TelemetrySettings,TraceListItem. The@terreno/ai/langfuseAppand@terreno/ai/langfuseClientsubpath exports are gone, along with the@langfuse/client,@langfuse/otel, and@opentelemetry/*dependencies of@terreno/ai.addGptRoutesdropslangfuseSystemPromptName; usesystemPromptName(a registry prompt) instead. Chat turns no longer setexperimental_telemetry.ControlPrimaryis now only"local".- The example backend no longer reads
LANGFUSE_SECRET_KEY,LANGFUSE_PUBLIC_KEY,LANGFUSE_BASE_URL,LANGFUSE_ORGANIZATION,LANGFUSE_PROJECT, orLANGFUSE_PROJECT_ID. Deploys (.github/workflows/cd.yml,scripts/ci/gcp-deploy.sh) no longer mount the Langfuse secrets, andinfra/flourish/main.tfdrops thebackend_secret_langfuse_secret_keyandbackend_secret_langfuse_public_keymodules, so the nextterraform applydeletes those two Secret Manager secrets. Deploy a revision without the mounts before applying.
Added
addGptRoutesacceptssystemPromptNameandsystemPromptLabel. A chat turn prepends that observability registry prompt to the system prompt and records its version on the trace.- The example chat reads
chat-assistantand thegenerate_joketool readsjoke-generatorfrom the observability prompt registry. bun run backend:seedfills every AI Observability screen: labelled prompt versions forexample-summarize,joke-generator, andchat-assistant, golden datasets, finished experiments, traces with scores, and review items in every status. Run it on an existing database with theseedAiObservabilityDemoadmin script.- Review batches: pick a human question set and press Grab 10 recent traces to give reviewers a fixed set of inputs and outputs (
POST /ai/observability/review/batches). - The review item screen shows one input, one output, and every question as Yes / No rows. On web,
Y/Nanswer the highlighted question,Entersubmits and moves to the next batch item, andSskips. Evaluator dimensions accept a reviewerquestion. - Run any LLM judge over a batch and see overall and per-question agreement with the human answers, plus a list of disagreements (
POST /ai/observability/review/batches/:id/judgeRuns). - The AI observability seed adds the
summary-review-questionsquestion set, two judges for it, and a 10-item batch with 8 answers where one judge agrees 97% and the other 78%. - Observability registry prompts can reference other prompts with
{{> base-rules}},{{> base-rules label=staging}}, or{{> base-rules version=3}}(default labelproduction). Shared instructions live in one prompt;PromptRegistry.get, the playground, experiments, and judges use the resolved text. - Every reference must resolve when it is saved. Creating a prompt, saving a version, and moving a label return 400
Invalid prompt referencefor a malformed tag, an unknown prompt or version, or a label the referenced prompt does not have yet, 400Prompt reference cyclewhen the change would make prompts include each other, and 400Prompt references nested too deeplywhen it would nest the prompt, or any prompt that includes it, more than 5 levels. - Traces stay named after the called prompt.
ObsTrace.promptslists it first, then each shared prompt version it pulled in, marked withincludedBy.PromptVersionRef.includesand harness prompt refs carry the same list.
Fixed
- Review queue:
YandNanswer the highlighted question when a Yes/No segment is focused. What the AI was given and What the AI wrote are headings above the field cards. - Review batches: Save batch sits on the New batch card. Search and More filters share a baseline.
- Prompt hub: description, folder, and tags sit on the Versions screen with the editor. System and template fields explain what to write.
- Evaluator detail loads the judge prompt
outputSchema(so helpfulness no longer reports a missing dimension) and experiment rows open that experiment.
Full Changelog: 57.21.0...57.22.0
58.0.0-beta.3
Immutable
release. Only release title and notes can be modified.
Upgrade note: mcp-server/src/docs/upgrades/58.0.0-beta.3.md.
Breaking
- Terreno 58 targets Expo SDK 58 (
~58.0.14), React Native0.88.0, and React19.3.0.@terreno/uipeersreact-native0.88.0. Native catalog moves with the SDK:react-native-gesture-handler~3.3.0,react-native-reanimated4.7.1+react-native-worklets0.13.0,react-native-screens~4.30.0,react-native-webview14.0.1,@sentry/react-native~8.28.0,@shopify/flash-list2.3.2,@shopify/react-native-skia2.14.0. Rebuild dev clients and store binaries. - Expo Router 58: set
export const unstable_settings = {initialRouteName}on the layout instead of passinginitialRouteNameto<Slot>/ navigators.SidebarNavigationignores the prop. - Expo Router 58 static rendering: a custom
app/+html.tsxmust renderheadNodesandbodyNodesfromuseServerDocumentContext()(expo-router/html), or exported pages ship without their JavaScript.example-frontendis updated. - React Native 0.88 generated types: type refs as
ViewInstance,TextInstance,ScrollViewInstance, andTextInputInstance(Box.scrollRef,TextField.inputRef,Textref). create-terreno-appscaffolds Expo~58.0.14, React Native0.88.0, and React19.3.0.- The Terreno 58 native module baseline lands in
example-frontendanddemo:@stripe/stripe-react-native0.81.0,react-native-purchasesandreact-native-purchases-ui10.12.2,expo-device,expo-crypto,expo-local-authentication,expo-system-ui, andexpo-build-properties(Android Kotlin 2.2.21 andcompileSdkVersion37 pins). Rebuild every dev client and store binary.react-native-otp-verifyis left out because it does not support the New Architecture. The demo has a hidden Native Modules page that shows each module's version and whether the running binary links it. See the 58.0.0 upgrade note. TerrenoAppturns HTTP rate limiting on by default. OmittingrateLimitnow mounts the limiter with the memory store (auth 20 / 15 min, api 600 / 15 min). PassrateLimit: falseto turn it off. On Cloud Run passrateLimit: {trustProxy: 1}so unauthenticated traffic keys by client IP. See the 58.0.0 upgrade note.@terreno/admin-frontendno longer takes an RTKapi. Theapiprop is removed from every admin component (AdminProvider,AdminShellLayout,AdminHome,AdminModelList,AdminModelTable,AdminModelForm,AdminScreenRouter,ConfigurationScreen,DocumentStorageBrowser,ConsentHistory, comms, jobs, org, consent, and announcement screens, and widget props), and admin hooks drop theirapiargument (useAdminConfig(apiBase),useAdminScripts(apiBase),useAdminRoles(apiBase),useConfigurationApi({basePath}),useDocumentStorageApi(basePath),useConsentHistory(baseUrl),useOrganizationsApi(basePath),useCommsDashboardApi(),useJobsDashboardApi(), and theuseAiObservability*Api()hooks).useAdminApi(api, routePath, modelName)is removed. UseuseAdminModelApi(routePath, modelName), which keeps the same hook names and calls the same/admin/{routePath}URLs through the admin fetch client.AdminApi,EndpointBuilder, and admininjectEndpointsare gone;@reduxjs/toolkitandreact-reduxare no longer peers of admin-frontend.AdminProvideris now the required auth binding for every admin request, including ObjectId and API-only model CRUD. Cookie SPAs passcredentials="same-origin"; embedded apps passapiOriginandgetAuthHeaders. Product screens that reuse admin components wrap them inAdminProvider. See the 58.0.0 upgrade guide.- Removed the legacy RTK realtime path. Use
synconmodelRouterwith@terreno/syncdbfor live collection updates.RealtimeApp,SyncApp, socket auth,sync:delta, and adminadmin:model.changedevents are unchanged. See the 58.0.0 upgrade note. @terreno/api:modelRouterno longer acceptsrealtime(now a TypeScript error), and the change stream no longer emits thesyncwebsocket event. RemovedRealtimeConfig,RealtimeEvent,DocumentSubscription,QuerySubscription,registerRealtime,getRealtimeRegistry,findRegistryEntryByCollection,findRegistryEntryByRoutePath,updateRealtimeRegistryOptions,clearRealtimeRegistry,RealtimeRegistryEntry, the query-subscription store (addQuerySubscription,removeQuerySubscription,removeAllSocketQueries,getQuerySubscriptionsForCollection,computeQueryId,clearQueryStore), andMAX_MODEL_SUBSCRIPTIONS/MAX_DOCUMENT_SUBSCRIPTIONS/MAX_QUERY_SUBSCRIPTIONS. Sockets no longer handlesubscribe:model,subscribe:document, orsubscribe:query.@terreno/rtk: removedrealtimeList,realtimeDocument,setRealtimeSocket,getRealtimeSocket,useSyncConnection, and theRealtimeEventtype. The rest of@terreno/rtk(includinguseSocketConnectionanduseRealtimeDebug) is removed in the same release; seeremove-rtk.md.- Removed
@terreno/rtkand every Redux dependency (@reduxjs/toolkit,react-redux,redux-persist,@rtk-query/codegen-openapi).@terreno/rtkis not published for 58.@terreno/syncdbis the only frontend data, request, and session layer. Followdocs/how-to/migrate-rtk-to-syncdb.md, which maps every removed export to its replacement, and the 58.0.0 upgrade note. - Apps upgrading from
@terreno/rtkmust installexpo-constantsandexpo-networkthemselves (rtk depended on them;@terreno/syncdblists them as optional peers), plus the optional peers for the features they use:better-auth,@better-auth/expo,@better-auth/passkey,@openfeature/web-sdk,@openfeature/react-sdk,@modelcontextprotocol/client. See the upgrade note. @terreno/syncdbadds@terreno/syncdb/api(createApiClient,ApiError), request hooks in@terreno/syncdb/react(ApiClientProvider,useApiQuery,useLazyApiQuery,useApiMutation,useSocketEvent),@terreno/syncdb/config(baseUrl,baseWebsocketsUrl,appHeaders),@terreno/syncdb/auth(createBetterAuthClient,SessionProvider,useSession,jwtAuthAdapter,useJwtAuth, token-expiry helpers),@terreno/syncdb/flags(useFeatureFlags,useTerrenoFeatureFlagson the sync socket),@terreno/syncdb/app(useUpgradeCheck,hasPermission,canOpenAdminPage,installDevConsoleLogger,useMCPTools), and@terreno/syncdb/buildNumber.terreno-syncdb-codegen --api-outgenerates typed hooks for every non-synced OpenAPI operation (same names as the RTK codegen), replacing@rtk-query/codegen-openapi.bun run sdkwritesstore/apiSdk.ts.@terreno/uiConsentNavigator,AnnouncementNavigator,useConsentForms,useSubmitConsent,useAnnouncements, anduseAcknowledgeAnnouncementtake a requestclientinstead of an RTKapi.GptHistory(gpt/histories) is a synced collection and keeps its ObjectId_id(no migration).McpServiceToken(mcp/service-tokens, read-only) is a synced collection with String ids; runmcpServiceTokenStringIdsMigration(@terreno/api) before deploying 58 frontends.create-terreno-app, theterreno_bootstrapprompt, and theterreno_generate_screentool scaffold apps without Redux or@terreno/rtk. The terreno-mcp-localget_rtk_statetool, the MCP resourceterreno://docs/rtk, andterreno state --slice rtkare removed; useget_syncdb_stateandterreno state.
Added
DataTablecolumns size themselves whenwidthis omitted. Each auto column starts at the wider of its header and its content (sampled from at most 50 rows, measured with a canvas on web and estimated on native), clamped to 80–360px, and auto columns grow to fill the table's container. Columns that setwidthkeep it.DataTableColumn.widthis now optional.@terreno/syncdbcreateSyncDb({idFormats})mints 24-hex ObjectIds for a collection set to"objectId", so a model that keeps Mongoose's default ObjectId_idcan sync without migrating its ids.mutate()throws on an explicit non-hex id for such a collection.generateObjectIdand theSyncIdFormattype are exported.- Sync
validationnacks carry an optionalreason:invalid_idwhen an ObjectId-keyed collection gets a non-hex id (rejected before the mutation is claimed), andid_collisionwhen a create names an_idanother document holds. A collision never touches the existing document and its message never names the holder. The ledger records the reason (SyncMutation.nackReason) so a redelivery replays it. GET /sync/entitiesleaves out non-hex ids for an ObjectId-keyed model instead of answering 400, so a rejected create queued for repair cannot fail the rest of the repair batch.
Changed
- The repository's agent rules now generate with rulesync 17 (up from 9). The root rule
.rulesync/rules/00-root.mdnow generatesAGENTS.md, which Devin and other AGENTS.md readers load, in place of.devin/rules/00-root.md. Never editAGENTS.mdby hand: edit the root rule and runbun run rules. The examples that existed only in the old hand-editedAGENTS.md(syncdb and RTK SDK usage) moved into the root rule, soCLAUDE.md, the Cursor root rule, and Copilot instructions get them too. Links in the root rule now resolve from the repository root. Generated Copilot hooks use the portablecommandfield. Generated Copilot subagents no longer listagent/runSubagentas their only tool, so they get every default tool. Generated skills carry theirlicense,disable-model-invocation, and Devintriggersfrontmatter. @terreno/syncdb/authSessionProvider:logout()no longer clears the session before the server answers. The session stays in the state untilauthClient.signOut()finishes (signOutTimeoutMs, default 10 seconds), and then it is cleared. Meanwhile the newisSigningOutstate (useSession().isSigningOut) is true;isLoadingis left alone, so a navigator gated on it keeps its scre...