v6.1.0-edge.4: Identity Claims, layered views on PostgreSQL, and hardened networking
The fifth Edge build of the 6.1 line, and a tighter one than its predecessor — 44 changesets, weighted toward closing gaps rather than opening surface. Three things stand out: Identity Claims arrives as core infrastructure for guest-record claiming and account linking; layered base views now work on PostgreSQL, which had thrown outright since the feature shipped; and outbound HTTP gets a real security boundary, with axios removed from the repository in favour of a new SSRF-aware @memberjunction/network-utils. Underneath, two genuine memory leaks in MJServer and a run of integration-connector fixes whose common theme is a run that stops should not lose its place.
Edge builds are prereleases. They publish under the edge dist-tag and never move latest.
New Features
Section titled “New Features”- Identity Claims. Core infrastructure for guest record claiming, account linking and invite verification (#4012), shipped with its redemption surface rather than as a schema-only foundation. Reads of
MJ: Identity Claimsare scoped to the requesting user, and redemption is decoupled from that read grant so claiming never requires handing out visibility of other people’s claims. Domain-specificGuestOrder/PersonAccountLinkclaim types were deliberately removed from core — those belong to BizApps, not to the platform. @memberjunction/network-utils, andaxiosis gone from the repository. A new server-side package providing SSRF-safe URL validation and a hardened fetch. Server-side web/HTTP actions now block private, loopback, link-local (including the cloud metadata address169.254.169.254) and reserved ranges, and re-validate on redirect — the step that makes an allowlist actually hold.- Layered base views work on PostgreSQL. CodeGen writes the inner view and restars the application-owned outer wrapper so
g.*re-expands after the inner one regenerates. PreviouslyPostgreSQLCodeGenProvider.generateBaseViewthrew on a layered entity, so the arrangement was SQL-Server-only. - CodeGen emits a composite index over an entity’s soft primary key — a gap where nothing in the stack had ever indexed one.
entityImportPackages— CodeGen now imports peer entity classes (embeds, related-record collections) from the npm package that owns them, instead of self-importing a stringentityPackage.- A connector can declare a source field excluded from sync, and integration-object fields are indexed with the per-record field view memoised.
EscapeSQLStringin@memberjunction/global— one canonical escape for string literals in SQL statements, clauses andExtraFilterpredicates, adopted across core packages.- Optional
@IncludedSchemaNameson the CodeGen metadata-heal procedures, so an Open App migration can positively scope its heal instead of photographing sibling apps, with cascade-delete kept inside the schema. - The weekly AI model refresh (2026-08-24 report) lands with the release rather than after it.
Improvements
Section titled “Improvements”- Two real memory leaks in MJServer, both from process-wide subscriptions.
ProviderBase.ensureInflightViewInvalidation()subscribed toMJGlobal’s event bus once per provider instance and never unsubscribed;SessionManager.heartbeatLastWritewas a plain unboundedMapin a class constructed fresh by every resolver that needs one, plusSessionJanitor. Both grew for the life of the process. - A restart no longer turns concurrent syncs into a queue — resume preserves the concurrency the original run had, instead of serialising what was parallel.
- Mid-run watermark durability floor. A watermark-based connector previously had no durable position at all until its run ended, so a SIGKILL, OOM or container eviction lost the entire run’s progress. This is the watermark twin of the existing keyset checkpoint.
- Discovery is bounded and observable — a deadline plus a watchdog — and it can recognise a rate limit again: its throttle test could never return true, so a throttled source looked like a slow one.
Retry-Afteris honoured between fetch attempts, with a rate token re-acquired on each retry, and a transport failure is retryable again — the classifier now reads the error’scausechain rather than only its message, whichundicimoved the detail out of.- Reactivating a connection no longer blocks on a live schema introspect, and a failed refresh is no longer reported as a clean zero-count one.
- Geocoding stops re-attempting an address it has already determined has no location.
- Custom-column promotion is one RSU pass.
PromoteForSyncused to run the full migrate + CodeGen + compile pipeline once per entity; it also now clears the staging JSON and stops re-offering columns it already created, and an interrupted spread is recoverable rather than a dead end. - Open App migrations heal afterwards.
mj migrate --schemaandmj app installnow run the core metadata-heal steps on both platforms, and CodeGen stops generating GRANT files forexcludeSchemasentities — which had been failing Open App runs withCannot find the object 'vw…'on sibling-schema permission files. - One covering index for every record-map lookup, with the per-record write path matching the batched one.
- Two hot-path costs removed from
MJGlobalwith byte-identical behaviour (lazyClassFactorydiagnostics). mj codegen manifestrecognises@RegisterClassExalongside@RegisterClass, in both the TypeScript-source and compiled-__decoratescan paths — classes registered the newer way were being tree-shaken out.- The T-SQL→PostgreSQL converter now FAILS on a statement it cannot parse instead of continuing. Silent partial conversion is the failure mode behind several of this cycle’s PostgreSQL defects.
- PostgreSQL counterparts for this release’s migrations, verified by a clean
mj migrateof all 72 migrations against a database built from nothing, thenmj sync pushwriting 13,854 records with zero errors.
Bug Fixes
Section titled “Bug Fixes”__mj.FileEntityRecordLink’s unique key omittedRecordID, so a file could attach to only one record per entity — in the table whose entire purpose is the generic file-to-any-record many-to-many (#3943). The v5.37 junction-table sweep’s “natural key is a pair of foreign keys” heuristic mechanically picked(EntityID, FileID)and dropped the soft key that makes a row distinct. Fixed on both platforms.- Ad-hoc SQL is refused for scope-limited sessions, and
ResolverBasenow escapes the filters it builds itself. spRebindLayeredOuterViewcould never restar a layered outer view on PostgreSQL — it shipped with an undeclaredv_starredvariable, and PL/pgSQL compiles the whole body on first call, so the routine failed as a unit.- A new schema now gets its
Applicationrow on PostgreSQL (identifier quoting in the insert). - Records with no value for their soft primary key are refused rather than written unaddressable, and within-batch
ExternalIDidentity is enforced before mapping. - An explicit MAX width (
-1) survives discovery instead of being silently narrowed. ProviderBase’s write-invalidation fan-out re-subscribes when theMJGlobalevent bus is replaced. Its one-time wiring guard was a boolean, which cannot notice thatMJGlobal.Reset()swapped the bus underneath it.UserInfoEngine’s debounced settings flush no longer raises a process-level unhandled rejection.DownloadMigrationsfetches what skyway will actually run (recursively), and an empty download now fails instead of passing.- The
UserCacheexport is kept alive for published consumers. - The retired GLM-4.7 Cerebras cost record uses a
Statusits entity actually allows.