v6.2.0-edge.6: Field-level security close-out, alternate base views, and calendar events
Field-level security close-out, Alternate Base Views, server-authored agent replies, native tool calling for the Loop agent, calendar events in Communication with a Calendar view type, and the content ingestion pipeline. Plus anonymous-guest isolation, mj sync push correctness, and CodeGen metadata-drift fixes.
Upgrade Notes apply: eleven migrations apply on mj migrate, agent-reply API callers must switch to userMessageId, clients and the web widget must upgrade with the server, field-level security and credential expiry refuse calls that used to succeed, shared RunView caches need a flush and field-secured documents a re-index, duplicate-detection vectors need a re-sync, and proxies that pin CORS headers must allow x-mj-timezone.
Edge builds are prereleases.
MemberJunction 6.x is released under the Business Source License 1.1; 5.x and earlier stay ISC. What the licence grants, and what needs certification, is in the licence section of the v6 upgrade guide.
New Features
Section titled “New Features”- Field-level security close-out (
@memberjunction/core,@memberjunction/server,@memberjunction/graphql-dataprovider,@memberjunction/templates,@memberjunction/a2aserver, and 36 other packages): A denied field value no longer reaches anyone the rule does not entitle: API callers, an LLM’s context, message recipients, or stored artifacts such as embeddings, tags and logs. Entity objects never hold a value their user is denied on any load path, and work done on a user’s behalf runs as that user: communication previews and sends, template renders, entity actions and A2A tasks. Caches that hold user-specific rows are keyed by user.guides/FIELD_LEVEL_SECURITY_GUIDE.mdis rewritten with a developer checklist. - Alternate Base Views (
@memberjunction/core,@memberjunction/core-entities,@memberjunction/generic-database-provider,@memberjunction/codegen-lib,@memberjunction/query-gen,@memberjunction/lists,@memberjunction/ng-entity-viewer, and others): An entity can register governed SQL views (MJ: Entity Alternate Base Views) that keep full column parity with itsBaseViewwhile returning a curated row subset, such as active members or open orders. They work across RunView, CodeGen, caching, query generation, lists, data contexts, and Data Explorer. - Server-authored agent replies (
@memberjunction/core-entities,@memberjunction/ai-agents,@memberjunction/server,@memberjunction/graphql-dataprovider,@memberjunction/ai-agent-client,@memberjunction/conversations-runtime,@memberjunction/ng-conversations, and others): Only server code can create or change an agent’s reply (RoleAIorError) inMJ: Conversation Details, so a client can no longer forge or rewrite what an agent said. The server creates the reply row itself from the user’s message. See Upgrade Notes for the API change. - Native tool calling for the Loop agent (
@memberjunction/ai-agents,@memberjunction/ai-prompts,@memberjunction/ai-anthropic,@memberjunction/ai-gemini,@memberjunction/ai-openai, and others): The Loop agent can run as a provider-native tool loop. Retries and unanswered calls keep the call/result ordering Anthropic and OpenAI require, and Anthropic and Gemini reasoning blocks are carried across tool turns and dropped, not replayed, when the history before them changes. - Calendar events in Communication (
@memberjunction/communication-types,@memberjunction/communication-engine,@memberjunction/communication-ms-graph,@memberjunction/communication-gmail,@memberjunction/ai-bridge-server,@memberjunction/telephony-adapters): Providers can create, update, cancel, get and sync calendar events, each against an explicit calendar target. MS Graph and Gmail (Google Calendar) implement them.CalendarEventLinksties events to any record throughMJ: Calendar Event Linksand syncs fromMJ: Calendar Sync States. The realtime bridge’s calendar sources now read through the providers, and itsGraphCalendarClientandGoogleCalendarClientare removed. - Calendar view type (
@memberjunction/ng-entity-viewer,@memberjunction/ng-ui-components): Entity views can show records on a day, week or month layout by a start date field and an optional end date field. - Content ingestion pipeline (
@memberjunction/content-pipeline,@memberjunction/content-pipeline-base,@memberjunction/record-set-processor,@memberjunction/content-autotagging,@memberjunction/core-entities, and others): Discover, Extract, Tag, Segment, Embed and Delete stages run over Content Sources, Items and Chunks through Record Set Processing’s newPipeline Stagework type. - Bound action parameters for agent runs (
@memberjunction/ai-core-plus,@memberjunction/ai-agents,@memberjunction/actions-base,@memberjunction/core-actions): A run can fix action input parameters (ExecuteAgentParams.boundActionParams) that the model can neither see nor change. Bindings are stored onMJ: AI Agent Runsand reapplied when a run is resumed or continued. - Server-set query parameters and query approvals (
@memberjunction/core,@memberjunction/query-processor,@memberjunction/core-entities,@memberjunction/server, and others): Query parameters can be marked server-set so callers cannot override them, templates can useContextvalues (user, time), andRequireApprovedruns only queries whose approved definition fingerprint still matches. - Properties on user views and dashboards (
@memberjunction/core,@memberjunction/generic-database-provider,@memberjunction/ng-entity-viewer,@memberjunction/ng-dashboard-viewer,@memberjunction/ng-query-viewer,@memberjunction/ng-dashboards): Saved views can declare typed inputs that each add a filter predicate, with server-only properties a caller cannot set. Dashboards gain properties, part input mappings, events and wires, and an Interactive Component part. - Executive Cockpit and event-driven agent wakes (
@memberjunction/ng-dashboards,@memberjunction/ai-agents,@memberjunction/core-actions,@memberjunction/credentials): A Chief of Staff cockpit in Explorer covers priorities, approvals of pending agent requests, agent wakes and the user’s agent policy. A resolved agent request wakes its owner’s agent on the next dispatcher sweep instead of waiting for the agent’s schedule. - Record links, version history and form toolbar (
@memberjunction/ng-base-forms,@memberjunction/ng-record-changes,@memberjunction/ng-entity-viewer,@memberjunction/ng-explorer-core, and others): Forms show links in both directions (fields on the record and records that point to it) with hover previews, a record-changes drawer with in-form historical version previews, and a registry for custom toolbar buttons. - Per-connection integration catalog (
@memberjunction/core-entities,@memberjunction/integration-engine,@memberjunction/integration-engine-base): NewCompanyIntegrationObjectandCompanyIntegrationObjectFieldtables give each connection its own copy of its connector’s objects and fields, so two connections to the same connector no longer overwrite each other’s discovery. The engine reads them behind a per-connection flag. - Eleven Realtime models (
@memberjunction/ai-elevenlabs,@memberjunction/ai-realtime-client,@memberjunction/realtime-runtime,@memberjunction/ng-conversations): Adds ElevenLabs’eleven_realtime_v1_miniandeleven_realtime_v1_maxas voice co-agent models on both server-bridged and browser-direct calls. - Local development sign-in (
@memberjunction/auth-providers,@memberjunction/server,@memberjunction/ng-auth-services,@memberjunction/installer): AnAuthProvider: "local"option signs in with locally issued tokens for development. The server refuses to start with it in production, and its endpoints reject non-localhost requests. - Weekly AI model refresh (
@memberjunction/ai,@memberjunction/aiengine,@memberjunction/core-entities): Adds Kimi K3.1 Pro (through Moonshot AI and OpenRouter), Kimi K3.1 Pro Highspeed (inactive), and MiniMax-M3.1-Flash.
Improvements
Section titled “Improvements”- SQL dialect follows the database (
@memberjunction/sql-dialect,@memberjunction/core,@memberjunction/ai-core-plus,@memberjunction/core-actions,@memberjunction/ai-agents,@memberjunction/server): The SQL an agent prompt asks for, and the connection its result runs on, are chosen from the provider’s platform, so agents on PostgreSQL no longer get SQL Server syntax. - Fewer read round trips (
@memberjunction/core,@memberjunction/generic-database-provider,@memberjunction/integration-engine,@memberjunction/server, and others):RunViewParams.SkipTotalRowCountskips the count query for callers that read only rows; a fullMaxRows: 1read no longer runs a secondCOUNT(*); RunView sends its view, count and aggregate queries in one batch. - Server scalability (
@memberjunction/server,@memberjunction/core,@memberjunction/generic-database-provider,@memberjunction/api-keys, and others): MJAPI replicas can be split into API and worker roles, with pluggable broadcast providers that keep caches in step across replicas. - Model failover respects its attempt limit (
@memberjunction/ai-prompts,@memberjunction/ai-core-plus):FailoverMaxAttemptsnow caps the requests a failover actually sends. Before, it was ignored and a failing prompt could walk every active model and vendor of its type. - OpenRouter model preference (
@memberjunction/ai-openrouter):MJ_OPENROUTER_MODEL_PREFERENCEsends an ordered fallback list that OpenRouter walks on errors. - Credential expiration enforced (
@memberjunction/credentials,@memberjunction/ai-prompts):CredentialEngineno longer hands out a credential past itsExpiresAt. - Duplicate detection (
@memberjunction/ai-vector-dupe,@memberjunction/ai-vector-sync,@memberjunction/ai-vectors-memory,@memberjunction/ng-dashboards, and others): A run records and uses the Entity Document it was started with, reports progress, finds duplicates past the first 1,000 records, and scopes vector queries to its document so several documents can share one index. - Integration discovery (
@memberjunction/integration-engine): Discovery stops at a memory budget instead of being killed, never saves an object with no fields, has a per-connection run deadline (default 12 hours), and its watchdog evicts entries for work that is no longer running. - DBAutoDoc key detection (
@memberjunction/db-auto-doc): LLM calls are time-bounded, keys are checked against the data before they are emitted, unique indexes count as primary-key evidence, seed context reaches the key passes, and organic keys are emitted hub-and-spoke instead of as all-pairs cliques. The statistical foreign-key detector works on PostgreSQL, where its sampling query failed for every column pair, and an unset embedding provider follows the LLM’s vendor instead of sending a Gemini key to OpenAI. Emitted keys no longer create a related-record grid on the form unlessorganicKeyDetection.autoCreateRelatedViewOnFormis set. - Explorer forms (
@memberjunction/ng-base-forms,@memberjunction/ng-shared,@memberjunction/ng-explorer-core): A record shown in a custom form can be opened in the standard form, and an entity view can create a record directly in the standard form. - Brand theme on first paint (
@memberjunction/ng-shared-generic,@memberjunction/ng-explorer-app, and others): The org brand overlay survives a cold load, andThemeDefinition.IsDefaultlets a brand theme be the default without writing a user preference. - Chat overlay follows shell policy (
@memberjunction/ng-explorer-core,@memberjunction/ng-explorer-app): A shell chrome policy can turn the floating chat overlay off per user, as it already could for search and notifications. - Predictive Studio safeguards (
@memberjunction/predictive-studio,@memberjunction/predictive-studio-core,@memberjunction/predictive-studio-sidecar,@memberjunction/ng-dashboards,@memberjunction/ng-core-entity-forms): Training is seeded and reproducible, validation metrics are out-of-sample, imbalanced classifiers must beat the majority-class baseline, and model drivers are shown only where the model kind supports them. Existing models trained without a locked holdout, or graded on accuracy alone, show as unmeasured, with their driver lists hidden, until retrained. - Whiteboard and markdown (
@memberjunction/ng-whiteboard,@memberjunction/ng-markdown,@memberjunction/ng-conversations): Whiteboard items take an optionalTagand hosts can set the pen palette (hex colors only); markdown images can be height-capped and report clicks.
Bug Fixes
Section titled “Bug Fixes”- Anonymous visitors isolated from each other (
@memberjunction/server,@memberjunction/core,@memberjunction/livekit-room-server,@memberjunction/ai-agents, and others): Every anonymous widget guest and magic-link invitee signs in as the one shared Anonymous user, so checks that compared only the user ID treated all of them as one person. A visitor who learned another’s session ID could relay into, close or restore that realtime session. Sessions, conversation runs and LiveKit rooms now check a per-visitor identity. - Second user records on sign-in (
@memberjunction/server): A user added outside the sign-in flow (by an admin, an invite or a direct insert) got a duplicateUserrecord on first login, because the cache refresh ran after auto-provisioning instead of before. Logins that match more than one record by email are no longer resolved by row order; the error log names the colliding records. Deactivating a duplicate does not take it out of the match, so change its email instead. mj sync pushmigrations (@memberjunction/metadata-sync,@memberjunction/generic-database-provider,@memberjunction/core-entities-server): Values from@lookupare written as natural-key subqueries instead of this database’s IDs, so Metadata_Sync migrations update the right rows everywhere. Deletes run in dependency order,--incrementalnotices@file:changes (the first incremental push after upgrading processes the whole tree once), and Open App migrations call core procedures in the core schema.- CodeGen metadata drift (
@memberjunction/codegen-lib,@memberjunction/schema-engine,@memberjunction/server): CodeGen keepsEntityFieldrows in step with the views and procedures it regenerates, prunes orphaned fields, keeps IS-A children’s inherited foreign keys, finds stale CRUD procedures, and fails the run when any step fails instead of reporting success. It no longer treats an entity’s own primary key as its hierarchy parent. - PostgreSQL full-text search and idle connections (
@memberjunction/codegen-lib,@memberjunction/postgresql-dataprovider,@memberjunction/generic-database-provider,@memberjunction/server): Enabling full-text search on a PostgreSQL entity creates its search objects instead of failing CodeGen, and a dropped idle pooled connection is logged instead of crashing MJAPI. On any database, user search on an entity flagged for full-text search but without a search function falls back to field matching instead of failing with a syntax error. - Integration incremental syncs skipped rows (
@memberjunction/integration-engine,@memberjunction/server): A connector that reports a running maximum per page (NetSuite 1.4.1 and later) moved the incremental filter forward mid-scan, so rows whose timestamp trailed the maximum were never fetched and the run reported success. The filter now stays at the run’s starting boundary. A connector upgrade that moves an object’s incremental cursor to another column now resets that object’s watermark, where the old column’s value used to filter the new one and silently drop rows. - Runtime schema updates and killed processes (
@memberjunction/schema-engine,@memberjunction/server,@memberjunction/integration-progress-artifacts): Child builds get a heap ceiling sized to free memory, pending work is recorded before the build so a restart resumes it, and at startup MJAPI marks runs a dead process left open as failed instead of leaving the wizard waiting. - Recording status overwritten by session saves (
@memberjunction/core-entities,@memberjunction/core-entities-server,@memberjunction/ai-agents,@memberjunction/server): A stale save of anMJ: AI Agent Sessionsrecord could clear a finished recording’s status and mark itPartial. The recording-ledger columns are no longer updatable through an entity save. - Record Processes (
@memberjunction/record-set-processor,@memberjunction/actions,@memberjunction/core,@memberjunction/global, and others): Pause and cancel work again (a checkpoint save overwrote the request), a record’s run detail row no longer fails its foreign key to the action log, and runs of fast actions are no longer slowed by that wait. - Realtime calls (
@memberjunction/realtime-runtime,@memberjunction/ai-realtime-client,@memberjunction/ng-conversations,@memberjunction/server): A call that fails keeps its end reason and tells the user, a start that fails closes its session at once, a new call waits for the previous teardown, spoken openings are saved to the transcript, and late user transcripts keep their own start time. - Recording shard uploads (
@memberjunction/realtime-runtime): A network failure is retried instead of being logged as a server refusal, and a 4xx rejection is dropped. - Anthropic request shapes (
@memberjunction/ai-anthropic): Assistant prefill is withheld when thinking is on, and sampling parameters are not sent to models that reject them. Streaming requests withoutmax_tokensdefault to 32000, as non-streaming ones do, so Claude 3 models need an explicit value. - ElevenLabs tool results (
@memberjunction/ai-realtime-client,@memberjunction/ai-elevenlabs): Tool results are sent as the string ElevenLabs expects; sending an object closed the conversation. - Smart filters returning every row (
@memberjunction/core-entities): A Smart Filter whose generated WHERE clause is blank regenerates it instead of returning the whole table. - Record CRUD actions (
@memberjunction/ai-engine-base,@memberjunction/aiengine,@memberjunction/ai-agents,@memberjunction/core-actions): Get, Update and Delete Record accept every primary-key shape and fail fast on unknown fields. - Template and form saves (
@memberjunction/ng-core-entity-forms,@memberjunction/ng-base-forms,@memberjunction/core): A content-type change in the Template Editor is saved, and a later save or delete is no longer queued into an already-submitted transaction group and dropped. - Vector index external IDs (
@memberjunction/core-entities-server): A new Vector Index record that already has anExternalIDadopts that provider index instead of creating an empty one. - Open App installs (
@memberjunction/open-app-engine,@memberjunction/dynamic-packages,@memberjunction/cli): A missing GitHub credential for a private repository is reported as such instead of as a missing tag, packages can declareplatformso Node-only packages stay out of the browser, and monorepo version tags are resolved from the tags that exist. - Flow editor runtime error (
@memberjunction/ng-flow-editor):@foblex/flowis pinned to 18.0.0, because 18.1.0 renamed exports and broke the flow editor at runtime withNG0919.
Upgrade Notes
Section titled “Upgrade Notes”- Eleven migrations apply on
mj migrate:Per_Connection_Integration_Catalog,DuplicateRun_EntityDocumentID,Composite_Performance_Indexes,Recording_Ledger_Columns_Not_Entity_Updatable,Bound_Data_Access_And_Approvals,Calendar_Event_Links,Entity_Alternate_Base_Views,Content_Pipeline_Framework,CodeGen_EntityField_Drift_Repairs,CommunicationProvider_UserDelegatedOAuth_GatesandMetadata_Sync. On PostgreSQL, the base-view gaps tracked in #5649 remain: theEnableFieldLevelSecurity,RelatedEntityFilterandRelatedEntityOrderByfield metadata is still missing. - Agent replies are created by the server (
@memberjunction/server,@memberjunction/graphql-dataprovider,@memberjunction/ai-agent-client,@memberjunction/conversations-runtime,@memberjunction/ai-agents,@memberjunction/task-graph):RunAIAgentFromConversationDetailtakesuserMessageId(the user’s saved message) instead ofconversationDetailId(a reply row the caller created). The server creates the reply row and names it in the acknowledgement. Client code that creates or editsAI/Errorrows inMJ: Conversation Detailsis refused, andRunAIAgent/RunAIAgentSystemUserno longer write into aconversationDetailIdthe caller passes.AgentClientSession.RunAgentFromConversationDetailtakesUserMessageId, andTaskContinuationParams.SubmittedByUserIDis required. - Upgrade clients with the server (
@memberjunction/graphql-dataprovider,@memberjunction/realtime-runtime,@memberjunction/server): Older@memberjunction/graphql-dataproviderbuilds send denied fields at their defaults when a transaction group creates a record, and this server refuses that input for a restricted user. Reload open browser tabs, and move pinned consumers to the matching client release. In the other direction, this release’s realtime runtime sends acloseReasonthat older servers do not accept. - Web widget and anonymous sessions (
@memberjunction/server,@memberjunction/realtime-widget,@memberjunction/ng-realtime-widget,@memberjunction/livekit-room-server): A guest token refresh needs a proof signed by a key the widget registers, so a widget bundle older than this release gets 403 at its first refresh; replace any self-hostedmj-widget.js. The widget needs its host page on HTTPS (orlocalhost) and shows nothing on plainhttp://. A widget whose guest role is the stockUIrole is refused withguest_role_not_isolated; useWidget Guestor a role listed inmagicLink.grantableRoleNames. Guest sessions end 12 hours after their first mint, and anonymous sessions started before the deploy must start again. - Field-level security refuses more (
@memberjunction/core,@memberjunction/server,@memberjunction/generic-database-provider,@memberjunction/templates,@memberjunction/entity-communications-server,@memberjunction/a2aserver, and others): Client input naming a field the caller cannot read is rejected instead of dropped. Ad-hoc SQL from any user except the system user may read only entity base views the caller reads with no row filter and no denied field, and ad-hoc SQL with no user is refused. For a user with any field denial, a saved query without a role-list grant is refused when it reads a custom view, synonym, function or other relation that is not an entity’s base view or table; grant such queries throughMJ: Query Permissionsafter reviewing their SQL. RESTrunView/runViewsalways returnsimplerows. An{% AIPrompt %}tag whose model fails now fails the render, so a communication that used to send with an error in its body does not send. An entity communication skips recipients whose address field the sender cannot read. Withouta2aServerSettings.userEmailthe A2A agent card lists no entities or agents. - Flush shared RunView caches and re-index field-secured documents (
@memberjunction/core,@memberjunction/server,@memberjunction/ai-vector-sync,@memberjunction/content-autotagging): Before this release a restricted user’s cache miss could write narrowed rows into the slot unrestricted users read, so flush RunView keys in a shared cache (Redis) once every server runs this release. Entity documents, vectors and tags now leave out fields not every role may read: re-vectorize Entity Documents on field-secured entities (rebuilding external stores such as Pinecone), re-run entity autotagging, and review tags produced from restricted text. - Template renders need their user (
@memberjunction/templates,@memberjunction/templates-base-types): Templates render as the user of each render. Pass that user asContextUser; a render without one still runs, but an{% AIPrompt %}tag fails it. - Expired credentials are refused (
@memberjunction/credentials,@memberjunction/ai-prompts): A credential past itsExpiresAtnow throwsCredentialExpiredErrorwhere it used to resolve. Find active credentials with a pastExpiresAtbefore upgrading;CredentialEngine.Instance.ExpirationConfigacceptspolicy: 'warn'or agraceMsfor a staged rollout. - Proxies must allow
x-mj-timezone(@memberjunction/graphql-dataprovider,@memberjunction/server): Browser requests carry the user’s time zone in anx-mj-timezoneheader. MJAPI’s own CORS setup needs nothing, but a proxy or gateway that pinsAccess-Control-Allow-Headersmust add it, or browser preflights fail. MaxRows: 1reads report one row (@memberjunction/generic-database-provider): A fullMaxRows: 1read now reportsTotalRowCount: 1rather than the view’s total. Read two rows when you need to know whether more exist.- Duplicate detection needs its document and fresh vectors (
@memberjunction/core-entities,@memberjunction/server,@memberjunction/ai-vector-dupe,@memberjunction/ai-vector-sync,@memberjunction/ai-vectors-memory):MJ: Duplicate Runs.EntityDocumentIDis required. The migration backfills existing runs and deletes runs whose entity has no document. Entity Documents no longer cascade deletes, so a document with runs or synced vectors cannot be deleted; set it Inactive instead. Vectors synced before this release carry noEntityDocumentID, so a run against them fails until the document’s vectors are re-synced. The in-memory vector store now scores standard cosine similarity: re-tune thresholds set against it to2 × old − 1. - Recording-ledger fields are read-only on entity saves (
@memberjunction/core-entities,@memberjunction/core-entities-server):MJ: AI Agent Sessionsdrops the setters and GraphQL inputs for the sevenRecording*ledger fields (RecordingStartedAtstays). Apply the whole release withmj migrate; the migration and the metadata sync must land together, or session saves fail. - Open App manifests and Node-only packages (
@memberjunction/open-app-engine,@memberjunction/dynamic-packages,@memberjunction/cli): Arole: "actions"package undersharedno longer reaches the browser build, and one underclientis rejected. Publishers whose Node-onlysharedpackage has another role should add"platform": "node"to it or move it toserver.