@arinoto/cdk-arch 0.1.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.
@@ -0,0 +1,29 @@
1
+ import { Construct } from 'constructs';
2
+ import { Function } from './function';
3
+ export interface ApiRoutes {
4
+ [path: string]: Function;
5
+ }
6
+ export interface RouteEntry {
7
+ name: string;
8
+ path: string;
9
+ handler: Function;
10
+ }
11
+ /**
12
+ * Represents an API container that routes requests to functions
13
+ */
14
+ export declare class ApiContainer extends Construct {
15
+ readonly routes: ApiRoutes;
16
+ private namedRoutes;
17
+ constructor(scope: Construct, id: string, routes?: ApiRoutes);
18
+ addRoute(name: string, path: string, handler: Function): void;
19
+ getRoute(path: string): Function | undefined;
20
+ getRouteByName(name: string): RouteEntry | undefined;
21
+ listRoutes(): string[];
22
+ listNamedRoutes(): RouteEntry[];
23
+ /**
24
+ * Returns a list of TBDFunctions that have not been overloaded.
25
+ * Use this to validate that all required implementations are provided.
26
+ */
27
+ validateOverloads(): Function[];
28
+ }
29
+ //# sourceMappingURL=api-container.d.ts.map
@@ -0,0 +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,QAAQ,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,SAAS;IACzC,SAAgB,MAAM,EAAE,SAAS,CAAC;IAClC,OAAO,CAAC,WAAW,CAAsC;gBAE7C,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;IAK7D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI5C,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIpD,UAAU,IAAI,MAAM,EAAE;IAItB,eAAe,IAAI,UAAU,EAAE;IAI/B;;;OAGG;IACH,iBAAiB,IAAI,QAAQ,EAAE;CAIhC"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiContainer = void 0;
4
+ const constructs_1 = require("constructs");
5
+ const function_1 = require("./function");
6
+ /**
7
+ * Represents an API container that routes requests to functions
8
+ */
9
+ class ApiContainer extends constructs_1.Construct {
10
+ constructor(scope, id, routes = {}) {
11
+ super(scope, id);
12
+ this.namedRoutes = new Map();
13
+ this.routes = routes;
14
+ }
15
+ addRoute(name, path, handler) {
16
+ this.routes[path] = handler;
17
+ this.namedRoutes.set(name, { name, path, handler });
18
+ }
19
+ getRoute(path) {
20
+ return this.routes[path];
21
+ }
22
+ getRouteByName(name) {
23
+ return this.namedRoutes.get(name);
24
+ }
25
+ listRoutes() {
26
+ return Object.keys(this.routes);
27
+ }
28
+ listNamedRoutes() {
29
+ return Array.from(this.namedRoutes.values());
30
+ }
31
+ /**
32
+ * Returns a list of TBDFunctions that have not been overloaded.
33
+ * Use this to validate that all required implementations are provided.
34
+ */
35
+ validateOverloads() {
36
+ return Object.values(this.routes)
37
+ .filter(fn => fn instanceof function_1.TBDFunction && !fn.hasOverload());
38
+ }
39
+ }
40
+ exports.ApiContainer = ApiContainer;
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWNvbnRhaW5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hcGktY29udGFpbmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJDQUF1QztBQUN2Qyx5Q0FBbUQ7QUFZbkQ7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxzQkFBUztJQUl6QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLFNBQW9CLEVBQUU7UUFDOUQsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUhYLGdCQUFXLEdBQTRCLElBQUksR0FBRyxFQUFFLENBQUM7UUFJdkQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELFFBQVEsQ0FBQyxJQUFZLEVBQUUsSUFBWSxFQUFFLE9BQWlCO1FBQ3BELElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxDQUFDO1FBQzVCLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsUUFBUSxDQUFDLElBQVk7UUFDbkIsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCxjQUFjLENBQUMsSUFBWTtRQUN6QixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRUQsZUFBZTtRQUNiLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7T0FHRztJQUNILGlCQUFpQjtRQUNmLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO2FBQzlCLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsWUFBWSxzQkFBVyxJQUFJLENBQUMsRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7SUFDbEUsQ0FBQztDQUNGO0FBdENELG9DQXNDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgRnVuY3Rpb24sIFRCREZ1bmN0aW9uIH0gZnJvbSAnLi9mdW5jdGlvbic7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQXBpUm91dGVzIHtcbiAgW3BhdGg6IHN0cmluZ106IEZ1bmN0aW9uO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJvdXRlRW50cnkge1xuICBuYW1lOiBzdHJpbmc7XG4gIHBhdGg6IHN0cmluZztcbiAgaGFuZGxlcjogRnVuY3Rpb247XG59XG5cbi8qKlxuICogUmVwcmVzZW50cyBhbiBBUEkgY29udGFpbmVyIHRoYXQgcm91dGVzIHJlcXVlc3RzIHRvIGZ1bmN0aW9uc1xuICovXG5leHBvcnQgY2xhc3MgQXBpQ29udGFpbmVyIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgcHVibGljIHJlYWRvbmx5IHJvdXRlczogQXBpUm91dGVzO1xuICBwcml2YXRlIG5hbWVkUm91dGVzOiBNYXA8c3RyaW5nLCBSb3V0ZUVudHJ5PiA9IG5ldyBNYXAoKTtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCByb3V0ZXM6IEFwaVJvdXRlcyA9IHt9KSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICB0aGlzLnJvdXRlcyA9IHJvdXRlcztcbiAgfVxuXG4gIGFkZFJvdXRlKG5hbWU6IHN0cmluZywgcGF0aDogc3RyaW5nLCBoYW5kbGVyOiBGdW5jdGlvbik6IHZvaWQge1xuICAgIHRoaXMucm91dGVzW3BhdGhdID0gaGFuZGxlcjtcbiAgICB0aGlzLm5hbWVkUm91dGVzLnNldChuYW1lLCB7IG5hbWUsIHBhdGgsIGhhbmRsZXIgfSk7XG4gIH1cblxuICBnZXRSb3V0ZShwYXRoOiBzdHJpbmcpOiBGdW5jdGlvbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucm91dGVzW3BhdGhdO1xuICB9XG5cbiAgZ2V0Um91dGVCeU5hbWUobmFtZTogc3RyaW5nKTogUm91dGVFbnRyeSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubmFtZWRSb3V0ZXMuZ2V0KG5hbWUpO1xuICB9XG5cbiAgbGlzdFJvdXRlcygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKHRoaXMucm91dGVzKTtcbiAgfVxuXG4gIGxpc3ROYW1lZFJvdXRlcygpOiBSb3V0ZUVudHJ5W10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMubmFtZWRSb3V0ZXMudmFsdWVzKCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBsaXN0IG9mIFRCREZ1bmN0aW9ucyB0aGF0IGhhdmUgbm90IGJlZW4gb3ZlcmxvYWRlZC5cbiAgICogVXNlIHRoaXMgdG8gdmFsaWRhdGUgdGhhdCBhbGwgcmVxdWlyZWQgaW1wbGVtZW50YXRpb25zIGFyZSBwcm92aWRlZC5cbiAgICovXG4gIHZhbGlkYXRlT3ZlcmxvYWRzKCk6IEZ1bmN0aW9uW10ge1xuICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMucm91dGVzKVxuICAgICAgLmZpbHRlcihmbiA9PiBmbiBpbnN0YW5jZW9mIFRCREZ1bmN0aW9uICYmICFmbi5oYXNPdmVybG9hZCgpKTtcbiAgfVxufVxuIl19
@@ -0,0 +1,19 @@
1
+ import { Construct } from 'constructs';
2
+ /**
3
+ * The root construct that represents an entire architecture
4
+ */
5
+ export declare class Architecture extends Construct {
6
+ constructor(id?: string);
7
+ synth(): ArchitectureDefinition;
8
+ private synthComponent;
9
+ }
10
+ export interface ArchitectureDefinition {
11
+ id: string;
12
+ components: ComponentDefinition[];
13
+ }
14
+ export interface ComponentDefinition {
15
+ id: string;
16
+ path: string;
17
+ type: string;
18
+ }
19
+ //# sourceMappingURL=architecture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture.d.ts","sourceRoot":"","sources":["../src/architecture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;GAEG;AACH,qBAAa,YAAa,SAAQ,SAAS;gBAC7B,EAAE,GAAE,MAAuB;IAIhC,KAAK,IAAI,sBAAsB;IAOtC,OAAO,CAAC,cAAc;CAOvB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Architecture = void 0;
4
+ const constructs_1 = require("constructs");
5
+ /**
6
+ * The root construct that represents an entire architecture
7
+ */
8
+ class Architecture extends constructs_1.Construct {
9
+ constructor(id = 'architecture') {
10
+ super(undefined, id);
11
+ }
12
+ synth() {
13
+ return {
14
+ id: this.node.id,
15
+ components: this.node.children.map(c => this.synthComponent(c))
16
+ };
17
+ }
18
+ synthComponent(construct) {
19
+ return {
20
+ id: construct.node.id,
21
+ path: construct.node.path,
22
+ type: construct.constructor.name
23
+ };
24
+ }
25
+ }
26
+ exports.Architecture = Architecture;
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJjaGl0ZWN0dXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2FyY2hpdGVjdHVyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwyQ0FBdUM7QUFFdkM7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxzQkFBUztJQUN6QyxZQUFZLEtBQWEsY0FBYztRQUNyQyxLQUFLLENBQUMsU0FBZ0IsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRU0sS0FBSztRQUNWLE9BQU87WUFDTCxFQUFFLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ2hCLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQWMsQ0FBQyxDQUFDO1NBQzdFLENBQUM7SUFDSixDQUFDO0lBRU8sY0FBYyxDQUFDLFNBQW9CO1FBQ3pDLE9BQU87WUFDTCxFQUFFLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ3JCLElBQUksRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUk7WUFDekIsSUFBSSxFQUFFLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSTtTQUNqQyxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBbkJELG9DQW1CQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuXG4vKipcbiAqIFRoZSByb290IGNvbnN0cnVjdCB0aGF0IHJlcHJlc2VudHMgYW4gZW50aXJlIGFyY2hpdGVjdHVyZVxuICovXG5leHBvcnQgY2xhc3MgQXJjaGl0ZWN0dXJlIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgY29uc3RydWN0b3IoaWQ6IHN0cmluZyA9ICdhcmNoaXRlY3R1cmUnKSB7XG4gICAgc3VwZXIodW5kZWZpbmVkIGFzIGFueSwgaWQpO1xuICB9XG5cbiAgcHVibGljIHN5bnRoKCk6IEFyY2hpdGVjdHVyZURlZmluaXRpb24ge1xuICAgIHJldHVybiB7XG4gICAgICBpZDogdGhpcy5ub2RlLmlkLFxuICAgICAgY29tcG9uZW50czogdGhpcy5ub2RlLmNoaWxkcmVuLm1hcChjID0+IHRoaXMuc3ludGhDb21wb25lbnQoYyBhcyBDb25zdHJ1Y3QpKVxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN5bnRoQ29tcG9uZW50KGNvbnN0cnVjdDogQ29uc3RydWN0KTogQ29tcG9uZW50RGVmaW5pdGlvbiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBjb25zdHJ1Y3Qubm9kZS5pZCxcbiAgICAgIHBhdGg6IGNvbnN0cnVjdC5ub2RlLnBhdGgsXG4gICAgICB0eXBlOiBjb25zdHJ1Y3QuY29uc3RydWN0b3IubmFtZVxuICAgIH07XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBBcmNoaXRlY3R1cmVEZWZpbml0aW9uIHtcbiAgaWQ6IHN0cmluZztcbiAgY29tcG9uZW50czogQ29tcG9uZW50RGVmaW5pdGlvbltdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbXBvbmVudERlZmluaXRpb24ge1xuICBpZDogc3RyaW5nO1xuICBwYXRoOiBzdHJpbmc7XG4gIHR5cGU6IHN0cmluZztcbn1cbiJdfQ==
@@ -0,0 +1,48 @@
1
+ import { Construct } from 'constructs';
2
+ import { ApiContainer } from './api-container';
3
+ import { FunctionHandler } from './function';
4
+ /**
5
+ * Service discovery configuration for runtime
6
+ */
7
+ export interface ServiceEndpoint {
8
+ host: string;
9
+ port: number;
10
+ }
11
+ /**
12
+ * Binding options for an ApiContainer
13
+ */
14
+ export interface BindOptions extends ServiceEndpoint {
15
+ /**
16
+ * Override function implementations.
17
+ * Keys are function property names on the container.
18
+ */
19
+ overloads?: Record<string, FunctionHandler>;
20
+ }
21
+ /**
22
+ * Binding between architectural components and their runtime endpoints.
23
+ * Supports function overloading for replacing implementations at runtime.
24
+ */
25
+ export declare class ArchitectureBinding {
26
+ private bindings;
27
+ private localComponents;
28
+ /**
29
+ * Bind an architectural component to a service endpoint.
30
+ * Optionally override function implementations with the overloads option.
31
+ * Overload keys must be route names registered via addRoute.
32
+ */
33
+ bind(component: ApiContainer, options: BindOptions): void;
34
+ /**
35
+ * Bind a component from environment variables.
36
+ * Looks for {PREFIX}_HOST and {PREFIX}_PORT environment variables.
37
+ */
38
+ bindFromEnv(component: ApiContainer, envPrefix: string, overloads?: Record<string, FunctionHandler>): void;
39
+ getEndpoint(component: Construct): ServiceEndpoint | undefined;
40
+ getAllBindings(): Map<Construct, ServiceEndpoint>;
41
+ setLocal(component: Construct): void;
42
+ isLocal(component: Construct): boolean;
43
+ }
44
+ /**
45
+ * Global binding registry
46
+ */
47
+ export declare const architectureBinding: ArchitectureBinding;
48
+ //# sourceMappingURL=binding.d.ts.map
@@ -0,0 +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,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;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;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI;IAQ1G,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"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.architectureBinding = exports.ArchitectureBinding = void 0;
4
+ const function_1 = require("./function");
5
+ /**
6
+ * Binding between architectural components and their runtime endpoints.
7
+ * Supports function overloading for replacing implementations at runtime.
8
+ */
9
+ class ArchitectureBinding {
10
+ constructor() {
11
+ this.bindings = new Map();
12
+ this.localComponents = new Set();
13
+ }
14
+ /**
15
+ * Bind an architectural component to a service endpoint.
16
+ * Optionally override function implementations with the overloads option.
17
+ * Overload keys must be route names registered via addRoute.
18
+ */
19
+ bind(component, options) {
20
+ this.bindings.set(component, { host: options.host, port: options.port });
21
+ Object.entries(options.overloads ?? {}).forEach(([name, handler]) => {
22
+ const route = component.getRouteByName(name);
23
+ if (!route) {
24
+ throw new Error(`Route '${name}' not found in component '${component.node.id}'`);
25
+ }
26
+ if (!(route.handler instanceof function_1.Function)) {
27
+ throw new Error(`Route '${name}' handler is not a Function`);
28
+ }
29
+ route.handler.overload(handler);
30
+ });
31
+ }
32
+ /**
33
+ * Bind a component from environment variables.
34
+ * Looks for {PREFIX}_HOST and {PREFIX}_PORT environment variables.
35
+ */
36
+ bindFromEnv(component, envPrefix, overloads) {
37
+ const host = process.env[`${envPrefix}_HOST`];
38
+ const port = process.env[`${envPrefix}_PORT`];
39
+ if (host && port) {
40
+ this.bind(component, { host, port: parseInt(port), overloads });
41
+ }
42
+ }
43
+ getEndpoint(component) {
44
+ return this.bindings.get(component);
45
+ }
46
+ getAllBindings() {
47
+ return this.bindings;
48
+ }
49
+ setLocal(component) {
50
+ this.localComponents.add(component);
51
+ }
52
+ isLocal(component) {
53
+ return this.localComponents.has(component);
54
+ }
55
+ }
56
+ exports.ArchitectureBinding = ArchitectureBinding;
57
+ /**
58
+ * Global binding registry
59
+ */
60
+ exports.architectureBinding = new ArchitectureBinding();
61
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmluZGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9iaW5kaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBLHlDQUF1RDtBQXFCdkQ7OztHQUdHO0FBQ0gsTUFBYSxtQkFBbUI7SUFBaEM7UUFDVSxhQUFRLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7UUFDdEQsb0JBQWUsR0FBbUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQWlEdEQsQ0FBQztJQS9DQzs7OztPQUlHO0lBQ0gsSUFBSSxDQUFDLFNBQXVCLEVBQUUsT0FBb0I7UUFDaEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRXpFLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO1lBQ2xFLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDN0MsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxJQUFJLDZCQUE2QixTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDbkYsQ0FBQztZQUNELElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLFlBQVksbUJBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQ3pDLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxJQUFJLDZCQUE2QixDQUFDLENBQUM7WUFDL0QsQ0FBQztZQUNELEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2xDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNILFdBQVcsQ0FBQyxTQUF1QixFQUFFLFNBQWlCLEVBQUUsU0FBMkM7UUFDakcsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsT0FBTyxDQUFDLENBQUM7UUFDOUMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsT0FBTyxDQUFDLENBQUM7UUFDOUMsSUFBSSxJQUFJLElBQUksSUFBSSxFQUFFLENBQUM7WUFDakIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVyxDQUFDLFNBQW9CO1FBQzlCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELGNBQWM7UUFDWixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDdkIsQ0FBQztJQUVELFFBQVEsQ0FBQyxTQUFvQjtRQUMzQixJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsT0FBTyxDQUFDLFNBQW9CO1FBQzFCLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDN0MsQ0FBQztDQUNGO0FBbkRELGtEQW1EQztBQUVEOztHQUVHO0FBQ1UsUUFBQSxtQkFBbUIsR0FBRyxJQUFJLG1CQUFtQixFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IEFwaUNvbnRhaW5lciB9IGZyb20gJy4vYXBpLWNvbnRhaW5lcic7XG5pbXBvcnQgeyBGdW5jdGlvbiwgRnVuY3Rpb25IYW5kbGVyIH0gZnJvbSAnLi9mdW5jdGlvbic7XG5cbi8qKlxuICogU2VydmljZSBkaXNjb3ZlcnkgY29uZmlndXJhdGlvbiBmb3IgcnVudGltZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZpY2VFbmRwb2ludCB7XG4gIGhvc3Q6IHN0cmluZztcbiAgcG9ydDogbnVtYmVyO1xufVxuXG4vKipcbiAqIEJpbmRpbmcgb3B0aW9ucyBmb3IgYW4gQXBpQ29udGFpbmVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQmluZE9wdGlvbnMgZXh0ZW5kcyBTZXJ2aWNlRW5kcG9pbnQge1xuICAvKipcbiAgICogT3ZlcnJpZGUgZnVuY3Rpb24gaW1wbGVtZW50YXRpb25zLlxuICAgKiBLZXlzIGFyZSBmdW5jdGlvbiBwcm9wZXJ0eSBuYW1lcyBvbiB0aGUgY29udGFpbmVyLlxuICAgKi9cbiAgb3ZlcmxvYWRzPzogUmVjb3JkPHN0cmluZywgRnVuY3Rpb25IYW5kbGVyPjtcbn1cblxuLyoqXG4gKiBCaW5kaW5nIGJldHdlZW4gYXJjaGl0ZWN0dXJhbCBjb21wb25lbnRzIGFuZCB0aGVpciBydW50aW1lIGVuZHBvaW50cy5cbiAqIFN1cHBvcnRzIGZ1bmN0aW9uIG92ZXJsb2FkaW5nIGZvciByZXBsYWNpbmcgaW1wbGVtZW50YXRpb25zIGF0IHJ1bnRpbWUuXG4gKi9cbmV4cG9ydCBjbGFzcyBBcmNoaXRlY3R1cmVCaW5kaW5nIHtcbiAgcHJpdmF0ZSBiaW5kaW5nczogTWFwPENvbnN0cnVjdCwgU2VydmljZUVuZHBvaW50PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBsb2NhbENvbXBvbmVudHM6IFNldDxDb25zdHJ1Y3Q+ID0gbmV3IFNldCgpO1xuXG4gIC8qKlxuICAgKiBCaW5kIGFuIGFyY2hpdGVjdHVyYWwgY29tcG9uZW50IHRvIGEgc2VydmljZSBlbmRwb2ludC5cbiAgICogT3B0aW9uYWxseSBvdmVycmlkZSBmdW5jdGlvbiBpbXBsZW1lbnRhdGlvbnMgd2l0aCB0aGUgb3ZlcmxvYWRzIG9wdGlvbi5cbiAgICogT3ZlcmxvYWQga2V5cyBtdXN0IGJlIHJvdXRlIG5hbWVzIHJlZ2lzdGVyZWQgdmlhIGFkZFJvdXRlLlxuICAgKi9cbiAgYmluZChjb21wb25lbnQ6IEFwaUNvbnRhaW5lciwgb3B0aW9uczogQmluZE9wdGlvbnMpOiB2b2lkIHtcbiAgICB0aGlzLmJpbmRpbmdzLnNldChjb21wb25lbnQsIHsgaG9zdDogb3B0aW9ucy5ob3N0LCBwb3J0OiBvcHRpb25zLnBvcnQgfSk7XG5cbiAgICBPYmplY3QuZW50cmllcyhvcHRpb25zLm92ZXJsb2FkcyA/PyB7fSkuZm9yRWFjaCgoW25hbWUsIGhhbmRsZXJdKSA9PiB7XG4gICAgICBjb25zdCByb3V0ZSA9IGNvbXBvbmVudC5nZXRSb3V0ZUJ5TmFtZShuYW1lKTtcbiAgICAgIGlmICghcm91dGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSb3V0ZSAnJHtuYW1lfScgbm90IGZvdW5kIGluIGNvbXBvbmVudCAnJHtjb21wb25lbnQubm9kZS5pZH0nYCk7XG4gICAgICB9XG4gICAgICBpZiAoIShyb3V0ZS5oYW5kbGVyIGluc3RhbmNlb2YgRnVuY3Rpb24pKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgUm91dGUgJyR7bmFtZX0nIGhhbmRsZXIgaXMgbm90IGEgRnVuY3Rpb25gKTtcbiAgICAgIH1cbiAgICAgIHJvdXRlLmhhbmRsZXIub3ZlcmxvYWQoaGFuZGxlcik7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQmluZCBhIGNvbXBvbmVudCBmcm9tIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAgICogTG9va3MgZm9yIHtQUkVGSVh9X0hPU1QgYW5kIHtQUkVGSVh9X1BPUlQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICAgKi9cbiAgYmluZEZyb21FbnYoY29tcG9uZW50OiBBcGlDb250YWluZXIsIGVudlByZWZpeDogc3RyaW5nLCBvdmVybG9hZHM/OiBSZWNvcmQ8c3RyaW5nLCBGdW5jdGlvbkhhbmRsZXI+KTogdm9pZCB7XG4gICAgY29uc3QgaG9zdCA9IHByb2Nlc3MuZW52W2Ake2VudlByZWZpeH1fSE9TVGBdO1xuICAgIGNvbnN0IHBvcnQgPSBwcm9jZXNzLmVudltgJHtlbnZQcmVmaXh9X1BPUlRgXTtcbiAgICBpZiAoaG9zdCAmJiBwb3J0KSB7XG4gICAgICB0aGlzLmJpbmQoY29tcG9uZW50LCB7IGhvc3QsIHBvcnQ6IHBhcnNlSW50KHBvcnQpLCBvdmVybG9hZHMgfSk7XG4gICAgfVxuICB9XG5cbiAgZ2V0RW5kcG9pbnQoY29tcG9uZW50OiBDb25zdHJ1Y3QpOiBTZXJ2aWNlRW5kcG9pbnQgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmJpbmRpbmdzLmdldChjb21wb25lbnQpO1xuICB9XG5cbiAgZ2V0QWxsQmluZGluZ3MoKTogTWFwPENvbnN0cnVjdCwgU2VydmljZUVuZHBvaW50PiB7XG4gICAgcmV0dXJuIHRoaXMuYmluZGluZ3M7XG4gIH1cblxuICBzZXRMb2NhbChjb21wb25lbnQ6IENvbnN0cnVjdCk6IHZvaWQge1xuICAgIHRoaXMubG9jYWxDb21wb25lbnRzLmFkZChjb21wb25lbnQpO1xuICB9XG5cbiAgaXNMb2NhbChjb21wb25lbnQ6IENvbnN0cnVjdCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmxvY2FsQ29tcG9uZW50cy5oYXMoY29tcG9uZW50KTtcbiAgfVxufVxuXG4vKipcbiAqIEdsb2JhbCBiaW5kaW5nIHJlZ2lzdHJ5XG4gKi9cbmV4cG9ydCBjb25zdCBhcmNoaXRlY3R1cmVCaW5kaW5nID0gbmV3IEFyY2hpdGVjdHVyZUJpbmRpbmcoKTtcbiJdfQ==
@@ -0,0 +1,26 @@
1
+ import { Construct } from 'constructs';
2
+ export type FunctionHandler<TArgs extends any[] = any[], TReturn = any> = (...args: TArgs) => Promise<TReturn>;
3
+ /**
4
+ * Represents a serverless function or handler in the architecture.
5
+ * Generic over argument types (TArgs) and return type (TReturn).
6
+ */
7
+ export declare class Function<TArgs extends any[] = any[], TReturn = any> extends Construct {
8
+ readonly handler: FunctionHandler<TArgs, TReturn>;
9
+ private _overload?;
10
+ constructor(scope: Construct, id: string, handler: FunctionHandler<TArgs, TReturn>);
11
+ /**
12
+ * Override the function's implementation at runtime.
13
+ * Used for replacing in-memory implementations with storage adapters or HTTP calls.
14
+ */
15
+ overload(handler: FunctionHandler<TArgs, TReturn>): void;
16
+ hasOverload(): boolean;
17
+ invoke(...args: TArgs): Promise<TReturn>;
18
+ }
19
+ /**
20
+ * A placeholder function that must be overloaded before use.
21
+ * Use this when defining an API contract without providing an implementation.
22
+ */
23
+ export declare class TBDFunction<TArgs extends any[] = any[], TReturn = any> extends Function<TArgs, TReturn> {
24
+ constructor(scope: Construct, id: string);
25
+ }
26
+ //# sourceMappingURL=function.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../src/function.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,MAAM,eAAe,CAAC,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,OAAO,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE/G;;;GAGG;AACH,qBAAa,QAAQ,CAAC,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,OAAO,GAAG,GAAG,CAAE,SAAQ,SAAS;IACjF,SAAgB,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACzD,OAAO,CAAC,SAAS,CAAC,CAAkC;gBAExC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC;IAKlF;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,IAAI;IAIxD,WAAW,IAAI,OAAO;IAIf,MAAM,CAAC,GAAG,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;CAIhD;AAED;;;GAGG;AACH,qBAAa,WAAW,CAAC,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,OAAO,GAAG,GAAG,CAAE,SAAQ,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBACvF,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM;CAKzC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TBDFunction = exports.Function = void 0;
4
+ const constructs_1 = require("constructs");
5
+ /**
6
+ * Represents a serverless function or handler in the architecture.
7
+ * Generic over argument types (TArgs) and return type (TReturn).
8
+ */
9
+ class Function extends constructs_1.Construct {
10
+ constructor(scope, id, handler) {
11
+ super(scope, id);
12
+ this.handler = handler;
13
+ }
14
+ /**
15
+ * Override the function's implementation at runtime.
16
+ * Used for replacing in-memory implementations with storage adapters or HTTP calls.
17
+ */
18
+ overload(handler) {
19
+ this._overload = handler;
20
+ }
21
+ hasOverload() {
22
+ return this._overload !== undefined;
23
+ }
24
+ invoke(...args) {
25
+ const fn = this._overload ?? this.handler;
26
+ return Promise.resolve(fn(...args));
27
+ }
28
+ }
29
+ exports.Function = Function;
30
+ /**
31
+ * A placeholder function that must be overloaded before use.
32
+ * Use this when defining an API contract without providing an implementation.
33
+ */
34
+ class TBDFunction extends Function {
35
+ constructor(scope, id) {
36
+ super(scope, id, (() => {
37
+ return Promise.reject(new Error(`Function '${id}' is not implemented. Provide an overload before invoking.`));
38
+ }));
39
+ }
40
+ }
41
+ exports.TBDFunction = TBDFunction;
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZnVuY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMkNBQXVDO0FBSXZDOzs7R0FHRztBQUNILE1BQWEsUUFBcUQsU0FBUSxzQkFBUztJQUlqRixZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLE9BQXdDO1FBQ2hGLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDakIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDekIsQ0FBQztJQUVEOzs7T0FHRztJQUNILFFBQVEsQ0FBQyxPQUF3QztRQUMvQyxJQUFJLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQztJQUMzQixDQUFDO0lBRUQsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLFNBQVMsS0FBSyxTQUFTLENBQUM7SUFDdEMsQ0FBQztJQUVNLE1BQU0sQ0FBQyxHQUFHLElBQVc7UUFDMUIsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDO1FBQzFDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7Q0FDRjtBQXpCRCw0QkF5QkM7QUFFRDs7O0dBR0c7QUFDSCxNQUFhLFdBQXdELFNBQVEsUUFBd0I7SUFDbkcsWUFBWSxLQUFnQixFQUFFLEVBQVU7UUFDdEMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUU7WUFDckIsT0FBTyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLGFBQWEsRUFBRSw0REFBNEQsQ0FBQyxDQUFDLENBQUM7UUFDaEgsQ0FBQyxDQUFvQyxDQUFDLENBQUM7SUFDekMsQ0FBQztDQUNGO0FBTkQsa0NBTUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuZXhwb3J0IHR5cGUgRnVuY3Rpb25IYW5kbGVyPFRBcmdzIGV4dGVuZHMgYW55W10gPSBhbnlbXSwgVFJldHVybiA9IGFueT4gPSAoLi4uYXJnczogVEFyZ3MpID0+IFByb21pc2U8VFJldHVybj47XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIHNlcnZlcmxlc3MgZnVuY3Rpb24gb3IgaGFuZGxlciBpbiB0aGUgYXJjaGl0ZWN0dXJlLlxuICogR2VuZXJpYyBvdmVyIGFyZ3VtZW50IHR5cGVzIChUQXJncykgYW5kIHJldHVybiB0eXBlIChUUmV0dXJuKS5cbiAqL1xuZXhwb3J0IGNsYXNzIEZ1bmN0aW9uPFRBcmdzIGV4dGVuZHMgYW55W10gPSBhbnlbXSwgVFJldHVybiA9IGFueT4gZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBwdWJsaWMgcmVhZG9ubHkgaGFuZGxlcjogRnVuY3Rpb25IYW5kbGVyPFRBcmdzLCBUUmV0dXJuPjtcbiAgcHJpdmF0ZSBfb3ZlcmxvYWQ/OiBGdW5jdGlvbkhhbmRsZXI8VEFyZ3MsIFRSZXR1cm4+O1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIGhhbmRsZXI6IEZ1bmN0aW9uSGFuZGxlcjxUQXJncywgVFJldHVybj4pIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMuaGFuZGxlciA9IGhhbmRsZXI7XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIGZ1bmN0aW9uJ3MgaW1wbGVtZW50YXRpb24gYXQgcnVudGltZS5cbiAgICogVXNlZCBmb3IgcmVwbGFjaW5nIGluLW1lbW9yeSBpbXBsZW1lbnRhdGlvbnMgd2l0aCBzdG9yYWdlIGFkYXB0ZXJzIG9yIEhUVFAgY2FsbHMuXG4gICAqL1xuICBvdmVybG9hZChoYW5kbGVyOiBGdW5jdGlvbkhhbmRsZXI8VEFyZ3MsIFRSZXR1cm4+KTogdm9pZCB7XG4gICAgdGhpcy5fb3ZlcmxvYWQgPSBoYW5kbGVyO1xuICB9XG5cbiAgaGFzT3ZlcmxvYWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX292ZXJsb2FkICE9PSB1bmRlZmluZWQ7XG4gIH1cblxuICBwdWJsaWMgaW52b2tlKC4uLmFyZ3M6IFRBcmdzKTogUHJvbWlzZTxUUmV0dXJuPiB7XG4gICAgY29uc3QgZm4gPSB0aGlzLl9vdmVybG9hZCA/PyB0aGlzLmhhbmRsZXI7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShmbiguLi5hcmdzKSk7XG4gIH1cbn1cblxuLyoqXG4gKiBBIHBsYWNlaG9sZGVyIGZ1bmN0aW9uIHRoYXQgbXVzdCBiZSBvdmVybG9hZGVkIGJlZm9yZSB1c2UuXG4gKiBVc2UgdGhpcyB3aGVuIGRlZmluaW5nIGFuIEFQSSBjb250cmFjdCB3aXRob3V0IHByb3ZpZGluZyBhbiBpbXBsZW1lbnRhdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIFRCREZ1bmN0aW9uPFRBcmdzIGV4dGVuZHMgYW55W10gPSBhbnlbXSwgVFJldHVybiA9IGFueT4gZXh0ZW5kcyBGdW5jdGlvbjxUQXJncywgVFJldHVybj4ge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCAoKCkgPT4ge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihgRnVuY3Rpb24gJyR7aWR9JyBpcyBub3QgaW1wbGVtZW50ZWQuIFByb3ZpZGUgYW4gb3ZlcmxvYWQgYmVmb3JlIGludm9raW5nLmApKTtcbiAgICB9KSBhcyBGdW5jdGlvbkhhbmRsZXI8VEFyZ3MsIFRSZXR1cm4+KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,6 @@
1
+ export { Construct } from 'constructs';
2
+ export { Architecture, ArchitectureDefinition, ComponentDefinition } from './architecture';
3
+ export { Function, TBDFunction, FunctionHandler } from './function';
4
+ export { ApiContainer, ApiRoutes, RouteEntry } from './api-container';
5
+ export { ArchitectureBinding, ServiceEndpoint, architectureBinding } from './binding';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.architectureBinding = exports.ArchitectureBinding = exports.ApiContainer = exports.TBDFunction = exports.Function = exports.Architecture = exports.Construct = void 0;
4
+ var constructs_1 = require("constructs");
5
+ Object.defineProperty(exports, "Construct", { enumerable: true, get: function () { return constructs_1.Construct; } });
6
+ var architecture_1 = require("./architecture");
7
+ Object.defineProperty(exports, "Architecture", { enumerable: true, get: function () { return architecture_1.Architecture; } });
8
+ var function_1 = require("./function");
9
+ Object.defineProperty(exports, "Function", { enumerable: true, get: function () { return function_1.Function; } });
10
+ Object.defineProperty(exports, "TBDFunction", { enumerable: true, get: function () { return function_1.TBDFunction; } });
11
+ var api_container_1 = require("./api-container");
12
+ Object.defineProperty(exports, "ApiContainer", { enumerable: true, get: function () { return api_container_1.ApiContainer; } });
13
+ var binding_1 = require("./binding");
14
+ Object.defineProperty(exports, "ArchitectureBinding", { enumerable: true, get: function () { return binding_1.ArchitectureBinding; } });
15
+ Object.defineProperty(exports, "architectureBinding", { enumerable: true, get: function () { return binding_1.architectureBinding; } });
16
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEseUNBQXVDO0FBQTlCLHVHQUFBLFNBQVMsT0FBQTtBQUNsQiwrQ0FBMkY7QUFBbEYsNEdBQUEsWUFBWSxPQUFBO0FBQ3JCLHVDQUFvRTtBQUEzRCxvR0FBQSxRQUFRLE9BQUE7QUFBRSx1R0FBQSxXQUFXLE9BQUE7QUFDOUIsaURBQXNFO0FBQTdELDZHQUFBLFlBQVksT0FBQTtBQUNyQixxQ0FBc0Y7QUFBN0UsOEdBQUEsbUJBQW1CLE9BQUE7QUFBbUIsOEdBQUEsbUJBQW1CLE9BQUEiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmV4cG9ydCB7IEFyY2hpdGVjdHVyZSwgQXJjaGl0ZWN0dXJlRGVmaW5pdGlvbiwgQ29tcG9uZW50RGVmaW5pdGlvbiB9IGZyb20gJy4vYXJjaGl0ZWN0dXJlJztcbmV4cG9ydCB7IEZ1bmN0aW9uLCBUQkRGdW5jdGlvbiwgRnVuY3Rpb25IYW5kbGVyIH0gZnJvbSAnLi9mdW5jdGlvbic7XG5leHBvcnQgeyBBcGlDb250YWluZXIsIEFwaVJvdXRlcywgUm91dGVFbnRyeSB9IGZyb20gJy4vYXBpLWNvbnRhaW5lcic7XG5leHBvcnQgeyBBcmNoaXRlY3R1cmVCaW5kaW5nLCBTZXJ2aWNlRW5kcG9pbnQsIGFyY2hpdGVjdHVyZUJpbmRpbmcgfSBmcm9tICcuL2JpbmRpbmcnO1xuIl19
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@arinoto/cdk-arch",
3
+ "version": "0.1.0",
4
+ "description": "CDK Architecture primitives for event-driven solution architectures",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "private": false,
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "files": [
12
+ "src",
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "clean": "rm -rf dist"
18
+ },
19
+ "keywords": [
20
+ "cdk",
21
+ "architecture",
22
+ "cdktf"
23
+ ],
24
+ "license": "MIT",
25
+ "devDependencies": {
26
+ "@types/node": "^20.0.0",
27
+ "typescript": "^5.0.0"
28
+ },
29
+ "dependencies": {
30
+ "constructs": "^10.4.5"
31
+ }
32
+ }
@@ -0,0 +1,55 @@
1
+ import { Construct } from 'constructs';
2
+ import { Function, TBDFunction } from './function';
3
+
4
+ export interface ApiRoutes {
5
+ [path: string]: Function;
6
+ }
7
+
8
+ export interface RouteEntry {
9
+ name: string;
10
+ path: string;
11
+ handler: Function;
12
+ }
13
+
14
+ /**
15
+ * Represents an API container that routes requests to functions
16
+ */
17
+ export class ApiContainer extends Construct {
18
+ public readonly routes: ApiRoutes;
19
+ private namedRoutes: Map<string, RouteEntry> = new Map();
20
+
21
+ constructor(scope: Construct, id: string, routes: ApiRoutes = {}) {
22
+ super(scope, id);
23
+ this.routes = routes;
24
+ }
25
+
26
+ addRoute(name: string, path: string, handler: Function): void {
27
+ this.routes[path] = handler;
28
+ this.namedRoutes.set(name, { name, path, handler });
29
+ }
30
+
31
+ getRoute(path: string): Function | undefined {
32
+ return this.routes[path];
33
+ }
34
+
35
+ getRouteByName(name: string): RouteEntry | undefined {
36
+ return this.namedRoutes.get(name);
37
+ }
38
+
39
+ listRoutes(): string[] {
40
+ return Object.keys(this.routes);
41
+ }
42
+
43
+ listNamedRoutes(): RouteEntry[] {
44
+ return Array.from(this.namedRoutes.values());
45
+ }
46
+
47
+ /**
48
+ * Returns a list of TBDFunctions that have not been overloaded.
49
+ * Use this to validate that all required implementations are provided.
50
+ */
51
+ validateOverloads(): Function[] {
52
+ return Object.values(this.routes)
53
+ .filter(fn => fn instanceof TBDFunction && !fn.hasOverload());
54
+ }
55
+ }
@@ -0,0 +1,36 @@
1
+ import { Construct } from 'constructs';
2
+
3
+ /**
4
+ * The root construct that represents an entire architecture
5
+ */
6
+ export class Architecture extends Construct {
7
+ constructor(id: string = 'architecture') {
8
+ super(undefined as any, id);
9
+ }
10
+
11
+ public synth(): ArchitectureDefinition {
12
+ return {
13
+ id: this.node.id,
14
+ components: this.node.children.map(c => this.synthComponent(c as Construct))
15
+ };
16
+ }
17
+
18
+ private synthComponent(construct: Construct): ComponentDefinition {
19
+ return {
20
+ id: construct.node.id,
21
+ path: construct.node.path,
22
+ type: construct.constructor.name
23
+ };
24
+ }
25
+ }
26
+
27
+ export interface ArchitectureDefinition {
28
+ id: string;
29
+ components: ComponentDefinition[];
30
+ }
31
+
32
+ export interface ComponentDefinition {
33
+ id: string;
34
+ path: string;
35
+ type: string;
36
+ }
package/src/binding.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { Construct } from 'constructs';
2
+ import { ApiContainer } from './api-container';
3
+ import { Function, FunctionHandler } from './function';
4
+
5
+ /**
6
+ * Service discovery configuration for runtime
7
+ */
8
+ export interface ServiceEndpoint {
9
+ host: string;
10
+ port: number;
11
+ }
12
+
13
+ /**
14
+ * Binding options for an ApiContainer
15
+ */
16
+ export interface BindOptions extends ServiceEndpoint {
17
+ /**
18
+ * Override function implementations.
19
+ * Keys are function property names on the container.
20
+ */
21
+ overloads?: Record<string, FunctionHandler>;
22
+ }
23
+
24
+ /**
25
+ * Binding between architectural components and their runtime endpoints.
26
+ * Supports function overloading for replacing implementations at runtime.
27
+ */
28
+ export class ArchitectureBinding {
29
+ private bindings: Map<Construct, ServiceEndpoint> = new Map();
30
+ private localComponents: Set<Construct> = new Set();
31
+
32
+ /**
33
+ * Bind an architectural component to a service endpoint.
34
+ * Optionally override function implementations with the overloads option.
35
+ * Overload keys must be route names registered via addRoute.
36
+ */
37
+ bind(component: ApiContainer, options: BindOptions): void {
38
+ this.bindings.set(component, { host: options.host, port: options.port });
39
+
40
+ Object.entries(options.overloads ?? {}).forEach(([name, handler]) => {
41
+ const route = component.getRouteByName(name);
42
+ if (!route) {
43
+ throw new Error(`Route '${name}' not found in component '${component.node.id}'`);
44
+ }
45
+ if (!(route.handler instanceof Function)) {
46
+ throw new Error(`Route '${name}' handler is not a Function`);
47
+ }
48
+ route.handler.overload(handler);
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Bind a component from environment variables.
54
+ * Looks for {PREFIX}_HOST and {PREFIX}_PORT environment variables.
55
+ */
56
+ bindFromEnv(component: ApiContainer, envPrefix: string, overloads?: Record<string, FunctionHandler>): void {
57
+ const host = process.env[`${envPrefix}_HOST`];
58
+ const port = process.env[`${envPrefix}_PORT`];
59
+ if (host && port) {
60
+ this.bind(component, { host, port: parseInt(port), overloads });
61
+ }
62
+ }
63
+
64
+ getEndpoint(component: Construct): ServiceEndpoint | undefined {
65
+ return this.bindings.get(component);
66
+ }
67
+
68
+ getAllBindings(): Map<Construct, ServiceEndpoint> {
69
+ return this.bindings;
70
+ }
71
+
72
+ setLocal(component: Construct): void {
73
+ this.localComponents.add(component);
74
+ }
75
+
76
+ isLocal(component: Construct): boolean {
77
+ return this.localComponents.has(component);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Global binding registry
83
+ */
84
+ export const architectureBinding = new ArchitectureBinding();
@@ -0,0 +1,46 @@
1
+ import { Construct } from 'constructs';
2
+
3
+ export type FunctionHandler<TArgs extends any[] = any[], TReturn = any> = (...args: TArgs) => Promise<TReturn>;
4
+
5
+ /**
6
+ * Represents a serverless function or handler in the architecture.
7
+ * Generic over argument types (TArgs) and return type (TReturn).
8
+ */
9
+ export class Function<TArgs extends any[] = any[], TReturn = any> extends Construct {
10
+ public readonly handler: FunctionHandler<TArgs, TReturn>;
11
+ private _overload?: FunctionHandler<TArgs, TReturn>;
12
+
13
+ constructor(scope: Construct, id: string, handler: FunctionHandler<TArgs, TReturn>) {
14
+ super(scope, id);
15
+ this.handler = handler;
16
+ }
17
+
18
+ /**
19
+ * Override the function's implementation at runtime.
20
+ * Used for replacing in-memory implementations with storage adapters or HTTP calls.
21
+ */
22
+ overload(handler: FunctionHandler<TArgs, TReturn>): void {
23
+ this._overload = handler;
24
+ }
25
+
26
+ hasOverload(): boolean {
27
+ return this._overload !== undefined;
28
+ }
29
+
30
+ public invoke(...args: TArgs): Promise<TReturn> {
31
+ const fn = this._overload ?? this.handler;
32
+ return Promise.resolve(fn(...args));
33
+ }
34
+ }
35
+
36
+ /**
37
+ * A placeholder function that must be overloaded before use.
38
+ * Use this when defining an API contract without providing an implementation.
39
+ */
40
+ export class TBDFunction<TArgs extends any[] = any[], TReturn = any> extends Function<TArgs, TReturn> {
41
+ constructor(scope: Construct, id: string) {
42
+ super(scope, id, (() => {
43
+ return Promise.reject(new Error(`Function '${id}' is not implemented. Provide an overload before invoking.`));
44
+ }) as FunctionHandler<TArgs, TReturn>);
45
+ }
46
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { Construct } from 'constructs';
2
+ export { Architecture, ArchitectureDefinition, ComponentDefinition } from './architecture';
3
+ export { Function, TBDFunction, FunctionHandler } from './function';
4
+ export { ApiContainer, ApiRoutes, RouteEntry } from './api-container';
5
+ export { ArchitectureBinding, ServiceEndpoint, architectureBinding } from './binding';