···525525526526 // Test that all expected templates are loaded
527527 expectedTemplates := []string{
528528- "base.html",
529528 "nav",
530529 "repo-card",
531530 "repository",
+6-3
pkg/atproto/lexicon.go
···406406}
407407408408// ResolveHoldDIDFromURL converts a hold endpoint URL to a did:web DID
409409-// For did:web holds: https://hold01.atcr.io → did:web:hold01.atcr.io
410410-// If input is already a DID, returns it as-is
409409+// This ensures that different representations of the same hold are deduplicated:
410410+// - http://172.28.0.3:8080 → did:web:172.28.0.3:8080
411411+// - http://hold01.atcr.io → did:web:hold01.atcr.io
412412+// - https://hold01.atcr.io → did:web:hold01.atcr.io
413413+// - did:web:hold01.atcr.io → did:web:hold01.atcr.io (passthrough)
411414func ResolveHoldDIDFromURL(holdURL string) string {
412415 // Handle empty URLs
413416 if holdURL == "" {
···415418 }
416419417420 // If already a DID, return as-is
418418- if strings.HasPrefix(holdURL, "did:") {
421421+ if IsDID(holdURL) {
419422 return holdURL
420423 }
421424
+2-3
pkg/auth/oauth/client.go
···2020type App struct {
2121 clientApp *oauth.ClientApp
2222 baseURL string
2323- directory identity.Directory
2423}
25242625// NewApp creates a new OAuth app for ATCR with default scopes
···3231func NewAppWithScopes(baseURL string, store oauth.ClientAuthStore, scopes []string) (*App, error) {
3332 config := NewClientConfigWithScopes(baseURL, scopes)
3433 clientApp := oauth.NewClientApp(&config, store)
3434+ clientApp.Dir = atproto.GetDirectory()
35353636 return &App{
3737 clientApp: clientApp,
3838 baseURL: baseURL,
3939- directory: atproto.GetDirectory(),
4039 }, nil
4140}
4241···102101103102// Directory returns the identity directory used by the OAuth app
104103func (a *App) Directory() identity.Directory {
105105- return a.directory
104104+ return a.clientApp.Dir
106105}
107106108107// ClientIDWithScopes generates a client ID with custom scopes
+2-2
pkg/hold/pds/xrpc.go
···263263264264 // Normalize actor to DID
265265 actorDID := actor
266266- if !strings.HasPrefix(actor, "did:") {
266266+ if !atproto.IsDID(actor) {
267267 // It's a handle, resolve to DID
268268 expectedHandle := strings.TrimPrefix(h.pds.DID(), "did:web:")
269269 if actor == expectedHandle {
···306306 for _, actor := range actors {
307307 // Normalize actor to DID
308308 actorDID := actor
309309- if !strings.HasPrefix(actor, "did:") {
309309+ if !atproto.IsDID(actor) {
310310 // It's a handle, check if it matches
311311 if actor == expectedHandle {
312312 actorDID = h.pds.DID()