Skip to content

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.

  • 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-existing Integration seed rows collide with or dangle against the re-pointed Open Apps (five installs hard-fail on UQ_Integration_Name) — check the upgrade guide before installing a connector Open App on an upgraded database.
  • ActionExecutionLog.Params now records the as-called inputs only — the final merged parameter set (inputs plus action outputs) moved to the new ResultParams column. Nothing errors: anything reading Params for an action’s outputs silently gets inputs instead. Repoint output-readers at ResultParams; input-readers are now more correct than before.
  • @memberjunction/aiengine removed its bespoke similarity APIsFindSimilarAgents/FindSimilarActions, RefreshAgentEmbeddings/RefreshActionEmbeddings, and the agent/action vector-service getters are gone in favor of the unified Provider.SearchEntity pipeline (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 catalogsSQLExpressionValidator now rejects sys.*, 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 with HS256 (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 forecloses alg=none and RS256→HS256 confusion attacks.
  • Negation-form RLS filters (<>, NOT IN, NOT LIKE) now match fewer rows when the substituted user property is undefined — 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.

  • Entity Action workflow extensions (@memberjunction/core-entities, @memberjunction/actions): EntityAction becomes the general workflow-hook substrate across MJ and every Open App — building on the existing save-path wiring (blocking Validate, 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. Previously BaseViewGenerated = 0 was 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): RowFilterID added to APIKeyScope and APIApplicationScope as nullable FKs into the existing RowLevelSecurityFilter catalog — 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 into SearchScopePermission or forking the search path.
  • Per-verb direct-SQL declarations on entities (@memberjunction/core): Entity can now declare, per verb, whether SQL that bypasses BaseEntity may write it — making the “everything flows through Save()/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 generic mj-bottom-sheet primitive.
  • Theme-aware registry components (@memberjunction/react-runtime, @memberjunction/interactive-component-types): ComponentStyles gains sequential/diverging visualization ramps backed by new theme tokens; ComponentSpec gains styleOverrides so 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.voice now reaches the session as the tts.voice_id override 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-type EntityDocument pipeline.
  • New @memberjunction/standards package: the repo’s adopted-standards checks, packaged.
  • 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 of sys.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 :latest now tracks certified builds only — Edge releases deliberately publish no image.
  • Release machinery hardened end-to-end: era-gated dist-tag routing (edge from 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 this releases/ 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.
  • statusUpdates push subscriptions bound to authenticated identity (@memberjunction/server): the subscription previously trusted the client-supplied sessionId alone, 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 required ownerUserId field makes the omission uncompilable.
  • Agent memory writes could leak one user’s memory to every user of the agent (@memberjunction/ai-agents): MemoryWriteManager tracked 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 its UserID. 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): CreateReportFromConversationDetailID now binds its argument as a typed parameter, and the RLS record-check path escapes primary-key values the way the sibling Load() path always did.
  • Transactions were published before they were begun (@memberjunction/sqlserver-dataprovider, @memberjunction/postgresql-dataprovider): BeginTransaction made 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.AgentID was 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. BaseAgent and AIPromptRunner now stamp it.
  • AgentRunner.RunAgent never 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): BaseDashboard guarantees NotifyLoadComplete() 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-storage pinned ng-notifications at 5.51.0, resolving the published package from the registry instead of linking the local 6.0.0 sibling — 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.