v6.1.0-edge.0: The 6.x era opens with the first Edge release
This is the first release of the 6.x era and the first Edge release ever. The release model changed with it: Edge builds are prereleases of the next line and publish to the edge npm dist-tag (npm install @memberjunction/core@edge), while latest stays on the certified line (currently 5.51.0) and moves only at certification. Ordinary semver ranges never auto-resolve an Edge build, so existing installations are unaffected until they opt in.
Breaking Changes (6.x)
Section titled “Breaking Changes (6.x)”- The 36 vendor connectors are removed from
@memberjunction/integration-connectors(Salesforce, HubSpot, QuickBooks, NetSuite, Mailchimp, SharePoint, iMIS, and 29 more). Every one was a duplicate of its self-contained Open App in the MemberJunction/Integrations repo (@memberjunction/connector-<vendor>), which is the copy that ships to customers — that repo is now the single source of truth, and connectors version independently of the MJ core release train. Known gap: seven pre-existingIntegrationseed rows collide with or dangle against the re-pointed Open Apps (five installs hard-fail onUQ_Integration_Name) — check the upgrade guide before installing a connector Open App on an upgraded database. ActionExecutionLog.Paramsnow records the as-called inputs only — the final merged parameter set (inputs plus action outputs) moved to the newResultParamscolumn. Nothing errors: anything readingParamsfor an action’s outputs silently gets inputs instead. Repoint output-readers atResultParams; input-readers are now more correct than before.@memberjunction/aiengineremoved its bespoke similarity APIs —FindSimilarAgents/FindSimilarActions,RefreshAgentEmbeddings/RefreshActionEmbeddings, and the agent/action vector-service getters are gone in favor of the unifiedProvider.SearchEntitypipeline (see New Features). The five core actions built on the old paths were rewritten as backward-compatible wrappers, so metadata-driven callers need no change; only direct TypeScript callers break, loudly, at compile time.- User-supplied SQL can no longer reference database system catalogs —
SQLExpressionValidatornow rejectssys.*,INFORMATION_SCHEMA,pg_catalog.*, and PostgreSQL credential views in every context, full queries included. Stored MJ Queries doing catalog introspection fail validation after upgrading; replace them with MJ’s own entity metadata, which respects the permission model. There is no opt-out, by design. - JWT verification accepts only asymmetric signature algorithms (
RS256/384/512,ES256/384/512,PS256) in MJServer and the MCP server. A deployment whose identity provider signs tokens withHS256(shared-secret HMAC) now fails closed at authentication. Standard OIDC providers (Auth0, Entra, Okta) sign RS256 and are unaffected. The list is hardcoded, deliberately — it foreclosesalg=noneand RS256→HS256 confusion attacks. - Negation-form RLS filters (
<>,NOT IN,NOT LIKE) now match fewer rows when the substituted user property isundefined— previously the literal string"undefined"leaked into the filter and widened results. Fewer visible rows after upgrading is the fix working, not a regression.
Full walkthrough, pre-upgrade checklist, and the verified did-not-change list: Upgrading to v6 on the docs site.
New Features
Section titled “New Features”- Entity Action workflow extensions (
@memberjunction/core-entities,@memberjunction/actions):EntityActionbecomes the general workflow-hook substrate across MJ and every Open App — building on the existing save-path wiring (blockingValidate,Execute Agent) with additive schema and a safer, diagnosable execution log, so apps stop inventing their own workflow layers. - Layered base views (
@memberjunction/core,@memberjunction/codegen-lib): an entity can now have both a generated base view and a custom view layered over it. PreviouslyBaseViewGenerated = 0was all-or-nothing — adding one computed column meant hand-maintaining the entire generated view forever, and later foreign keys silently never got display joins. (SQL Server only; PostgreSQL refuses layered views by design.) - API-key row-filter schema (
@memberjunction/api-keys-base,@memberjunction/api-keys):RowFilterIDadded toAPIKeyScopeandAPIApplicationScopeas nullable FKs into the existingRowLevelSecurityFiltercatalog — purely additive in this release; enforcement lands with the follow-up implementation. The FK makes a filter undeletable while a live key references it. - Pluggable search-scope permission resolver (
@memberjunction/search-engine,@memberjunction/server): the resolver behind every search authorization check is now replaceable, so consumers whose entitlements aren’t MJ users or roles can plug in their own model instead of projecting derived rows intoSearchScopePermissionor forking the search path. - Per-verb direct-SQL declarations on entities (
@memberjunction/core):Entitycan now declare, per verb, whether SQL that bypassesBaseEntitymay write it — making the “everything flows throughSave()/Delete()” contract enforceable instead of aspirational. - Mobile records UX (
@memberjunction/ng-explorer-core,@memberjunction/ng-ui-components,@memberjunction/ng-shared): below the 768px breakpoint the records region runs headerless with a record bar and a bottom-sheet record switcher (docked records included); split layouts flatten to a single stack without touching desktop-made layouts. Ships a new genericmj-bottom-sheetprimitive. - Theme-aware registry components (
@memberjunction/react-runtime,@memberjunction/interactive-component-types):ComponentStylesgains sequential/diverging visualization ramps backed by new theme tokens;ComponentSpecgainsstyleOverridesso user-requested styling travels as spec data rather than color literals in generated code. All 10 generic registry components now read theme slots. - Per-session voice on ElevenLabs realtime (
@memberjunction/ai-elevenlabs):Config.voicenow reaches the session as thetts.voice_idoverride on both mint paths, and the agent drift-check requires the whole override set — repairing previously-provisioned agents that silently dropped voice overrides. - Entity semantic search standardized on
Provider.SearchEntity(@memberjunction/aiengine): retires the bespoke in-memory “find similar” paths in favor of the unified Search-typeEntityDocumentpipeline. - New
@memberjunction/standardspackage: the repo’s adopted-standards checks, packaged.
Improvements
Section titled “Improvements”- The monorepo now builds with pnpm (strict, workspace-linked). Nothing changes for consumers — published packages, registry, and npm/yarn installs are identical — but strict resolution already surfaced and fixed real latent bugs that npm’s hoisting had been hiding, including a package silently resolving the wrong major of a dependency.
- CodeGen cold runs ~44% faster (
@memberjunction/codegen-lib): the per-field introspection view now reads user-object catalog views instead ofsys.all_columns/sys.all_objects— 190.7s → 105.9s on a 500-table schema, byte-for-byte identical generated output. - CodeGen smart-field-identification guardrails: search defaults OFF with a narrow whitelist and anti-pattern list; a new guardrails module enforces the rules in code so flag drift can’t sneak back regardless of LLM output.
- PostgreSQL parity made whole and gated: the four 6.x migrations missing PostgreSQL counterparts got them, every metadata sync ships with one, and CI now enforces both counterpart existence and counterpart content on every migration change.
- UI layering / DOM discipline phase 4: coverage and gates extended across ~22 more Angular packages.
- Docker
:latestnow tracks certified builds only — Edge releases deliberately publish no image. - Release machinery hardened end-to-end: era-gated dist-tag routing (
edgefrom the version grammar; an unsuffixed 6.x version is refused on the routine path), a registry-truth verification step after every publish, rerun-safe tag/release steps, and thisreleases/directory documented as the canonical notes record. - CI reliability: the migration gate’s concurrency group is keyed per-ref (it could previously only be green on one PR at a time), and turbo’s cache is persisted across runs.
Bug Fixes
Section titled “Bug Fixes”statusUpdatespush subscriptions bound to authenticated identity (@memberjunction/server): the subscription previously trusted the client-suppliedsessionIdalone, so obtaining another user’s session id was enough to receive their pushes. Every push now carries the owner’s user ID and the filter requires it to match the connection’s server-authenticated identity, failing closed; all ~22 publish sites route through one helper whose requiredownerUserIdfield makes the omission uncompilable.- Agent memory writes could leak one user’s memory to every user of the agent (
@memberjunction/ai-agents):MemoryWriteManagertracked the notes written during a run by ID alone. Because the near-duplicate search deliberately does not filter out agent-wide (UserID IS NULL) notes when a user is supplied, a user-scoped write would find an agent-scoped note written moments earlier in the same run and supersede it — rewriting its text but never itsUserID. One memory was lost outright, and the survivor held user-specific content at agent-wide scope, readable by everyone else using that agent. Write bookkeeping is now keyed by scope, the within-run idempotency hash is scope-qualified (identical text at two scopes is two memories, not a duplicate), and the exact-restatement path can no longer route a cross-scope note into the touch-and-drop branch. - SQL parameterization/escaping hardening (
@memberjunction/server,@memberjunction/generic-database-provider):CreateReportFromConversationDetailIDnow binds its argument as a typed parameter, and the RLS record-check path escapes primary-key values the way the siblingLoad()path always did. - Transactions were published before they were begun (
@memberjunction/sqlserver-dataprovider,@memberjunction/postgresql-dataprovider):BeginTransactionmade the transaction object visible to other callers before the driver had actually started it, so concurrent work could enlist in a transaction that did not yet exist and poison the connection for everything that followed. Fixed identically on both providers. AIPromptRun.AgentIDwas never populated (@memberjunction/ai-agents,@memberjunction/ai-prompts): prompt runs recorded no link back to the agent that issued them, leaving agent-level cost, latency and failure analysis unattributable.BaseAgentandAIPromptRunnernow stamp it.AgentRunner.RunAgentnever hydrated conversation artifacts (@memberjunction/ai-agents): agents invoked through this entry point could not see artifacts attached to the conversation, so any prompt depending on one silently ran without it.- Metadata cache was refreshing every ~50 hours instead of every 3 minutes (
@memberjunction/server,@memberjunction/sqlserver-dataprovider): a milliseconds-vs-seconds unit mismatch multiplied the configured interval by 1000 — the likely root cause of “stale metadata until MJAPI restart.” Both halves of the conversion fixed together. - Duplicate rows in BaseEngine caches from UUID casing (
@memberjunction/core): primary-key matching in cache maintenance now compares UUID columns case-insensitively (metadata-driven, PG-aware), so a lowercase client-minted id and its uppercase SQL Server twin no longer append duplicates. - Explorer loading screen can no longer hang forever (
@memberjunction/ng-shared,@memberjunction/ng-dashboards):BaseDashboardguaranteesNotifyLoadComplete()fires even when a resource’s load throws — previously any full reload of a deep URL while the API was momentarily down stranded the whole shell on the loading screen. - Session landing decoupled from the app switcher’s sort order (
@memberjunction/ng-explorer-core): fresh sessions (magic links included) now land on the declared-default app instead of whatever the user dragged to the top, and the landing path validates a candidate’s default tab before activating it instead of stranding the session. @memberjunction/ng-file-storagepinnedng-notificationsat5.51.0, resolving the published package from the registry instead of linking the local6.0.0sibling — corrected.- UI-layers gate deadlock: a manifest dependency declaration backing a marker-excused import no longer trips the layering gate while the dependency-check gate simultaneously requires it.