@arinoto/cdk-arch 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,48 @@
1
1
  import { Construct } from 'constructs';
2
2
  import { Function } from './function';
3
- export interface ApiRoutes {
4
- [name: string]: RouteEntry;
5
- }
6
- export interface RouteEntry {
3
+ /**
4
+ * A route entry that captures the handler's argument and return types.
5
+ */
6
+ export interface RouteEntry<TArgs extends any[] = any[], TReturn = any> {
7
7
  path: string;
8
- handler: Function;
8
+ handler: Function<TArgs, TReturn>;
9
9
  }
10
10
  /**
11
- * Represents an API container that routes requests to functions
11
+ * Base type for route definitions - maps route names to route entries.
12
+ */
13
+ export type ApiRoutes = {
14
+ [name: string]: RouteEntry;
15
+ };
16
+ /**
17
+ * Extract the handler signature from a Function type.
18
+ */
19
+ export type HandlerOf<T> = T extends Function<infer Args, infer Return> ? (...args: Args) => Promise<Return> : never;
20
+ /**
21
+ * Extract handler signatures from all routes in an ApiRoutes type.
22
+ */
23
+ export type RouteHandlers<TRoutes extends ApiRoutes> = {
24
+ [K in keyof TRoutes]: HandlerOf<TRoutes[K]['handler']>;
25
+ };
26
+ /**
27
+ * Represents an API container that routes requests to functions.
28
+ *
29
+ * @typeParam TRoutes - The type of the routes object, preserving route names and handler signatures.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const api = new ApiContainer(arch, 'api', {
34
+ * hello: { path: 'GET /v1/api/hello/{name}', handler: helloFunction },
35
+ * hellos: { path: 'GET /v1/api/hellos', handler: hellosFunction }
36
+ * });
37
+ * // api has type ApiContainer<{ hello: RouteEntry<[string], string>, hellos: RouteEntry<[], Greeting[]> }>
38
+ * ```
12
39
  */
13
- export declare class ApiContainer extends Construct {
14
- readonly routes: ApiRoutes;
15
- constructor(scope: Construct, id: string, routes?: ApiRoutes);
16
- addRoute(name: string, path: string, handler: Function): void;
17
- getRoute(name: string): RouteEntry;
18
- listRoutes(): string[];
40
+ export declare class ApiContainer<TRoutes extends ApiRoutes = ApiRoutes> extends Construct {
41
+ readonly routes: TRoutes;
42
+ constructor(scope: Construct, id: string, routes?: TRoutes);
43
+ addRoute<TArgs extends any[], TReturn>(name: string, path: string, handler: Function<TArgs, TReturn>): void;
44
+ getRoute<K extends keyof TRoutes & string>(name: K): TRoutes[K];
45
+ listRoutes(): (keyof TRoutes & string)[];
19
46
  /**
20
47
  * Returns a list of TBDFunctions that have not been overloaded.
21
48
  * Use this to validate that all required implementations are provided.
@@ -1 +1 @@
1
- {"version":3,"file":"api-container.d.ts","sourceRoot":"","sources":["../src/api-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAe,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,SAAS;IACxB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,SAAS;IACzC,SAAgB,MAAM,EAAE,SAAS,CAAC;gBAEtB,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAE,SAAc;IAKhE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,IAAI;IAI7D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;IAQlC,UAAU,IAAK,MAAM,EAAE;IAIvB;;;OAGG;IACH,iBAAiB,IAAI,QAAQ,EAAE;CAKhC"}
1
+ {"version":3,"file":"api-container.d.ts","sourceRoot":"","sources":["../src/api-container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAe,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,OAAO,GAAG,GAAG;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC5B,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,MAAM,IAAI,EAAE,MAAM,MAAM,CAAC,GACnE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,GAClC,KAAK,CAAC;AAEV;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,SAAS,IAAI;KACpD,CAAC,IAAI,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;CACvD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAY,CAAC,OAAO,SAAS,SAAS,GAAG,SAAS,CAAE,SAAQ,SAAS;IAChF,SAAgB,MAAM,EAAE,OAAO,CAAC;gBAEpB,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,GAAE,OAAuB;IAKzE,QAAQ,CAAC,KAAK,SAAS,GAAG,EAAE,EAAE,OAAO,EACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,GAChC,IAAI;IAIP,QAAQ,CAAC,CAAC,SAAS,MAAM,OAAO,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQ/D,UAAU,IAAI,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE;IAIxC;;;OAGG;IACH,iBAAiB,IAAI,QAAQ,EAAE;CAKhC"}
@@ -4,7 +4,18 @@ exports.ApiContainer = void 0;
4
4
  const constructs_1 = require("constructs");
5
5
  const function_1 = require("./function");
6
6
  /**
7
- * Represents an API container that routes requests to functions
7
+ * Represents an API container that routes requests to functions.
8
+ *
9
+ * @typeParam TRoutes - The type of the routes object, preserving route names and handler signatures.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const api = new ApiContainer(arch, 'api', {
14
+ * hello: { path: 'GET /v1/api/hello/{name}', handler: helloFunction },
15
+ * hellos: { path: 'GET /v1/api/hellos', handler: hellosFunction }
16
+ * });
17
+ * // api has type ApiContainer<{ hello: RouteEntry<[string], string>, hellos: RouteEntry<[], Greeting[]> }>
18
+ * ```
8
19
  */
9
20
  class ApiContainer extends constructs_1.Construct {
10
21
  constructor(scope, id, routes = {}) {
@@ -35,4 +46,4 @@ class ApiContainer extends constructs_1.Construct {
35
46
  }
36
47
  }
37
48
  exports.ApiContainer = ApiContainer;
38
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWNvbnRhaW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hcGktY29udGFpbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF1QztBQUN2Qyx5Q0FBbUQ7QUFXbkQ7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxzQkFBUztJQUd6QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLFNBQW9CLEVBQUU7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztJQUN2QixDQUFDO0lBRUQsUUFBUSxDQUFDLElBQVksRUFBRSxJQUFZLEVBQUUsT0FBaUI7UUFDcEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUN4QyxDQUFDO0lBRUQsUUFBUSxDQUFDLElBQVk7UUFDbkIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsSUFBSSw2QkFBNkIsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzlFLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsaUJBQWlCO1FBQ2YsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7YUFDOUIsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQzthQUMzQixNQUFNLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLFlBQVksc0JBQVcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7Q0FDRjtBQWpDRCxvQ0FpQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IEZ1bmN0aW9uLCBUQkRGdW5jdGlvbiB9IGZyb20gJy4vZnVuY3Rpb24nO1xuXG5leHBvcnQgaW50ZXJmYWNlIEFwaVJvdXRlcyB7XG4gIFtuYW1lOiBzdHJpbmddOiBSb3V0ZUVudHJ5O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJvdXRlRW50cnkge1xuICBwYXRoOiBzdHJpbmc7XG4gIGhhbmRsZXI6IEZ1bmN0aW9uO1xufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgYW4gQVBJIGNvbnRhaW5lciB0aGF0IHJvdXRlcyByZXF1ZXN0cyB0byBmdW5jdGlvbnNcbiAqL1xuZXhwb3J0IGNsYXNzIEFwaUNvbnRhaW5lciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIHB1YmxpYyByZWFkb25seSByb3V0ZXM6IEFwaVJvdXRlcztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCByb3V0ZXM6IEFwaVJvdXRlcyA9IHt9KSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICB0aGlzLnJvdXRlcyA9IHJvdXRlcztcbiAgfVxuXG4gIGFkZFJvdXRlKG5hbWU6IHN0cmluZywgcGF0aDogc3RyaW5nLCBoYW5kbGVyOiBGdW5jdGlvbik6IHZvaWQge1xuICAgIHRoaXMucm91dGVzW25hbWVdID0geyBwYXRoLCBoYW5kbGVyIH07XG4gIH1cblxuICBnZXRSb3V0ZShuYW1lOiBzdHJpbmcpOiBSb3V0ZUVudHJ5IHtcbiAgICBjb25zdCBlbnRyeSA9IHRoaXMucm91dGVzW25hbWVdO1xuICAgIGlmICghZW50cnkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUm91dGUgJyR7bmFtZX0nIG5vdCBmb3VuZCBpbiBjb250YWluZXIgJyR7dGhpcy5ub2RlLmlkfSdgKTtcbiAgICB9XG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG5cbiAgbGlzdFJvdXRlcygpIDogc3RyaW5nW10ge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnJvdXRlcyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIGxpc3Qgb2YgVEJERnVuY3Rpb25zIHRoYXQgaGF2ZSBub3QgYmVlbiBvdmVybG9hZGVkLlxuICAgKiBVc2UgdGhpcyB0byB2YWxpZGF0ZSB0aGF0IGFsbCByZXF1aXJlZCBpbXBsZW1lbnRhdGlvbnMgYXJlIHByb3ZpZGVkLlxuICAgKi9cbiAgdmFsaWRhdGVPdmVybG9hZHMoKTogRnVuY3Rpb25bXSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5yb3V0ZXMpXG4gICAgICAubWFwKGVudHJ5ID0+IGVudHJ5LmhhbmRsZXIpXG4gICAgICAuZmlsdGVyKGZuID0+IGZuIGluc3RhbmNlb2YgVEJERnVuY3Rpb24gJiYgIWZuLmhhc092ZXJsb2FkKCkpO1xuICB9XG59XG4iXX0=
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWNvbnRhaW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hcGktY29udGFpbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF1QztBQUN2Qyx5Q0FBbUQ7QUErQm5EOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFhLFlBQW9ELFNBQVEsc0JBQVM7SUFHaEYsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxTQUFrQixFQUFhO1FBQ3ZFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDakIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELFFBQVEsQ0FDTixJQUFZLEVBQ1osSUFBWSxFQUNaLE9BQWlDO1FBRWhDLElBQUksQ0FBQyxNQUFvQixDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQ3ZELENBQUM7SUFFRCxRQUFRLENBQW1DLElBQU87UUFDaEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsSUFBSSw2QkFBNkIsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzlFLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQStCLENBQUM7SUFDaEUsQ0FBQztJQUVEOzs7T0FHRztJQUNILGlCQUFpQjtRQUNmLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO2FBQzlCLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7YUFDM0IsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxZQUFZLHNCQUFXLElBQUksQ0FBQyxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0NBQ0Y7QUFyQ0Qsb0NBcUNDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBGdW5jdGlvbiwgVEJERnVuY3Rpb24gfSBmcm9tICcuL2Z1bmN0aW9uJztcblxuLyoqXG4gKiBBIHJvdXRlIGVudHJ5IHRoYXQgY2FwdHVyZXMgdGhlIGhhbmRsZXIncyBhcmd1bWVudCBhbmQgcmV0dXJuIHR5cGVzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJvdXRlRW50cnk8VEFyZ3MgZXh0ZW5kcyBhbnlbXSA9IGFueVtdLCBUUmV0dXJuID0gYW55PiB7XG4gIHBhdGg6IHN0cmluZztcbiAgaGFuZGxlcjogRnVuY3Rpb248VEFyZ3MsIFRSZXR1cm4+O1xufVxuXG4vKipcbiAqIEJhc2UgdHlwZSBmb3Igcm91dGUgZGVmaW5pdGlvbnMgLSBtYXBzIHJvdXRlIG5hbWVzIHRvIHJvdXRlIGVudHJpZXMuXG4gKi9cbmV4cG9ydCB0eXBlIEFwaVJvdXRlcyA9IHtcbiAgW25hbWU6IHN0cmluZ106IFJvdXRlRW50cnk7XG59XG5cbi8qKlxuICogRXh0cmFjdCB0aGUgaGFuZGxlciBzaWduYXR1cmUgZnJvbSBhIEZ1bmN0aW9uIHR5cGUuXG4gKi9cbmV4cG9ydCB0eXBlIEhhbmRsZXJPZjxUPiA9IFQgZXh0ZW5kcyBGdW5jdGlvbjxpbmZlciBBcmdzLCBpbmZlciBSZXR1cm4+XG4gID8gKC4uLmFyZ3M6IEFyZ3MpID0+IFByb21pc2U8UmV0dXJuPlxuICA6IG5ldmVyO1xuXG4vKipcbiAqIEV4dHJhY3QgaGFuZGxlciBzaWduYXR1cmVzIGZyb20gYWxsIHJvdXRlcyBpbiBhbiBBcGlSb3V0ZXMgdHlwZS5cbiAqL1xuZXhwb3J0IHR5cGUgUm91dGVIYW5kbGVyczxUUm91dGVzIGV4dGVuZHMgQXBpUm91dGVzPiA9IHtcbiAgW0sgaW4ga2V5b2YgVFJvdXRlc106IEhhbmRsZXJPZjxUUm91dGVzW0tdWydoYW5kbGVyJ10+O1xufTtcblxuLyoqXG4gKiBSZXByZXNlbnRzIGFuIEFQSSBjb250YWluZXIgdGhhdCByb3V0ZXMgcmVxdWVzdHMgdG8gZnVuY3Rpb25zLlxuICpcbiAqIEB0eXBlUGFyYW0gVFJvdXRlcyAtIFRoZSB0eXBlIG9mIHRoZSByb3V0ZXMgb2JqZWN0LCBwcmVzZXJ2aW5nIHJvdXRlIG5hbWVzIGFuZCBoYW5kbGVyIHNpZ25hdHVyZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGFwaSA9IG5ldyBBcGlDb250YWluZXIoYXJjaCwgJ2FwaScsIHtcbiAqICAgaGVsbG86IHsgcGF0aDogJ0dFVCAvdjEvYXBpL2hlbGxvL3tuYW1lfScsIGhhbmRsZXI6IGhlbGxvRnVuY3Rpb24gfSxcbiAqICAgaGVsbG9zOiB7IHBhdGg6ICdHRVQgL3YxL2FwaS9oZWxsb3MnLCBoYW5kbGVyOiBoZWxsb3NGdW5jdGlvbiB9XG4gKiB9KTtcbiAqIC8vIGFwaSBoYXMgdHlwZSBBcGlDb250YWluZXI8eyBoZWxsbzogUm91dGVFbnRyeTxbc3RyaW5nXSwgc3RyaW5nPiwgaGVsbG9zOiBSb3V0ZUVudHJ5PFtdLCBHcmVldGluZ1tdPiB9PlxuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBBcGlDb250YWluZXI8VFJvdXRlcyBleHRlbmRzIEFwaVJvdXRlcyA9IEFwaVJvdXRlcz4gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgcmVhZG9ubHkgcm91dGVzOiBUUm91dGVzO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHJvdXRlczogVFJvdXRlcyA9IHt9IGFzIFRSb3V0ZXMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMucm91dGVzID0gcm91dGVzO1xuICB9XG5cbiAgYWRkUm91dGU8VEFyZ3MgZXh0ZW5kcyBhbnlbXSwgVFJldHVybj4oXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBoYW5kbGVyOiBGdW5jdGlvbjxUQXJncywgVFJldHVybj5cbiAgKTogdm9pZCB7XG4gICAgKHRoaXMucm91dGVzIGFzIEFwaVJvdXRlcylbbmFtZV0gPSB7IHBhdGgsIGhhbmRsZXIgfTtcbiAgfVxuXG4gIGdldFJvdXRlPEsgZXh0ZW5kcyBrZXlvZiBUUm91dGVzICYgc3RyaW5nPihuYW1lOiBLKTogVFJvdXRlc1tLXSB7XG4gICAgY29uc3QgZW50cnkgPSB0aGlzLnJvdXRlc1tuYW1lXTtcbiAgICBpZiAoIWVudHJ5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFJvdXRlICcke25hbWV9JyBub3QgZm91bmQgaW4gY29udGFpbmVyICcke3RoaXMubm9kZS5pZH0nYCk7XG4gICAgfVxuICAgIHJldHVybiBlbnRyeTtcbiAgfVxuXG4gIGxpc3RSb3V0ZXMoKTogKGtleW9mIFRSb3V0ZXMgJiBzdHJpbmcpW10ge1xuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnJvdXRlcykgYXMgKGtleW9mIFRSb3V0ZXMgJiBzdHJpbmcpW107XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIGxpc3Qgb2YgVEJERnVuY3Rpb25zIHRoYXQgaGF2ZSBub3QgYmVlbiBvdmVybG9hZGVkLlxuICAgKiBVc2UgdGhpcyB0byB2YWxpZGF0ZSB0aGF0IGFsbCByZXF1aXJlZCBpbXBsZW1lbnRhdGlvbnMgYXJlIHByb3ZpZGVkLlxuICAgKi9cbiAgdmFsaWRhdGVPdmVybG9hZHMoKTogRnVuY3Rpb25bXSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5yb3V0ZXMpXG4gICAgICAubWFwKGVudHJ5ID0+IGVudHJ5LmhhbmRsZXIpXG4gICAgICAuZmlsdGVyKGZuID0+IGZuIGluc3RhbmNlb2YgVEJERnVuY3Rpb24gJiYgIWZuLmhhc092ZXJsb2FkKCkpO1xuICB9XG59XG4iXX0=
package/dist/binding.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Construct } from 'constructs';
2
- import { ApiContainer } from './api-container';
2
+ import { ApiContainer, ApiRoutes } from './api-container';
3
3
  import { FunctionHandler } from './function';
4
4
  /**
5
5
  * Service discovery configuration for runtime
@@ -29,7 +29,7 @@ export declare class ArchitectureBinding {
29
29
  * Optionally override function implementations with the overloads option.
30
30
  * Overload keys must be route names registered via addRoute.
31
31
  */
32
- bind(component: ApiContainer, options: BindOptions): void;
32
+ bind<TRoutes extends ApiRoutes>(component: ApiContainer<TRoutes>, options: BindOptions): void;
33
33
  getEndpoint(component: Construct): ServiceEndpoint | undefined;
34
34
  getAllBindings(): Map<Construct, ServiceEndpoint>;
35
35
  setLocal(component: Construct): void;
@@ -1 +1 @@
1
- {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAY,eAAe,EAAE,MAAM,YAAY,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC7C;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAA8C;IAC9D,OAAO,CAAC,eAAe,CAA6B;IAEpD;;;;OAIG;IACH,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAezD,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS;IAI9D,cAAc,IAAI,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC;IAIjD,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAIpC,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;CAGvC;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC"}
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../src/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAY,eAAe,EAAE,MAAM,YAAY,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC7C;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAA8C;IAC9D,OAAO,CAAC,eAAe,CAA6B;IAEpD;;;;OAIG;IACH,IAAI,CAAC,OAAO,SAAS,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAe7F,WAAW,CAAC,SAAS,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS;IAI9D,cAAc,IAAI,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC;IAIjD,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAIpC,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;CAGvC;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,qBAA4B,CAAC"}
package/dist/binding.js CHANGED
@@ -47,4 +47,4 @@ exports.ArchitectureBinding = ArchitectureBinding;
47
47
  * Global binding registry
48
48
  */
49
49
  exports.architectureBinding = new ArchitectureBinding();
50
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmluZGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9iaW5kaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHlDQUF1RDtBQW9CdkQ7OztHQUdHO0FBQ0gsTUFBYSxtQkFBbUI7SUFBaEM7UUFDVSxhQUFRLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7UUFDdEQsb0JBQWUsR0FBbUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQXFDdEQsQ0FBQztJQW5DQzs7OztPQUlHO0lBQ0gsSUFBSSxDQUFDLFNBQXVCLEVBQUUsT0FBb0I7UUFDaEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBRTNELE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO1lBQ2xFLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxJQUFJLDZCQUE2QixTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDbkYsQ0FBQztZQUNELElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLFlBQVksbUJBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQ3pDLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxJQUFJLDZCQUE2QixDQUFDLENBQUM7WUFDL0QsQ0FBQztZQUNELEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2xDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELFdBQVcsQ0FBQyxTQUFvQjtRQUM5QixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRCxjQUFjO1FBQ1osT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxRQUFRLENBQUMsU0FBb0I7UUFDM0IsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELE9BQU8sQ0FBQyxTQUFvQjtRQUMxQixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzdDLENBQUM7Q0FDRjtBQXZDRCxrREF1Q0M7QUFFRDs7R0FFRztBQUNVLFFBQUEsbUJBQW1CLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBBcGlDb250YWluZXIgfSBmcm9tICcuL2FwaS1jb250YWluZXInO1xuaW1wb3J0IHsgRnVuY3Rpb24sIEZ1bmN0aW9uSGFuZGxlciB9IGZyb20gJy4vZnVuY3Rpb24nO1xuXG4vKipcbiAqIFNlcnZpY2UgZGlzY292ZXJ5IGNvbmZpZ3VyYXRpb24gZm9yIHJ1bnRpbWVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlRW5kcG9pbnQge1xuICBiYXNlVXJsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQmluZGluZyBvcHRpb25zIGZvciBhbiBBcGlDb250YWluZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCaW5kT3B0aW9ucyBleHRlbmRzIFNlcnZpY2VFbmRwb2ludCB7XG4gIC8qKlxuICAgKiBPdmVycmlkZSBmdW5jdGlvbiBpbXBsZW1lbnRhdGlvbnMuXG4gICAqIEtleXMgYXJlIGZ1bmN0aW9uIHByb3BlcnR5IG5hbWVzIG9uIHRoZSBjb250YWluZXIuXG4gICAqL1xuICBvdmVybG9hZHM/OiBSZWNvcmQ8c3RyaW5nLCBGdW5jdGlvbkhhbmRsZXI+O1xufVxuXG4vKipcbiAqIEJpbmRpbmcgYmV0d2VlbiBhcmNoaXRlY3R1cmFsIGNvbXBvbmVudHMgYW5kIHRoZWlyIHJ1bnRpbWUgZW5kcG9pbnRzLlxuICogU3VwcG9ydHMgZnVuY3Rpb24gb3ZlcmxvYWRpbmcgZm9yIHJlcGxhY2luZyBpbXBsZW1lbnRhdGlvbnMgYXQgcnVudGltZS5cbiAqL1xuZXhwb3J0IGNsYXNzIEFyY2hpdGVjdHVyZUJpbmRpbmcge1xuICBwcml2YXRlIGJpbmRpbmdzOiBNYXA8Q29uc3RydWN0LCBTZXJ2aWNlRW5kcG9pbnQ+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIGxvY2FsQ29tcG9uZW50czogU2V0PENvbnN0cnVjdD4gPSBuZXcgU2V0KCk7XG5cbiAgLyoqXG4gICAqIEJpbmQgYW4gYXJjaGl0ZWN0dXJhbCBjb21wb25lbnQgdG8gYSBzZXJ2aWNlIGVuZHBvaW50LlxuICAgKiBPcHRpb25hbGx5IG92ZXJyaWRlIGZ1bmN0aW9uIGltcGxlbWVudGF0aW9ucyB3aXRoIHRoZSBvdmVybG9hZHMgb3B0aW9uLlxuICAgKiBPdmVybG9hZCBrZXlzIG11c3QgYmUgcm91dGUgbmFtZXMgcmVnaXN0ZXJlZCB2aWEgYWRkUm91dGUuXG4gICAqL1xuICBiaW5kKGNvbXBvbmVudDogQXBpQ29udGFpbmVyLCBvcHRpb25zOiBCaW5kT3B0aW9ucyk6IHZvaWQge1xuICAgIHRoaXMuYmluZGluZ3Muc2V0KGNvbXBvbmVudCwgeyBiYXNlVXJsOiBvcHRpb25zLmJhc2VVcmwgfSk7XG5cbiAgICBPYmplY3QuZW50cmllcyhvcHRpb25zLm92ZXJsb2FkcyA/PyB7fSkuZm9yRWFjaCgoW25hbWUsIGhhbmRsZXJdKSA9PiB7XG4gICAgICBjb25zdCByb3V0ZSA9IGNvbXBvbmVudC5nZXRSb3V0ZShuYW1lKTtcbiAgICAgIGlmICghcm91dGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSb3V0ZSAnJHtuYW1lfScgbm90IGZvdW5kIGluIGNvbXBvbmVudCAnJHtjb21wb25lbnQubm9kZS5pZH0nYCk7XG4gICAgICB9XG4gICAgICBpZiAoIShyb3V0ZS5oYW5kbGVyIGluc3RhbmNlb2YgRnVuY3Rpb24pKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgUm91dGUgJyR7bmFtZX0nIGhhbmRsZXIgaXMgbm90IGEgRnVuY3Rpb25gKTtcbiAgICAgIH1cbiAgICAgIHJvdXRlLmhhbmRsZXIub3ZlcmxvYWQoaGFuZGxlcik7XG4gICAgfSk7XG4gIH1cblxuICBnZXRFbmRwb2ludChjb21wb25lbnQ6IENvbnN0cnVjdCk6IFNlcnZpY2VFbmRwb2ludCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuYmluZGluZ3MuZ2V0KGNvbXBvbmVudCk7XG4gIH1cblxuICBnZXRBbGxCaW5kaW5ncygpOiBNYXA8Q29uc3RydWN0LCBTZXJ2aWNlRW5kcG9pbnQ+IHtcbiAgICByZXR1cm4gdGhpcy5iaW5kaW5ncztcbiAgfVxuXG4gIHNldExvY2FsKGNvbXBvbmVudDogQ29uc3RydWN0KTogdm9pZCB7XG4gICAgdGhpcy5sb2NhbENvbXBvbmVudHMuYWRkKGNvbXBvbmVudCk7XG4gIH1cblxuICBpc0xvY2FsKGNvbXBvbmVudDogQ29uc3RydWN0KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubG9jYWxDb21wb25lbnRzLmhhcyhjb21wb25lbnQpO1xuICB9XG59XG5cbi8qKlxuICogR2xvYmFsIGJpbmRpbmcgcmVnaXN0cnlcbiAqL1xuZXhwb3J0IGNvbnN0IGFyY2hpdGVjdHVyZUJpbmRpbmcgPSBuZXcgQXJjaGl0ZWN0dXJlQmluZGluZygpO1xuIl19
50
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmluZGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9iaW5kaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHlDQUF1RDtBQW9CdkQ7OztHQUdHO0FBQ0gsTUFBYSxtQkFBbUI7SUFBaEM7UUFDVSxhQUFRLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7UUFDdEQsb0JBQWUsR0FBbUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQXFDdEQsQ0FBQztJQW5DQzs7OztPQUlHO0lBQ0gsSUFBSSxDQUE0QixTQUFnQyxFQUFFLE9BQW9CO1FBQ3BGLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUUzRCxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRTtZQUNsRSxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDWCxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsSUFBSSw2QkFBNkIsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQ25GLENBQUM7WUFDRCxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxZQUFZLG1CQUFRLENBQUMsRUFBRSxDQUFDO2dCQUN6QyxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsSUFBSSw2QkFBNkIsQ0FBQyxDQUFDO1lBQy9ELENBQUM7WUFDRCxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxXQUFXLENBQUMsU0FBb0I7UUFDOUIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsY0FBYztRQUNaLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2QixDQUFDO0lBRUQsUUFBUSxDQUFDLFNBQW9CO1FBQzNCLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFRCxPQUFPLENBQUMsU0FBb0I7UUFDMUIsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM3QyxDQUFDO0NBQ0Y7QUF2Q0Qsa0RBdUNDO0FBRUQ7O0dBRUc7QUFDVSxRQUFBLG1CQUFtQixHQUFHLElBQUksbUJBQW1CLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQXBpQ29udGFpbmVyLCBBcGlSb3V0ZXMgfSBmcm9tICcuL2FwaS1jb250YWluZXInO1xuaW1wb3J0IHsgRnVuY3Rpb24sIEZ1bmN0aW9uSGFuZGxlciB9IGZyb20gJy4vZnVuY3Rpb24nO1xuXG4vKipcbiAqIFNlcnZpY2UgZGlzY292ZXJ5IGNvbmZpZ3VyYXRpb24gZm9yIHJ1bnRpbWVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlRW5kcG9pbnQge1xuICBiYXNlVXJsOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQmluZGluZyBvcHRpb25zIGZvciBhbiBBcGlDb250YWluZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCaW5kT3B0aW9ucyBleHRlbmRzIFNlcnZpY2VFbmRwb2ludCB7XG4gIC8qKlxuICAgKiBPdmVycmlkZSBmdW5jdGlvbiBpbXBsZW1lbnRhdGlvbnMuXG4gICAqIEtleXMgYXJlIGZ1bmN0aW9uIHByb3BlcnR5IG5hbWVzIG9uIHRoZSBjb250YWluZXIuXG4gICAqL1xuICBvdmVybG9hZHM/OiBSZWNvcmQ8c3RyaW5nLCBGdW5jdGlvbkhhbmRsZXI+O1xufVxuXG4vKipcbiAqIEJpbmRpbmcgYmV0d2VlbiBhcmNoaXRlY3R1cmFsIGNvbXBvbmVudHMgYW5kIHRoZWlyIHJ1bnRpbWUgZW5kcG9pbnRzLlxuICogU3VwcG9ydHMgZnVuY3Rpb24gb3ZlcmxvYWRpbmcgZm9yIHJlcGxhY2luZyBpbXBsZW1lbnRhdGlvbnMgYXQgcnVudGltZS5cbiAqL1xuZXhwb3J0IGNsYXNzIEFyY2hpdGVjdHVyZUJpbmRpbmcge1xuICBwcml2YXRlIGJpbmRpbmdzOiBNYXA8Q29uc3RydWN0LCBTZXJ2aWNlRW5kcG9pbnQ+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIGxvY2FsQ29tcG9uZW50czogU2V0PENvbnN0cnVjdD4gPSBuZXcgU2V0KCk7XG5cbiAgLyoqXG4gICAqIEJpbmQgYW4gYXJjaGl0ZWN0dXJhbCBjb21wb25lbnQgdG8gYSBzZXJ2aWNlIGVuZHBvaW50LlxuICAgKiBPcHRpb25hbGx5IG92ZXJyaWRlIGZ1bmN0aW9uIGltcGxlbWVudGF0aW9ucyB3aXRoIHRoZSBvdmVybG9hZHMgb3B0aW9uLlxuICAgKiBPdmVybG9hZCBrZXlzIG11c3QgYmUgcm91dGUgbmFtZXMgcmVnaXN0ZXJlZCB2aWEgYWRkUm91dGUuXG4gICAqL1xuICBiaW5kPFRSb3V0ZXMgZXh0ZW5kcyBBcGlSb3V0ZXM+KGNvbXBvbmVudDogQXBpQ29udGFpbmVyPFRSb3V0ZXM+LCBvcHRpb25zOiBCaW5kT3B0aW9ucyk6IHZvaWQge1xuICAgIHRoaXMuYmluZGluZ3Muc2V0KGNvbXBvbmVudCwgeyBiYXNlVXJsOiBvcHRpb25zLmJhc2VVcmwgfSk7XG5cbiAgICBPYmplY3QuZW50cmllcyhvcHRpb25zLm92ZXJsb2FkcyA/PyB7fSkuZm9yRWFjaCgoW25hbWUsIGhhbmRsZXJdKSA9PiB7XG4gICAgICBjb25zdCByb3V0ZSA9IGNvbXBvbmVudC5nZXRSb3V0ZShuYW1lKTtcbiAgICAgIGlmICghcm91dGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSb3V0ZSAnJHtuYW1lfScgbm90IGZvdW5kIGluIGNvbXBvbmVudCAnJHtjb21wb25lbnQubm9kZS5pZH0nYCk7XG4gICAgICB9XG4gICAgICBpZiAoIShyb3V0ZS5oYW5kbGVyIGluc3RhbmNlb2YgRnVuY3Rpb24pKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgUm91dGUgJyR7bmFtZX0nIGhhbmRsZXIgaXMgbm90IGEgRnVuY3Rpb25gKTtcbiAgICAgIH1cbiAgICAgIHJvdXRlLmhhbmRsZXIub3ZlcmxvYWQoaGFuZGxlcik7XG4gICAgfSk7XG4gIH1cblxuICBnZXRFbmRwb2ludChjb21wb25lbnQ6IENvbnN0cnVjdCk6IFNlcnZpY2VFbmRwb2ludCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuYmluZGluZ3MuZ2V0KGNvbXBvbmVudCk7XG4gIH1cblxuICBnZXRBbGxCaW5kaW5ncygpOiBNYXA8Q29uc3RydWN0LCBTZXJ2aWNlRW5kcG9pbnQ+IHtcbiAgICByZXR1cm4gdGhpcy5iaW5kaW5ncztcbiAgfVxuXG4gIHNldExvY2FsKGNvbXBvbmVudDogQ29uc3RydWN0KTogdm9pZCB7XG4gICAgdGhpcy5sb2NhbENvbXBvbmVudHMuYWRkKGNvbXBvbmVudCk7XG4gIH1cblxuICBpc0xvY2FsKGNvbXBvbmVudDogQ29uc3RydWN0KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubG9jYWxDb21wb25lbnRzLmhhcyhjb21wb25lbnQpO1xuICB9XG59XG5cbi8qKlxuICogR2xvYmFsIGJpbmRpbmcgcmVnaXN0cnlcbiAqL1xuZXhwb3J0IGNvbnN0IGFyY2hpdGVjdHVyZUJpbmRpbmcgPSBuZXcgQXJjaGl0ZWN0dXJlQmluZGluZygpO1xuIl19
@@ -1,11 +1,32 @@
1
- import { ApiContainer } from './api-container';
2
- import { FunctionHandler } from './function';
1
+ import { ApiContainer, ApiRoutes, RouteHandlers } from './api-container';
3
2
  import { ServiceEndpoint } from './binding';
3
+ export type Fetcher = () => {
4
+ fetch: typeof fetch;
5
+ };
4
6
  /**
5
7
  * Create an HTTP handler for a route by name.
6
8
  * Looks up the route path from the container's registry.
7
9
  */
8
- export declare const httpHandler: (endpoint: ServiceEndpoint, container: ApiContainer, routeName: string, fetcher?: () => {
9
- fetch: typeof fetch;
10
- }) => FunctionHandler;
10
+ export declare const httpHandler: <TRoutes extends ApiRoutes, K extends keyof TRoutes & string>(endpoint: ServiceEndpoint, container: ApiContainer<TRoutes>, routeName: K, fetcher?: Fetcher) => RouteHandlers<TRoutes>[K];
11
+ /**
12
+ * Create HTTP bindings for multiple routes as a callable client.
13
+ * Returns a strongly-typed object where each route name maps to an async function
14
+ * with the same signature as the original handler.
15
+ *
16
+ * @typeParam TRoutes - The routes type from the ApiContainer
17
+ * @typeParam K - The subset of route names to include in the client
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const api = new ApiContainer(arch, 'api', {
22
+ * hello: { path: 'GET /v1/api/hello/{name}', handler: helloFunction },
23
+ * hellos: { path: 'GET /v1/api/hellos', handler: hellosFunction }
24
+ * });
25
+ *
26
+ * const client = createHttpBindings(endpoint, api, ['hello', 'hellos']);
27
+ * await client.hello('John'); // (name: string) => Promise<string>
28
+ * await client.hellos(); // () => Promise<Greeting[]>
29
+ * ```
30
+ */
31
+ export declare const createHttpBindings: <TRoutes extends ApiRoutes, K extends keyof TRoutes & string>(endpoint: ServiceEndpoint, container: ApiContainer<TRoutes>, routeNames: readonly K[], fetcher?: Fetcher) => Pick<RouteHandlers<TRoutes>, K>;
11
32
  //# sourceMappingURL=http-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http-handler.d.ts","sourceRoot":"","sources":["../src/http-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,WAAW,GACtB,UAAU,eAAe,EACzB,WAAW,YAAY,EACvB,WAAW,MAAM,EACjB,UAAS,MAAM;IAAE,KAAK,EAAE,OAAO,KAAK,CAAA;CAAoB,KACvD,eAgCF,CAAC"}
1
+ {"version":3,"file":"http-handler.d.ts","sourceRoot":"","sources":["../src/http-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,MAAM,OAAO,GAAG,MAAM;IAAE,KAAK,EAAE,OAAO,KAAK,CAAA;CAAE,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,SAAS,SAAS,EACzB,CAAC,SAAS,MAAM,OAAO,GAAG,MAAM,EAEhC,UAAU,eAAe,EACzB,WAAW,YAAY,CAAC,OAAO,CAAC,EAChC,WAAW,CAAC,EACZ,UAAS,OAAyB,KACjC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CA+B1B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,SAAS,SAAS,EACzB,CAAC,SAAS,MAAM,OAAO,GAAG,MAAM,EAEhC,UAAU,eAAe,EACzB,WAAW,YAAY,CAAC,OAAO,CAAC,EAChC,YAAY,SAAS,CAAC,EAAE,EACxB,UAAS,OAAyB,KACjC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAQhC,CAAC"}
@@ -1,18 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.httpHandler = void 0;
3
+ exports.createHttpBindings = exports.httpHandler = void 0;
4
4
  /**
5
5
  * Create an HTTP handler for a route by name.
6
6
  * Looks up the route path from the container's registry.
7
7
  */
8
8
  const httpHandler = (endpoint, container, routeName, fetcher = () => ({ fetch })) => {
9
9
  const route = container.getRoute(routeName);
10
- if (!route) {
11
- throw new Error(`Route '${routeName}' not found in container '${container.node.id}'`);
12
- }
13
10
  const [method, path] = route.path.split(' ');
14
11
  const pathParams = path.match(/\{(\w+)\}/g) || [];
15
- return async (...args) => {
12
+ const handler = async (...args) => {
16
13
  const url = pathParams.reduce((u, param, i) => args[i] !== undefined ? u.replace(param, encodeURIComponent(String(args[i]))) : u, `${endpoint.baseUrl}${path}`);
17
14
  const options = {
18
15
  method: method || 'GET',
@@ -28,6 +25,34 @@ const httpHandler = (endpoint, container, routeName, fetcher = () => ({ fetch })
28
25
  }
29
26
  return response.json();
30
27
  };
28
+ return handler;
31
29
  };
32
30
  exports.httpHandler = httpHandler;
33
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2h0dHAtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFJQTs7O0dBR0c7QUFDSSxNQUFNLFdBQVcsR0FBRyxDQUN6QixRQUF5QixFQUN6QixTQUF1QixFQUN2QixTQUFpQixFQUNqQixVQUF5QyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUMsS0FBSyxFQUFDLENBQUMsRUFDdkMsRUFBRTtJQUNuQixNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzVDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxTQUFTLDZCQUE2QixTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDeEYsQ0FBQztJQUVELE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0MsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFbEQsT0FBTyxLQUFLLEVBQUUsR0FBRyxJQUFXLEVBQUUsRUFBRTtRQUM5QixNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUMzQixDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQ2xHLEdBQUcsUUFBUSxDQUFDLE9BQU8sR0FBRyxJQUFJLEVBQUUsQ0FDN0IsQ0FBQztRQUVGLE1BQU0sT0FBTyxHQUFnQjtZQUMzQixNQUFNLEVBQUUsTUFBTSxJQUFJLEtBQUs7WUFDdkIsT0FBTyxFQUFFLEVBQUUsY0FBYyxFQUFFLGtCQUFrQixFQUFFO1lBQy9DLEdBQUcsQ0FBQyxDQUFDLE1BQU0sS0FBSyxNQUFNLElBQUksTUFBTSxLQUFLLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsVUFBVSxDQUFDLE1BQU07Z0JBQzVFLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRTtnQkFDbkQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztTQUNSLENBQUM7UUFFRixPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixFQUFFLEVBQUMsR0FBRyxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUM7UUFDeEQsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXJELElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsR0FBRyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLFlBQVksSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDL0csQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3pCLENBQUMsQ0FBQztBQUNKLENBQUMsQ0FBQztBQXJDVyxRQUFBLFdBQVcsZUFxQ3RCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQXBpQ29udGFpbmVyIH0gZnJvbSAnLi9hcGktY29udGFpbmVyJztcbmltcG9ydCB7IEZ1bmN0aW9uSGFuZGxlciB9IGZyb20gJy4vZnVuY3Rpb24nO1xuaW1wb3J0IHsgU2VydmljZUVuZHBvaW50IH0gZnJvbSAnLi9iaW5kaW5nJztcblxuLyoqXG4gKiBDcmVhdGUgYW4gSFRUUCBoYW5kbGVyIGZvciBhIHJvdXRlIGJ5IG5hbWUuXG4gKiBMb29rcyB1cCB0aGUgcm91dGUgcGF0aCBmcm9tIHRoZSBjb250YWluZXIncyByZWdpc3RyeS5cbiAqL1xuZXhwb3J0IGNvbnN0IGh0dHBIYW5kbGVyID0gKFxuICBlbmRwb2ludDogU2VydmljZUVuZHBvaW50LFxuICBjb250YWluZXI6IEFwaUNvbnRhaW5lcixcbiAgcm91dGVOYW1lOiBzdHJpbmcsXG4gIGZldGNoZXI6ICgpID0+IHsgZmV0Y2g6IHR5cGVvZiBmZXRjaCB9ID0gKCkgPT4gKHtmZXRjaH0pXG4pOiBGdW5jdGlvbkhhbmRsZXIgPT4ge1xuICBjb25zdCByb3V0ZSA9IGNvbnRhaW5lci5nZXRSb3V0ZShyb3V0ZU5hbWUpO1xuICBpZiAoIXJvdXRlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBSb3V0ZSAnJHtyb3V0ZU5hbWV9JyBub3QgZm91bmQgaW4gY29udGFpbmVyICcke2NvbnRhaW5lci5ub2RlLmlkfSdgKTtcbiAgfVxuXG4gIGNvbnN0IFttZXRob2QsIHBhdGhdID0gcm91dGUucGF0aC5zcGxpdCgnICcpO1xuICBjb25zdCBwYXRoUGFyYW1zID0gcGF0aC5tYXRjaCgvXFx7KFxcdyspXFx9L2cpIHx8IFtdO1xuXG4gIHJldHVybiBhc3luYyAoLi4uYXJnczogYW55W10pID0+IHtcbiAgICBjb25zdCB1cmwgPSBwYXRoUGFyYW1zLnJlZHVjZShcbiAgICAgICh1LCBwYXJhbSwgaSkgPT4gYXJnc1tpXSAhPT0gdW5kZWZpbmVkID8gdS5yZXBsYWNlKHBhcmFtLCBlbmNvZGVVUklDb21wb25lbnQoU3RyaW5nKGFyZ3NbaV0pKSkgOiB1LFxuICAgICAgYCR7ZW5kcG9pbnQuYmFzZVVybH0ke3BhdGh9YFxuICAgICk7XG5cbiAgICBjb25zdCBvcHRpb25zOiBSZXF1ZXN0SW5pdCA9IHtcbiAgICAgIG1ldGhvZDogbWV0aG9kIHx8ICdHRVQnLFxuICAgICAgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nIH0sXG4gICAgICAuLi4oKG1ldGhvZCA9PT0gJ1BPU1QnIHx8IG1ldGhvZCA9PT0gJ1BVVCcpICYmIGFyZ3MubGVuZ3RoID4gcGF0aFBhcmFtcy5sZW5ndGhcbiAgICAgICAgPyB7IGJvZHk6IEpTT04uc3RyaW5naWZ5KGFyZ3NbcGF0aFBhcmFtcy5sZW5ndGhdKSB9XG4gICAgICAgIDoge30pXG4gICAgfTtcblxuICAgIGNvbnNvbGUubG9nKCdIVFRQIGhhbmRsZXIuIFdpbGwgZmV0Y2gnLCB7dXJsLCBvcHRpb25zfSk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaGVyKCkuZmV0Y2godXJsLCBvcHRpb25zKTtcblxuICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUmVtb3RlIGNhbGwgdG8gJHt1cmx9IHdpdGggJHtKU09OLnN0cmluZ2lmeShvcHRpb25zKX0gZmFpbGVkOiAke0pTT04uc3RyaW5naWZ5KHJlc3BvbnNlKX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpO1xuICB9O1xufTsiXX0=
31
+ /**
32
+ * Create HTTP bindings for multiple routes as a callable client.
33
+ * Returns a strongly-typed object where each route name maps to an async function
34
+ * with the same signature as the original handler.
35
+ *
36
+ * @typeParam TRoutes - The routes type from the ApiContainer
37
+ * @typeParam K - The subset of route names to include in the client
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const api = new ApiContainer(arch, 'api', {
42
+ * hello: { path: 'GET /v1/api/hello/{name}', handler: helloFunction },
43
+ * hellos: { path: 'GET /v1/api/hellos', handler: hellosFunction }
44
+ * });
45
+ *
46
+ * const client = createHttpBindings(endpoint, api, ['hello', 'hellos']);
47
+ * await client.hello('John'); // (name: string) => Promise<string>
48
+ * await client.hellos(); // () => Promise<Greeting[]>
49
+ * ```
50
+ */
51
+ const createHttpBindings = (endpoint, container, routeNames, fetcher = () => ({ fetch })) => {
52
+ return routeNames.reduce((acc, name) => {
53
+ acc[name] = (0, exports.httpHandler)(endpoint, container, name, fetcher);
54
+ return acc;
55
+ }, {});
56
+ };
57
+ exports.createHttpBindings = createHttpBindings;
58
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC1oYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2h0dHAtaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFNQTs7O0dBR0c7QUFDSSxNQUFNLFdBQVcsR0FBRyxDQUl6QixRQUF5QixFQUN6QixTQUFnQyxFQUNoQyxTQUFZLEVBQ1osVUFBbUIsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFDLEtBQUssRUFBQyxDQUFDLEVBQ1AsRUFBRTtJQUM3QixNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRTVDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0MsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFbEQsTUFBTSxPQUFPLEdBQUcsS0FBSyxFQUFFLEdBQUcsSUFBVyxFQUFFLEVBQUU7UUFDdkMsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FDM0IsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsa0JBQWtCLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUNsRyxHQUFHLFFBQVEsQ0FBQyxPQUFPLEdBQUcsSUFBSSxFQUFFLENBQzdCLENBQUM7UUFFRixNQUFNLE9BQU8sR0FBZ0I7WUFDM0IsTUFBTSxFQUFFLE1BQU0sSUFBSSxLQUFLO1lBQ3ZCLE9BQU8sRUFBRSxFQUFFLGNBQWMsRUFBRSxrQkFBa0IsRUFBRTtZQUMvQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEtBQUssTUFBTSxJQUFJLE1BQU0sS0FBSyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLFVBQVUsQ0FBQyxNQUFNO2dCQUM1RSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUU7Z0JBQ25ELENBQUMsQ0FBQyxFQUFFLENBQUM7U0FDUixDQUFDO1FBRUYsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsRUFBRSxFQUFDLEdBQUcsRUFBRSxPQUFPLEVBQUMsQ0FBQyxDQUFDO1FBQ3hELE1BQU0sUUFBUSxHQUFHLE1BQU0sT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUVyRCxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ2pCLE1BQU0sSUFBSSxLQUFLLENBQUMsa0JBQWtCLEdBQUcsU0FBUyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxZQUFZLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQy9HLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN6QixDQUFDLENBQUM7SUFFRixPQUFPLE9BQW9DLENBQUM7QUFDOUMsQ0FBQyxDQUFDO0FBdkNXLFFBQUEsV0FBVyxlQXVDdEI7QUFFRjs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNJLE1BQU0sa0JBQWtCLEdBQUcsQ0FJaEMsUUFBeUIsRUFDekIsU0FBZ0MsRUFDaEMsVUFBd0IsRUFDeEIsVUFBbUIsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFDLEtBQUssRUFBQyxDQUFDLEVBQ0QsRUFBRTtJQUNuQyxPQUFPLFVBQVUsQ0FBQyxNQUFNLENBQ3RCLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQ1osR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUEsbUJBQVcsRUFBQyxRQUFRLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM1RCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUMsRUFDRCxFQUFxQyxDQUN0QyxDQUFDO0FBQ0osQ0FBQyxDQUFDO0FBaEJXLFFBQUEsa0JBQWtCLHNCQWdCN0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBcGlDb250YWluZXIsIEFwaVJvdXRlcywgUm91dGVIYW5kbGVycyB9IGZyb20gJy4vYXBpLWNvbnRhaW5lcic7XG5pbXBvcnQgeyBGdW5jdGlvbkhhbmRsZXIgfSBmcm9tICcuL2Z1bmN0aW9uJztcbmltcG9ydCB7IFNlcnZpY2VFbmRwb2ludCB9IGZyb20gJy4vYmluZGluZyc7XG5cbmV4cG9ydCB0eXBlIEZldGNoZXIgPSAoKSA9PiB7IGZldGNoOiB0eXBlb2YgZmV0Y2ggfTtcblxuLyoqXG4gKiBDcmVhdGUgYW4gSFRUUCBoYW5kbGVyIGZvciBhIHJvdXRlIGJ5IG5hbWUuXG4gKiBMb29rcyB1cCB0aGUgcm91dGUgcGF0aCBmcm9tIHRoZSBjb250YWluZXIncyByZWdpc3RyeS5cbiAqL1xuZXhwb3J0IGNvbnN0IGh0dHBIYW5kbGVyID0gPFxuICBUUm91dGVzIGV4dGVuZHMgQXBpUm91dGVzLFxuICBLIGV4dGVuZHMga2V5b2YgVFJvdXRlcyAmIHN0cmluZ1xuPihcbiAgZW5kcG9pbnQ6IFNlcnZpY2VFbmRwb2ludCxcbiAgY29udGFpbmVyOiBBcGlDb250YWluZXI8VFJvdXRlcz4sXG4gIHJvdXRlTmFtZTogSyxcbiAgZmV0Y2hlcjogRmV0Y2hlciA9ICgpID0+ICh7ZmV0Y2h9KVxuKTogUm91dGVIYW5kbGVyczxUUm91dGVzPltLXSA9PiB7XG4gIGNvbnN0IHJvdXRlID0gY29udGFpbmVyLmdldFJvdXRlKHJvdXRlTmFtZSk7XG5cbiAgY29uc3QgW21ldGhvZCwgcGF0aF0gPSByb3V0ZS5wYXRoLnNwbGl0KCcgJyk7XG4gIGNvbnN0IHBhdGhQYXJhbXMgPSBwYXRoLm1hdGNoKC9cXHsoXFx3KylcXH0vZykgfHwgW107XG5cbiAgY29uc3QgaGFuZGxlciA9IGFzeW5jICguLi5hcmdzOiBhbnlbXSkgPT4ge1xuICAgIGNvbnN0IHVybCA9IHBhdGhQYXJhbXMucmVkdWNlKFxuICAgICAgKHUsIHBhcmFtLCBpKSA9PiBhcmdzW2ldICE9PSB1bmRlZmluZWQgPyB1LnJlcGxhY2UocGFyYW0sIGVuY29kZVVSSUNvbXBvbmVudChTdHJpbmcoYXJnc1tpXSkpKSA6IHUsXG4gICAgICBgJHtlbmRwb2ludC5iYXNlVXJsfSR7cGF0aH1gXG4gICAgKTtcblxuICAgIGNvbnN0IG9wdGlvbnM6IFJlcXVlc3RJbml0ID0ge1xuICAgICAgbWV0aG9kOiBtZXRob2QgfHwgJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicgfSxcbiAgICAgIC4uLigobWV0aG9kID09PSAnUE9TVCcgfHwgbWV0aG9kID09PSAnUFVUJykgJiYgYXJncy5sZW5ndGggPiBwYXRoUGFyYW1zLmxlbmd0aFxuICAgICAgICA/IHsgYm9keTogSlNPTi5zdHJpbmdpZnkoYXJnc1twYXRoUGFyYW1zLmxlbmd0aF0pIH1cbiAgICAgICAgOiB7fSlcbiAgICB9O1xuXG4gICAgY29uc29sZS5sb2coJ0hUVFAgaGFuZGxlci4gV2lsbCBmZXRjaCcsIHt1cmwsIG9wdGlvbnN9KTtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoZXIoKS5mZXRjaCh1cmwsIG9wdGlvbnMpO1xuXG4gICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZW1vdGUgY2FsbCB0byAke3VybH0gd2l0aCAke0pTT04uc3RyaW5naWZ5KG9wdGlvbnMpfSBmYWlsZWQ6ICR7SlNPTi5zdHJpbmdpZnkocmVzcG9uc2UpfWApO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS5qc29uKCk7XG4gIH07XG5cbiAgcmV0dXJuIGhhbmRsZXIgYXMgUm91dGVIYW5kbGVyczxUUm91dGVzPltLXTtcbn07XG5cbi8qKlxuICogQ3JlYXRlIEhUVFAgYmluZGluZ3MgZm9yIG11bHRpcGxlIHJvdXRlcyBhcyBhIGNhbGxhYmxlIGNsaWVudC5cbiAqIFJldHVybnMgYSBzdHJvbmdseS10eXBlZCBvYmplY3Qgd2hlcmUgZWFjaCByb3V0ZSBuYW1lIG1hcHMgdG8gYW4gYXN5bmMgZnVuY3Rpb25cbiAqIHdpdGggdGhlIHNhbWUgc2lnbmF0dXJlIGFzIHRoZSBvcmlnaW5hbCBoYW5kbGVyLlxuICpcbiAqIEB0eXBlUGFyYW0gVFJvdXRlcyAtIFRoZSByb3V0ZXMgdHlwZSBmcm9tIHRoZSBBcGlDb250YWluZXJcbiAqIEB0eXBlUGFyYW0gSyAtIFRoZSBzdWJzZXQgb2Ygcm91dGUgbmFtZXMgdG8gaW5jbHVkZSBpbiB0aGUgY2xpZW50XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGFwaSA9IG5ldyBBcGlDb250YWluZXIoYXJjaCwgJ2FwaScsIHtcbiAqICAgaGVsbG86IHsgcGF0aDogJ0dFVCAvdjEvYXBpL2hlbGxvL3tuYW1lfScsIGhhbmRsZXI6IGhlbGxvRnVuY3Rpb24gfSxcbiAqICAgaGVsbG9zOiB7IHBhdGg6ICdHRVQgL3YxL2FwaS9oZWxsb3MnLCBoYW5kbGVyOiBoZWxsb3NGdW5jdGlvbiB9XG4gKiB9KTtcbiAqXG4gKiBjb25zdCBjbGllbnQgPSBjcmVhdGVIdHRwQmluZGluZ3MoZW5kcG9pbnQsIGFwaSwgWydoZWxsbycsICdoZWxsb3MnXSk7XG4gKiBhd2FpdCBjbGllbnQuaGVsbG8oJ0pvaG4nKTsgIC8vIChuYW1lOiBzdHJpbmcpID0+IFByb21pc2U8c3RyaW5nPlxuICogYXdhaXQgY2xpZW50LmhlbGxvcygpOyAgICAgICAvLyAoKSA9PiBQcm9taXNlPEdyZWV0aW5nW10+XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IGNyZWF0ZUh0dHBCaW5kaW5ncyA9IDxcbiAgVFJvdXRlcyBleHRlbmRzIEFwaVJvdXRlcyxcbiAgSyBleHRlbmRzIGtleW9mIFRSb3V0ZXMgJiBzdHJpbmdcbj4oXG4gIGVuZHBvaW50OiBTZXJ2aWNlRW5kcG9pbnQsXG4gIGNvbnRhaW5lcjogQXBpQ29udGFpbmVyPFRSb3V0ZXM+LFxuICByb3V0ZU5hbWVzOiByZWFkb25seSBLW10sXG4gIGZldGNoZXI6IEZldGNoZXIgPSAoKSA9PiAoe2ZldGNofSlcbik6IFBpY2s8Um91dGVIYW5kbGVyczxUUm91dGVzPiwgSz4gPT4ge1xuICByZXR1cm4gcm91dGVOYW1lcy5yZWR1Y2UoXG4gICAgKGFjYywgbmFtZSkgPT4ge1xuICAgICAgYWNjW25hbWVdID0gaHR0cEhhbmRsZXIoZW5kcG9pbnQsIGNvbnRhaW5lciwgbmFtZSwgZmV0Y2hlcik7XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sXG4gICAge30gYXMgUGljazxSb3V0ZUhhbmRsZXJzPFRSb3V0ZXM+LCBLPlxuICApO1xufTtcbiJdfQ==
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { Construct } from 'constructs';
2
2
  export { Architecture, ArchitectureDefinition, ComponentDefinition } from './architecture';
3
3
  export { Function, TBDFunction, FunctionHandler } from './function';
4
- export { ApiContainer, ApiRoutes, RouteEntry } from './api-container';
4
+ export { ApiContainer, ApiRoutes, RouteEntry, HandlerOf, RouteHandlers } from './api-container';
5
5
  export { ArchitectureBinding, ServiceEndpoint, architectureBinding } from './binding';
6
- export { httpHandler } from './http-handler';
6
+ export { httpHandler, createHttpBindings, Fetcher } from './http-handler';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.httpHandler = exports.architectureBinding = exports.ArchitectureBinding = exports.ApiContainer = exports.TBDFunction = exports.Function = exports.Architecture = exports.Construct = void 0;
3
+ exports.createHttpBindings = exports.httpHandler = exports.architectureBinding = exports.ArchitectureBinding = exports.ApiContainer = exports.TBDFunction = exports.Function = exports.Architecture = exports.Construct = void 0;
4
4
  var constructs_1 = require("constructs");
5
5
  Object.defineProperty(exports, "Construct", { enumerable: true, get: function () { return constructs_1.Construct; } });
6
6
  var architecture_1 = require("./architecture");
@@ -15,4 +15,5 @@ Object.defineProperty(exports, "ArchitectureBinding", { enumerable: true, get: f
15
15
  Object.defineProperty(exports, "architectureBinding", { enumerable: true, get: function () { return binding_1.architectureBinding; } });
16
16
  var http_handler_1 = require("./http-handler");
17
17
  Object.defineProperty(exports, "httpHandler", { enumerable: true, get: function () { return http_handler_1.httpHandler; } });
18
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEseUNBQXVDO0FBQTlCLHVHQUFBLFNBQVMsT0FBQTtBQUNsQiwrQ0FBMkY7QUFBbEYsNEdBQUEsWUFBWSxPQUFBO0FBQ3JCLHVDQUFvRTtBQUEzRCxvR0FBQSxRQUFRLE9BQUE7QUFBRSx1R0FBQSxXQUFXLE9BQUE7QUFDOUIsaURBQXNFO0FBQTdELDZHQUFBLFlBQVksT0FBQTtBQUNyQixxQ0FBc0Y7QUFBN0UsOEdBQUEsbUJBQW1CLE9BQUE7QUFBbUIsOEdBQUEsbUJBQW1CLE9BQUE7QUFDbEUsK0NBQTZDO0FBQXBDLDJHQUFBLFdBQVcsT0FBQSIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuZXhwb3J0IHsgQXJjaGl0ZWN0dXJlLCBBcmNoaXRlY3R1cmVEZWZpbml0aW9uLCBDb21wb25lbnREZWZpbml0aW9uIH0gZnJvbSAnLi9hcmNoaXRlY3R1cmUnO1xuZXhwb3J0IHsgRnVuY3Rpb24sIFRCREZ1bmN0aW9uLCBGdW5jdGlvbkhhbmRsZXIgfSBmcm9tICcuL2Z1bmN0aW9uJztcbmV4cG9ydCB7IEFwaUNvbnRhaW5lciwgQXBpUm91dGVzLCBSb3V0ZUVudHJ5IH0gZnJvbSAnLi9hcGktY29udGFpbmVyJztcbmV4cG9ydCB7IEFyY2hpdGVjdHVyZUJpbmRpbmcsIFNlcnZpY2VFbmRwb2ludCwgYXJjaGl0ZWN0dXJlQmluZGluZyB9IGZyb20gJy4vYmluZGluZyc7XG5leHBvcnQgeyBodHRwSGFuZGxlciB9IGZyb20gJy4vaHR0cC1oYW5kbGVyJztcbiJdfQ==
18
+ Object.defineProperty(exports, "createHttpBindings", { enumerable: true, get: function () { return http_handler_1.createHttpBindings; } });
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEseUNBQXVDO0FBQTlCLHVHQUFBLFNBQVMsT0FBQTtBQUNsQiwrQ0FBMkY7QUFBbEYsNEdBQUEsWUFBWSxPQUFBO0FBQ3JCLHVDQUFvRTtBQUEzRCxvR0FBQSxRQUFRLE9BQUE7QUFBRSx1R0FBQSxXQUFXLE9BQUE7QUFDOUIsaURBQWdHO0FBQXZGLDZHQUFBLFlBQVksT0FBQTtBQUNyQixxQ0FBc0Y7QUFBN0UsOEdBQUEsbUJBQW1CLE9BQUE7QUFBbUIsOEdBQUEsbUJBQW1CLE9BQUE7QUFDbEUsK0NBQTBFO0FBQWpFLDJHQUFBLFdBQVcsT0FBQTtBQUFFLGtIQUFBLGtCQUFrQixPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5leHBvcnQgeyBBcmNoaXRlY3R1cmUsIEFyY2hpdGVjdHVyZURlZmluaXRpb24sIENvbXBvbmVudERlZmluaXRpb24gfSBmcm9tICcuL2FyY2hpdGVjdHVyZSc7XG5leHBvcnQgeyBGdW5jdGlvbiwgVEJERnVuY3Rpb24sIEZ1bmN0aW9uSGFuZGxlciB9IGZyb20gJy4vZnVuY3Rpb24nO1xuZXhwb3J0IHsgQXBpQ29udGFpbmVyLCBBcGlSb3V0ZXMsIFJvdXRlRW50cnksIEhhbmRsZXJPZiwgUm91dGVIYW5kbGVycyB9IGZyb20gJy4vYXBpLWNvbnRhaW5lcic7XG5leHBvcnQgeyBBcmNoaXRlY3R1cmVCaW5kaW5nLCBTZXJ2aWNlRW5kcG9pbnQsIGFyY2hpdGVjdHVyZUJpbmRpbmcgfSBmcm9tICcuL2JpbmRpbmcnO1xuZXhwb3J0IHsgaHR0cEhhbmRsZXIsIGNyZWF0ZUh0dHBCaW5kaW5ncywgRmV0Y2hlciB9IGZyb20gJy4vaHR0cC1oYW5kbGVyJztcbiJdfQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arinoto/cdk-arch",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CDK Architecture primitives for event-driven solution architectures",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,31 +1,66 @@
1
1
  import { Construct } from 'constructs';
2
2
  import { Function, TBDFunction } from './function';
3
3
 
4
- export interface ApiRoutes {
5
- [name: string]: RouteEntry;
4
+ /**
5
+ * A route entry that captures the handler's argument and return types.
6
+ */
7
+ export interface RouteEntry<TArgs extends any[] = any[], TReturn = any> {
8
+ path: string;
9
+ handler: Function<TArgs, TReturn>;
6
10
  }
7
11
 
8
- export interface RouteEntry {
9
- path: string;
10
- handler: Function;
12
+ /**
13
+ * Base type for route definitions - maps route names to route entries.
14
+ */
15
+ export type ApiRoutes = {
16
+ [name: string]: RouteEntry;
11
17
  }
12
18
 
13
19
  /**
14
- * Represents an API container that routes requests to functions
20
+ * Extract the handler signature from a Function type.
21
+ */
22
+ export type HandlerOf<T> = T extends Function<infer Args, infer Return>
23
+ ? (...args: Args) => Promise<Return>
24
+ : never;
25
+
26
+ /**
27
+ * Extract handler signatures from all routes in an ApiRoutes type.
28
+ */
29
+ export type RouteHandlers<TRoutes extends ApiRoutes> = {
30
+ [K in keyof TRoutes]: HandlerOf<TRoutes[K]['handler']>;
31
+ };
32
+
33
+ /**
34
+ * Represents an API container that routes requests to functions.
35
+ *
36
+ * @typeParam TRoutes - The type of the routes object, preserving route names and handler signatures.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const api = new ApiContainer(arch, 'api', {
41
+ * hello: { path: 'GET /v1/api/hello/{name}', handler: helloFunction },
42
+ * hellos: { path: 'GET /v1/api/hellos', handler: hellosFunction }
43
+ * });
44
+ * // api has type ApiContainer<{ hello: RouteEntry<[string], string>, hellos: RouteEntry<[], Greeting[]> }>
45
+ * ```
15
46
  */
16
- export class ApiContainer extends Construct {
17
- public readonly routes: ApiRoutes;
47
+ export class ApiContainer<TRoutes extends ApiRoutes = ApiRoutes> extends Construct {
48
+ public readonly routes: TRoutes;
18
49
 
19
- constructor(scope: Construct, id: string, routes: ApiRoutes = {}) {
50
+ constructor(scope: Construct, id: string, routes: TRoutes = {} as TRoutes) {
20
51
  super(scope, id);
21
52
  this.routes = routes;
22
53
  }
23
54
 
24
- addRoute(name: string, path: string, handler: Function): void {
25
- this.routes[name] = { path, handler };
55
+ addRoute<TArgs extends any[], TReturn>(
56
+ name: string,
57
+ path: string,
58
+ handler: Function<TArgs, TReturn>
59
+ ): void {
60
+ (this.routes as ApiRoutes)[name] = { path, handler };
26
61
  }
27
62
 
28
- getRoute(name: string): RouteEntry {
63
+ getRoute<K extends keyof TRoutes & string>(name: K): TRoutes[K] {
29
64
  const entry = this.routes[name];
30
65
  if (!entry) {
31
66
  throw new Error(`Route '${name}' not found in container '${this.node.id}'`);
@@ -33,8 +68,8 @@ export class ApiContainer extends Construct {
33
68
  return entry;
34
69
  }
35
70
 
36
- listRoutes() : string[] {
37
- return Object.keys(this.routes);
71
+ listRoutes(): (keyof TRoutes & string)[] {
72
+ return Object.keys(this.routes) as (keyof TRoutes & string)[];
38
73
  }
39
74
 
40
75
  /**
package/src/binding.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Construct } from 'constructs';
2
- import { ApiContainer } from './api-container';
2
+ import { ApiContainer, ApiRoutes } from './api-container';
3
3
  import { Function, FunctionHandler } from './function';
4
4
 
5
5
  /**
@@ -33,7 +33,7 @@ export class ArchitectureBinding {
33
33
  * Optionally override function implementations with the overloads option.
34
34
  * Overload keys must be route names registered via addRoute.
35
35
  */
36
- bind(component: ApiContainer, options: BindOptions): void {
36
+ bind<TRoutes extends ApiRoutes>(component: ApiContainer<TRoutes>, options: BindOptions): void {
37
37
  this.bindings.set(component, { baseUrl: options.baseUrl });
38
38
 
39
39
  Object.entries(options.overloads ?? {}).forEach(([name, handler]) => {
@@ -1,26 +1,28 @@
1
- import { ApiContainer } from './api-container';
1
+ import { ApiContainer, ApiRoutes, RouteHandlers } from './api-container';
2
2
  import { FunctionHandler } from './function';
3
3
  import { ServiceEndpoint } from './binding';
4
4
 
5
+ export type Fetcher = () => { fetch: typeof fetch };
6
+
5
7
  /**
6
8
  * Create an HTTP handler for a route by name.
7
9
  * Looks up the route path from the container's registry.
8
10
  */
9
- export const httpHandler = (
11
+ export const httpHandler = <
12
+ TRoutes extends ApiRoutes,
13
+ K extends keyof TRoutes & string
14
+ >(
10
15
  endpoint: ServiceEndpoint,
11
- container: ApiContainer,
12
- routeName: string,
13
- fetcher: () => { fetch: typeof fetch } = () => ({fetch})
14
- ): FunctionHandler => {
16
+ container: ApiContainer<TRoutes>,
17
+ routeName: K,
18
+ fetcher: Fetcher = () => ({fetch})
19
+ ): RouteHandlers<TRoutes>[K] => {
15
20
  const route = container.getRoute(routeName);
16
- if (!route) {
17
- throw new Error(`Route '${routeName}' not found in container '${container.node.id}'`);
18
- }
19
21
 
20
22
  const [method, path] = route.path.split(' ');
21
23
  const pathParams = path.match(/\{(\w+)\}/g) || [];
22
24
 
23
- return async (...args: any[]) => {
25
+ const handler = async (...args: any[]) => {
24
26
  const url = pathParams.reduce(
25
27
  (u, param, i) => args[i] !== undefined ? u.replace(param, encodeURIComponent(String(args[i]))) : u,
26
28
  `${endpoint.baseUrl}${path}`
@@ -43,4 +45,44 @@ export const httpHandler = (
43
45
 
44
46
  return response.json();
45
47
  };
46
- };
48
+
49
+ return handler as RouteHandlers<TRoutes>[K];
50
+ };
51
+
52
+ /**
53
+ * Create HTTP bindings for multiple routes as a callable client.
54
+ * Returns a strongly-typed object where each route name maps to an async function
55
+ * with the same signature as the original handler.
56
+ *
57
+ * @typeParam TRoutes - The routes type from the ApiContainer
58
+ * @typeParam K - The subset of route names to include in the client
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const api = new ApiContainer(arch, 'api', {
63
+ * hello: { path: 'GET /v1/api/hello/{name}', handler: helloFunction },
64
+ * hellos: { path: 'GET /v1/api/hellos', handler: hellosFunction }
65
+ * });
66
+ *
67
+ * const client = createHttpBindings(endpoint, api, ['hello', 'hellos']);
68
+ * await client.hello('John'); // (name: string) => Promise<string>
69
+ * await client.hellos(); // () => Promise<Greeting[]>
70
+ * ```
71
+ */
72
+ export const createHttpBindings = <
73
+ TRoutes extends ApiRoutes,
74
+ K extends keyof TRoutes & string
75
+ >(
76
+ endpoint: ServiceEndpoint,
77
+ container: ApiContainer<TRoutes>,
78
+ routeNames: readonly K[],
79
+ fetcher: Fetcher = () => ({fetch})
80
+ ): Pick<RouteHandlers<TRoutes>, K> => {
81
+ return routeNames.reduce(
82
+ (acc, name) => {
83
+ acc[name] = httpHandler(endpoint, container, name, fetcher);
84
+ return acc;
85
+ },
86
+ {} as Pick<RouteHandlers<TRoutes>, K>
87
+ );
88
+ };
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Construct } from 'constructs';
2
2
  export { Architecture, ArchitectureDefinition, ComponentDefinition } from './architecture';
3
3
  export { Function, TBDFunction, FunctionHandler } from './function';
4
- export { ApiContainer, ApiRoutes, RouteEntry } from './api-container';
4
+ export { ApiContainer, ApiRoutes, RouteEntry, HandlerOf, RouteHandlers } from './api-container';
5
5
  export { ArchitectureBinding, ServiceEndpoint, architectureBinding } from './binding';
6
- export { httpHandler } from './http-handler';
6
+ export { httpHandler, createHttpBindings, Fetcher } from './http-handler';