feat: standardized trigger for DWN endpoint changes on connected identities#1284
Draft
poindex-bot wants to merge 2 commits into
Draft
feat: standardized trigger for DWN endpoint changes on connected identities#1284poindex-bot wants to merge 2 commits into
poindex-bot wants to merge 2 commits into
Conversation
…tities Connected apps previously stayed unaware of a DID's DWN service-endpoint add/remove until a full disconnect/reconnect, because endpoints are only re-derived by re-resolving the DID and that resolution freezes in the AgentDidResolverCache. This adds a prompt, standardized trigger: - refresh primitive + connection-endpoints-changed event (agent/auth/api) - published serviceConfig announcement protocol + wallet publish + dapp watch The DID document remains authoritative; the announcement only prompts a fresh resolution.
…+ simplify Rebased onto the merged enboxorg#1283 sync work, plus behavior-preserving cleanups. sync-engine-level.ts: - invalidateSyncTargets() now delegates to the canonical invalidateSyncTargetsCache() that enboxorg#1283 introduced (and which also resets the new _syncTargetsLastResolutionComplete flag), instead of inlining a stale copy of the invalidation triple. enboxorg#1283 consolidated that triple specifically to stop it drifting across call sites; this avoids reintroducing the drift. service-config.ts (behavior-preserving): - publishServiceConfig: build messageParams with a conditional spread instead of an explicitly-typed object plus post-write mutation. - fanOutServiceConfigRecord: reuse the endpoints the caller already resolved rather than resolving getRemoteDwnEndpointUrls a second time; an empty set is the no-op path, which drops the redundant resolution and its try/catch.
poindex-bot
force-pushed
the
feat/dwn-endpoint-change-trigger
branch
from
July 16, 2026 19:10
9cf35ae to
d38e2b1
Compare
LiranCohen
marked this pull request as draft
July 16, 2026 19:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a standardized, near-real-time trigger so a connected app learns that a DID's DWN service endpoints changed (a DWN added/removed) without a disconnect/reconnect.
Why it was needed
Endpoints live only in the DID document and are re-derived on every operation by re-resolving the connected DID. That resolution freezes in the
AgentDidResolverCache(15 min TTL, longer for store-managed DIDs), the connect grant carries no endpoints, and the session stores none — so a wallet-side change was invisible to a live session until the cache turned over or the app reconnected. There was no event, push, or session-update path.What this adds
Layer 0 — refresh primitive + event
AgentDidApi.refreshResolution(did)— evict the cached resolution and re-resolve.SyncEngineLevel.invalidateSyncTargets()— drop the memoized sync-target endpoints (also onsetDwnEndpoints, closing the ~30 s stale window).AgentIdentityApi.refreshDwnEndpoints(did)— composes both.AuthManager.refreshConnection()/Enbox.refreshConnection()— re-resolve the connected DID and emit the newconnection-endpoints-changedevent with theadded/removeddelta.Layer 1 — service-config announcement (the trigger)
serviceConfigDWN protocol (owner-write,anyoneread).setDwnEndpoints()publishes a "poke" record by default (announce: falseopts out;publishServiceConfig()triggers it standalone).serviceConfigProtocolRequest()(read-only) to their connectprotocolsand callingAuthManager.startServiceConfigWatch(). Requesting the protocol yields the standardMessages.Readgrant, so the record replicates via sync; the watch subscribes locally and callsrefreshConnection()on change. Because apps go through the agent abstraction, the refresh happens in place — the cachedEnboxinstance keeps working against the new endpoints.No changes to the security-sensitive connect approval ceremony. The record is a poke only — the DID document stays authoritative (the dapp re-resolves and adopts that), so there is no new trust surface. Connect never issues
Records.Subscribegrants, so observers subscribe as the delegate and read the public record.Opt-in is conservative: the dapp-side watch and the connect-request protocol are explicit (like
startConnectionMonitor). Auto-appending the protocol inconnect()is a deliberate follow-up.Known edge case
Full migration to a brand-new DWN the app never synced can't deliver the poke over the old channel — covered by the resolver-TTL fallback; a migrating wallet should dual-write the announcement to old + new DWNs during the window.
Test plan
bun run lint— clean across the workspacebun run build— 17/17 packagespackages/agent/tests/service-config.spec.ts(4) —refreshResolutionevicts+re-resolves;publishServiceConfiginstalls protocol + writes a readable record; updates the single record in place;setDwnEndpoints({ announce: false })publishes nothingpackages/auth/tests/connect-endpoints.spec.ts(6) —refreshConnectionadd/remove/unchanged deltas + event, resolution-failure baseline, session guardspackages/agentidentity-api.spec(28) anddid-api.spec(64) — no regressionspackages/authfulltest:node— 576 pass, 0 fail@enbox/agent test:nodein CI (includese2e-*specs needing a:3000server)Rollout notes
@enbox/agent,@enbox/auth,@enbox/apiat patch (internal deps auto-patch).setDwnEndpoints()now publishes a service-config record by default and invalidates the local sync-targets cache. Publishing is best-effort (never fails the endpoint update); passannounce: falsefor the old pure-update behavior.