package storage import ( "net/url" "strings" ) // NormalizeObjectKey converts stored avatar/object refs to a stable S3 object key. // Accepts legacy full URLs, /{bucket}/... paths, or raw keys like avatars/{tenant}/{uid}.png. func NormalizeObjectKey(bucket, ref string) string { ref = strings.TrimSpace(ref) if ref == "" || bucket == "" { return ref } bucket = strings.Trim(bucket, "/") ref = strings.Trim(ref, "/") if strings.Contains(ref, "://") { parsed, err := url.Parse(ref) if err != nil { return ref } ref = strings.Trim(parsed.Path, "/") } prefix := bucket + "/" if strings.HasPrefix(ref, prefix) { return strings.TrimPrefix(ref, prefix) } if strings.HasPrefix(ref, "/"+prefix) { return strings.TrimPrefix(strings.TrimPrefix(ref, "/"), prefix) } return ref } // PublicObjectPath builds a same-origin browser path: /{bucket}/{key}. func PublicObjectPath(bucket, key string) string { bucket = strings.Trim(strings.TrimSpace(bucket), "/") key = strings.Trim(strings.TrimSpace(key), "/") if bucket == "" || key == "" { return "" } return "/" + bucket + "/" + key }