@@ -198,6 +198,30 @@ class PackageBackend {
198198 return await db.lookupOrNull <ReservedPackage >(packageKey);
199199 }
200200
201+ /// Lists the currently reserved package names. A reserved package prefix is a regular name
202+ /// that ends with `_` (underscore).
203+ ///
204+ /// List the prefixes in descending length for easier matching.
205+ Future <List <String >> listReservedPackagePrefixes () async {
206+ return await cache.reservedPackagePrefixes ().get (() async {
207+ final list = < String > [];
208+ await for (final p in db.query <ReservedPackage >().run ()) {
209+ final name = p.name;
210+ if (name != null && name.endsWith ('_' )) {
211+ list.add (name);
212+ }
213+ }
214+ list.sort ((a, b) {
215+ if (a.length != b.length) {
216+ return - a.length.compareTo (b.length);
217+ }
218+ return a.compareTo (b);
219+ });
220+ return list;
221+ })
222+ as List <String >;
223+ }
224+
201225 /// Looks up a package by name.
202226 Future <List <Package >> lookupPackages (Iterable <String > packageNames) async {
203227 return (await db.lookup (
@@ -1191,7 +1215,18 @@ class PackageBackend {
11911215 required String name,
11921216 required AuthenticatedAgent agent,
11931217 }) async {
1194- final reservedPackage = await lookupReservedPackage (name);
1218+ // Apply either the exact-name reserved package lookup, or the closest prefix (ending with '_').
1219+ var reservedPackage = await lookupReservedPackage (name);
1220+ if (reservedPackage == null ) {
1221+ // lookup prefixes
1222+ final prefixes = await listReservedPackagePrefixes ();
1223+ for (final prefix in prefixes) {
1224+ if (name.startsWith (prefix)) {
1225+ reservedPackage = await lookupReservedPackage (prefix);
1226+ break ;
1227+ }
1228+ }
1229+ }
11951230
11961231 bool isAllowedUser = false ;
11971232 if (agent is AuthenticatedUser ) {
0 commit comments