@@ -11,24 +11,43 @@ use crate::{prelude::*, store_id::IdMapping};
1111/// Each line has the format `<canister_name>.<env_name>.<domain>:<principal>`.
1212/// The file is written fresh each time from the full set of current mappings
1313/// across all environments sharing this network.
14+ ///
15+ /// `extra_entries` are raw `(full_domain, canister_id)` pairs appended after the
16+ /// environment-based entries (e.g. system canisters like Internet Identity).
1417pub fn write_custom_domains (
1518 status_dir : & Path ,
1619 domain : & str ,
1720 env_mappings : & BTreeMap < String , IdMapping > ,
21+ extra_entries : & [ ( String , String ) ] ,
1822) -> Result < ( ) , WriteCustomDomainsError > {
1923 let file_path = status_dir. join ( "custom-domains.txt" ) ;
20- let content: String = env_mappings
24+ let mut content: String = env_mappings
2125 . iter ( )
2226 . flat_map ( |( env_name, mappings) | {
2327 mappings
2428 . iter ( )
2529 . map ( move |( name, principal) | format ! ( "{name}.{env_name}.{domain}:{principal}\n " ) )
2630 } )
2731 . collect ( ) ;
32+ for ( full_domain, canister_id) in extra_entries {
33+ content. push_str ( & format ! ( "{full_domain}:{canister_id}\n " ) ) ;
34+ }
2835 crate :: fs:: write ( & file_path, content. as_bytes ( ) ) ?;
2936 Ok ( ( ) )
3037}
3138
39+ /// Returns the custom domain entry for the II frontend canister, if II is enabled.
40+ pub fn ii_custom_domain_entry ( ii : bool , domain : & str ) -> Option < ( String , String ) > {
41+ if ii {
42+ Some ( (
43+ format ! ( "id.ai.{domain}" ) ,
44+ icp_canister_interfaces:: internet_identity:: INTERNET_IDENTITY_FRONTEND_CID . to_string ( ) ,
45+ ) )
46+ } else {
47+ None
48+ }
49+ }
50+
3251/// Extracts the domain authority from a gateway URL for use in subdomain-based
3352/// canister routing.
3453///
@@ -110,7 +129,7 @@ mod tests {
110129 ) ;
111130 env_mappings. insert ( "staging" . to_string ( ) , staging_mappings) ;
112131
113- write_custom_domains ( dir. path ( ) , "localhost" , & env_mappings) . unwrap ( ) ;
132+ write_custom_domains ( dir. path ( ) , "localhost" , & env_mappings, & [ ] ) . unwrap ( ) ;
114133
115134 let content = std:: fs:: read_to_string ( dir. path ( ) . join ( "custom-domains.txt" ) ) . unwrap ( ) ;
116135 // BTreeMap is ordered, so local comes before staging
@@ -122,6 +141,38 @@ mod tests {
122141 ) ;
123142 }
124143
144+ #[ test]
145+ fn write_custom_domains_with_extra_entries ( ) {
146+ let dir = camino_tempfile:: Utf8TempDir :: new ( ) . unwrap ( ) ;
147+ let env_mappings = BTreeMap :: new ( ) ;
148+ let extra = vec ! [ (
149+ "id.ai.localhost" . to_string( ) ,
150+ "uqzsh-gqaaa-aaaaq-qaada-cai" . to_string( ) ,
151+ ) ] ;
152+
153+ write_custom_domains ( dir. path ( ) , "localhost" , & env_mappings, & extra) . unwrap ( ) ;
154+
155+ let content = std:: fs:: read_to_string ( dir. path ( ) . join ( "custom-domains.txt" ) ) . unwrap ( ) ;
156+ assert_eq ! ( content, "id.ai.localhost:uqzsh-gqaaa-aaaaq-qaada-cai\n " ) ;
157+ }
158+
159+ #[ test]
160+ fn ii_custom_domain_entry_returns_entry_when_enabled ( ) {
161+ let entry = ii_custom_domain_entry ( true , "localhost" ) ;
162+ assert_eq ! (
163+ entry,
164+ Some ( (
165+ "id.ai.localhost" . to_string( ) ,
166+ "uqzsh-gqaaa-aaaaq-qaada-cai" . to_string( )
167+ ) )
168+ ) ;
169+ }
170+
171+ #[ test]
172+ fn ii_custom_domain_entry_returns_none_when_disabled ( ) {
173+ assert_eq ! ( ii_custom_domain_entry( false , "localhost" ) , None ) ;
174+ }
175+
125176 #[ test]
126177 fn canister_gateway_url_with_friendly_domain ( ) {
127178 let base: Url = "http://localhost:8000" . parse ( ) . unwrap ( ) ;
0 commit comments