66 RegisteredMutation ,
77 RegisteredQuery ,
88} from "./registration.js" ;
9- import { Expand , UnionToIntersection } from "../type_utils.js" ;
9+ import type { UnionToIntersection } from "../type_utils.js" ;
1010import { PaginationOptions , PaginationResult } from "./pagination.js" ;
1111import { functionName } from "./functionName.js" ;
1212import { getFunctionAddress } from "./components/paths.js" ;
@@ -226,7 +226,7 @@ type FunctionReferencesInModule<Module extends Record<string, any>> = {
226226 - readonly [ ExportName in keyof Module as Module [ ExportName ] [ "isConvexFunction" ] extends true
227227 ? ExportName
228228 : never ] : FunctionReferenceFromExport < Module [ ExportName ] > ;
229- } ;
229+ } & unknown ;
230230
231231/**
232232 * Given a path to a module and it's type, generate an API type for this module.
@@ -236,11 +236,17 @@ type FunctionReferencesInModule<Module extends Record<string, any>> = {
236236type ApiForModule <
237237 ModulePath extends string ,
238238 Module extends object ,
239- > = ModulePath extends `${infer First } /${infer Second } `
240- ? {
241- [ _ in First ] : ApiForModule < Second , Module > ;
242- }
243- : { [ _ in ModulePath ] : FunctionReferencesInModule < Module > } ;
239+ LastPathWasSegmented extends boolean ,
240+ > =
241+ ModulePath extends SegmentedPath < infer First , infer Rest >
242+ ? {
243+ [ _ in First ] : ApiForModule < Rest , Module , true > ;
244+ }
245+ : LastPathWasSegmented extends true
246+ ? {
247+ [ _ in ModulePath ] : FunctionReferencesInModule < Module > ;
248+ }
249+ : FunctionReferencesInModule < Module > ;
244250
245251/**
246252 * Given the types of all modules in the `convex/` directory, construct the type
@@ -253,40 +259,61 @@ type ApiForModule<
253259 * @public
254260 */
255261export type ApiFromModules < AllModules extends Record < string , object > > =
256- FilterApi <
257- ApiFromModulesAllowEmptyNodes < AllModules > ,
258- FunctionReference < any , any , any , any >
259- > ;
262+ keyof AllModules & SegmentedPath extends never
263+ ? ApiFromNonSegmentedModules < AllModules >
264+ : ApiFromSegmentedModules < AllModules > ;
265+
266+ // fast path for cases with no segmented modules
267+ type ApiFromNonSegmentedModules < AllModules extends Record < string , object > > = {
268+ [ ModulePath in keyof AllModules as keyof FunctionReferencesInModule <
269+ AllModules [ ModulePath ]
270+ > extends never
271+ ? never
272+ : ModulePath ] : FunctionReferencesInModule < AllModules [ ModulePath ] > ;
273+ } ;
260274
261- type ApiFromModulesAllowEmptyNodes < AllModules extends Record < string , object > > =
275+ type ApiFromSegmentedModules < AllModules extends Record < string , object > > =
262276 ExpandModulesAndDirs <
263- UnionToIntersection <
264- {
265- [ ModulePath in keyof AllModules ] : ApiForModule <
266- ModulePath & string ,
267- AllModules [ ModulePath ]
268- > ;
269- } [ keyof AllModules ]
270- >
277+ IntersectUnionProperties < {
278+ [ ModulePath in keyof AllModules as FirstSegment < ModulePath > ] : ModulePath extends SegmentedPath <
279+ string ,
280+ infer Rest
281+ >
282+ ? ApiForModule < Rest , AllModules [ ModulePath ] , true >
283+ : ApiForModule < ModulePath & string , AllModules [ ModulePath ] , false > ;
284+ } >
271285 > ;
272286
287+ type IntersectUnionProperties < O extends object > = {
288+ [ K in keyof O ] : UnionToIntersection < O [ K ] > ;
289+ } ;
290+
291+ type SegmentedPath <
292+ First extends string = string ,
293+ Rest extends string = string ,
294+ > = `${First } /${Rest } `;
295+
296+ type FirstSegment < ModulePath > =
297+ ModulePath extends SegmentedPath < infer First > ? First : ModulePath ;
298+
273299/**
274300 * @public
275301 *
276302 * Filter a Convex deployment api object for functions which meet criteria,
277303 * for example all public queries.
278304 */
279- export type FilterApi < API , Predicate > = Expand < {
305+ export type FilterApi < API , Predicate > = {
280306 [ mod in keyof API as API [ mod ] extends Predicate
281307 ? mod
282- : API [ mod ] extends FunctionReference < any , any , any , any >
308+ : API [ mod ] extends AnyFunctionReference
283309 ? never
284- : FilterApi < API [ mod ] , Predicate > extends Record < string , never >
310+ : { } extends FilterApi < API [ mod ] , Predicate >
285311 ? never
286312 : mod ] : API [ mod ] extends Predicate
287313 ? API [ mod ]
288314 : FilterApi < API [ mod ] , Predicate > ;
289- } > ;
315+ // equivalent to Expand without requiring another mapped type
316+ } & unknown ;
290317
291318/**
292319 * Given an api of type API and a FunctionReference subtype, return an api object
@@ -365,12 +392,18 @@ export function justSchedulable<API>(
365392 * The differences are:
366393 * 1. This version is recursive.
367394 * 2. This stops recursing when it hits a {@link FunctionReference}.
395+ * 3. This omits empty object properties
368396 */
369- type ExpandModulesAndDirs < ObjectType > = ObjectType extends AnyFunctionReference
370- ? ObjectType
371- : {
372- [ Key in keyof ObjectType ] : ExpandModulesAndDirs < ObjectType [ Key ] > ;
373- } ;
397+ type ExpandModulesAndDirs < ObjectType > =
398+ ObjectType extends Record < string , AnyFunctionReference >
399+ ? ObjectType
400+ : {
401+ [ Key in keyof ObjectType as keyof ExpandModulesAndDirs <
402+ ObjectType [ Key ]
403+ > extends never
404+ ? never
405+ : Key ] : ExpandModulesAndDirs < ObjectType [ Key ] > ;
406+ } ;
374407
375408/**
376409 * A {@link FunctionReference} of any type and any visibility with any
0 commit comments