@composurecdk/core 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.
- package/dist/builder.d.ts +46 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +42 -0
- package/dist/builder.js.map +1 -0
- package/dist/compose.d.ts +93 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +81 -0
- package/dist/compose.js.map +1 -0
- package/dist/cyclic-dependency-error.d.ts +12 -0
- package/dist/cyclic-dependency-error.d.ts.map +1 -0
- package/dist/cyclic-dependency-error.js +16 -0
- package/dist/cyclic-dependency-error.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +23 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +2 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/ref.d.ts +114 -0
- package/dist/ref.d.ts.map +1 -0
- package/dist/ref.js +103 -0
- package/dist/ref.js.map +1 -0
- package/dist/stack-strategy.d.ts +75 -0
- package/dist/stack-strategy.d.ts.map +1 -0
- package/dist/stack-strategy.js +55 -0
- package/dist/stack-strategy.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constructs an instance of `T`.
|
|
3
|
+
*/
|
|
4
|
+
type Constructor<T> = new () => T;
|
|
5
|
+
/**
|
|
6
|
+
* Constrains `T` to have a mutable `props` property of type `Props`.
|
|
7
|
+
* Classes used with {@link Builder} must expose their configuration this way.
|
|
8
|
+
*/
|
|
9
|
+
interface ObjectWithProps<Props extends object> {
|
|
10
|
+
props: Partial<Props>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A fluent builder interface generated from a props type and a target class.
|
|
14
|
+
*
|
|
15
|
+
* For each key in `Props`, the builder exposes an overloaded method:
|
|
16
|
+
* - Called with an argument: sets the prop value and returns the builder for chaining.
|
|
17
|
+
* - Called with no arguments: returns the current prop value.
|
|
18
|
+
*
|
|
19
|
+
* Methods from `T` that return `T` (chainable methods) have their return type
|
|
20
|
+
* replaced to return the builder. All other members of `T` pass through as-is,
|
|
21
|
+
* allowing methods like `build()` to be called directly on the builder.
|
|
22
|
+
*
|
|
23
|
+
* @typeParam Props - The configurable properties.
|
|
24
|
+
* @typeParam T - The target class the builder wraps.
|
|
25
|
+
*/
|
|
26
|
+
export type IBuilder<Props extends object, T> = {
|
|
27
|
+
[K in keyof Props]-?: ((arg: Props[K]) => IBuilder<Props, T>) & (() => Props[K]);
|
|
28
|
+
} & {
|
|
29
|
+
[K in keyof T]: T[K] extends (...args: infer A) => T ? (...args: A) => IBuilder<Props, T> : T[K];
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Creates a fluent builder wrapping an instance of `T`.
|
|
33
|
+
*
|
|
34
|
+
* The builder is backed by a {@link Proxy} that intercepts property access:
|
|
35
|
+
* - For keys in `Props`: returns a getter/setter function. When called with a
|
|
36
|
+
* value, it sets the prop and returns the builder. When called with no args,
|
|
37
|
+
* it returns the current value.
|
|
38
|
+
* - For methods on `T` that return `T`: wraps them to return the builder instead.
|
|
39
|
+
* - For all other members: delegates directly to the underlying instance.
|
|
40
|
+
*
|
|
41
|
+
* @param constructor - The class to instantiate and wrap.
|
|
42
|
+
* @returns A fluent {@link IBuilder} wrapping a new instance of `T`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function Builder<Props extends object, T extends ObjectWithProps<Props>>(constructor: Constructor<T>): IBuilder<Props, T>;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,KAAK,WAAW,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC;AAElC;;;GAGG;AACH,UAAU,eAAe,CAAC,KAAK,SAAS,MAAM;IAC5C,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,QAAQ,CAAC,KAAK,SAAS,MAAM,EAAE,CAAC,IAAI;KAC7C,CAAC,IAAI,MAAM,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;CACjF,GAAG;KACD,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACjG,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,KAAK,SAAS,MAAM,EAAE,CAAC,SAAS,eAAe,CAAC,KAAK,CAAC,EAC5E,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,GAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAoCpB"}
|
package/dist/builder.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a fluent builder wrapping an instance of `T`.
|
|
3
|
+
*
|
|
4
|
+
* The builder is backed by a {@link Proxy} that intercepts property access:
|
|
5
|
+
* - For keys in `Props`: returns a getter/setter function. When called with a
|
|
6
|
+
* value, it sets the prop and returns the builder. When called with no args,
|
|
7
|
+
* it returns the current value.
|
|
8
|
+
* - For methods on `T` that return `T`: wraps them to return the builder instead.
|
|
9
|
+
* - For all other members: delegates directly to the underlying instance.
|
|
10
|
+
*
|
|
11
|
+
* @param constructor - The class to instantiate and wrap.
|
|
12
|
+
* @returns A fluent {@link IBuilder} wrapping a new instance of `T`.
|
|
13
|
+
*/
|
|
14
|
+
export function Builder(constructor) {
|
|
15
|
+
const instance = new constructor();
|
|
16
|
+
const methods = new Set(Object.getOwnPropertyNames(Object.getPrototypeOf(instance)).filter((key) => key !== "constructor" && typeof instance[key] === "function"));
|
|
17
|
+
const proxy = new Proxy(instance, {
|
|
18
|
+
get(target, prop) {
|
|
19
|
+
if (typeof prop === "symbol") {
|
|
20
|
+
return Reflect.get(target, prop);
|
|
21
|
+
}
|
|
22
|
+
// Props getter/setter
|
|
23
|
+
if (!methods.has(prop)) {
|
|
24
|
+
return (...args) => {
|
|
25
|
+
if (args.length === 0) {
|
|
26
|
+
return target.props[prop];
|
|
27
|
+
}
|
|
28
|
+
target.props[prop] = args[0];
|
|
29
|
+
return proxy;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Method on target — wrap to return proxy for chainable methods
|
|
33
|
+
const method = target[prop];
|
|
34
|
+
return (...args) => {
|
|
35
|
+
const result = method.apply(target, args);
|
|
36
|
+
return result === target ? proxy : result;
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return proxy;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"AAiCA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CACrB,WAA2B;IAE3B,MAAM,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAChE,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,KAAK,aAAa,IAAI,OAAQ,QAAoC,CAAC,GAAG,CAAC,KAAK,UAAU,CAC5F,CACF,CAAC;IAEF,MAAM,KAAK,GAAuB,IAAI,KAAK,CAAC,QAAQ,EAAE;QACpD,GAAG,CAAC,MAAS,EAAE,IAAqB;YAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAY,CAAC;YAC9C,CAAC;YAED,sBAAsB;YACtB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE;oBAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACtB,OAAO,MAAM,CAAC,KAAK,CAAC,IAAmB,CAAC,CAAC;oBAC3C,CAAC;oBACD,MAAM,CAAC,KAAK,CAAC,IAAmB,CAAC,GAAG,IAAI,CAAC,CAAC,CAAuB,CAAC;oBAClE,OAAO,KAAK,CAAC;gBACf,CAAC,CAAC;YACJ,CAAC;YAED,gEAAgE;YAChE,MAAM,MAAM,GAAI,MAAkC,CAAC,IAAI,CAAiC,CAAC;YACzF,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE;gBAC5B,MAAM,MAAM,GAAY,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBACnD,OAAO,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;YAC5C,CAAC,CAAC;QACJ,CAAC;KACF,CAAuB,CAAC;IAEzB,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type IConstruct } from "constructs";
|
|
2
|
+
import { type Lifecycle } from "./lifecycle.js";
|
|
3
|
+
import { type StackStrategy } from "./stack-strategy.js";
|
|
4
|
+
/**
|
|
5
|
+
* Maps a record of {@link Lifecycle} components to a record of their build outputs.
|
|
6
|
+
* Each property's type is derived from the return type of the corresponding
|
|
7
|
+
* component's `build` method, preserving full type information through composition.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - A record where every value implements {@link Lifecycle}.
|
|
10
|
+
*/
|
|
11
|
+
type BuildResult<T extends {
|
|
12
|
+
[Property in keyof T]: Lifecycle;
|
|
13
|
+
}> = {
|
|
14
|
+
[Property in keyof T]: ReturnType<T[Property]["build"]>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Declares which other components a component depends on within a system.
|
|
18
|
+
* Dependencies are expressed as an array of component keys. During build,
|
|
19
|
+
* the resolved outputs of these components are passed as the component's context.
|
|
20
|
+
*
|
|
21
|
+
* @typeParam Components - The full set of components in the system.
|
|
22
|
+
*/
|
|
23
|
+
type Dependency<Components extends Record<string, Lifecycle>> = (keyof Components)[];
|
|
24
|
+
/**
|
|
25
|
+
* A {@link Lifecycle} produced by {@link compose}, extended with methods
|
|
26
|
+
* for controlling how components are routed to scopes during build.
|
|
27
|
+
*
|
|
28
|
+
* Because `ComposedSystem` extends `Lifecycle`, a composed system can be
|
|
29
|
+
* nested as a component inside another `compose` call — composition is
|
|
30
|
+
* recursive.
|
|
31
|
+
*/
|
|
32
|
+
export interface ComposedSystem<Components extends Record<string, Lifecycle>> extends Lifecycle<BuildResult<Components>> {
|
|
33
|
+
/**
|
|
34
|
+
* Returns a new {@link Lifecycle} that routes components to specific scopes
|
|
35
|
+
* (typically Stacks) during build. Components not listed in the map use the
|
|
36
|
+
* default scope passed to `build`.
|
|
37
|
+
*
|
|
38
|
+
* Accepts any `IConstruct`, so `Stack`, `DeploymentStack`, or custom
|
|
39
|
+
* subclasses all work.
|
|
40
|
+
*
|
|
41
|
+
* @param stacks - A partial map from component key to scope.
|
|
42
|
+
* @returns A {@link Lifecycle} with stack routing applied.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* compose({ handler, api }, { handler: [], api: ["handler"] })
|
|
47
|
+
* .withStacks({ handler: serviceStack, api: apiStack })
|
|
48
|
+
* .build(app, "MySystem");
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
withStacks(stacks: {
|
|
52
|
+
[K in keyof Components]?: IConstruct;
|
|
53
|
+
}): Lifecycle<BuildResult<Components>>;
|
|
54
|
+
/**
|
|
55
|
+
* Returns a new {@link Lifecycle} that uses a {@link StackStrategy} to
|
|
56
|
+
* determine each component's scope during build.
|
|
57
|
+
*
|
|
58
|
+
* @param strategy - The strategy that resolves scopes for components.
|
|
59
|
+
* @returns A {@link Lifecycle} with strategy-based stack routing applied.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* compose({ handler, api, table }, { ... })
|
|
64
|
+
* .withStackStrategy(groupedStacks(
|
|
65
|
+
* key => key === "table" ? "persistence" : "service",
|
|
66
|
+
* (app, id) => new Stack(app, id),
|
|
67
|
+
* ))
|
|
68
|
+
* .build(app, "MySystem");
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
withStackStrategy(strategy: StackStrategy): Lifecycle<BuildResult<Components>>;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Composes a set of {@link Lifecycle} components into a single system that
|
|
75
|
+
* manages their build order and dependency resolution.
|
|
76
|
+
*
|
|
77
|
+
* A directed acyclic graph is built eagerly from the declared dependencies.
|
|
78
|
+
* Cyclic dependencies are detected at composition time and throw immediately.
|
|
79
|
+
* When `build` is called, components are built in topological order, each
|
|
80
|
+
* receiving the build outputs of its dependencies as its context.
|
|
81
|
+
*
|
|
82
|
+
* The returned {@link ComposedSystem} is a {@link Lifecycle}, so it can be
|
|
83
|
+
* nested as a component in a larger `compose` call.
|
|
84
|
+
*
|
|
85
|
+
* @param components - A record of named {@link Lifecycle} components.
|
|
86
|
+
* @param dependencies - For each component, the list of other component keys it depends on.
|
|
87
|
+
* @returns A {@link ComposedSystem} whose build output is the combined {@link BuildResult} of all components.
|
|
88
|
+
*/
|
|
89
|
+
export declare function compose<Components extends Record<string, Lifecycle>>(components: Components, dependencies: {
|
|
90
|
+
[Property in keyof Components]: Dependency<Components>;
|
|
91
|
+
}): ComposedSystem<Components>;
|
|
92
|
+
export {};
|
|
93
|
+
//# sourceMappingURL=compose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;GAMG;AACH,KAAK,WAAW,CAAC,CAAC,SAAS;KAAG,QAAQ,IAAI,MAAM,CAAC,GAAG,SAAS;CAAE,IAAI;KAChE,QAAQ,IAAI,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC;CACxD,CAAC;AAEF;;;;;;GAMG;AACH,KAAK,UAAU,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,EAAE,CAAC;AA+BrF;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAE,SAAQ,SAAS,CAC7F,WAAW,CAAC,UAAU,CAAC,CACxB;IACC;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,MAAM,EAAE;SAAG,CAAC,IAAI,MAAM,UAAU,CAAC,CAAC,EAAE,UAAU;KAAE,GAAG,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjG;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC;CAChF;AAyDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,UAAU,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAClE,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE;KAAG,QAAQ,IAAI,MAAM,UAAU,GAAG,UAAU,CAAC,UAAU,CAAC;CAAE,GACvE,cAAc,CAAC,UAAU,CAAC,CAE5B"}
|
package/dist/compose.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { alg, json } from "@dagrejs/graphlib";
|
|
2
|
+
import { CyclicDependencyError } from "./cyclic-dependency-error.js";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a directed acyclic graph from component dependency declarations.
|
|
5
|
+
* The graph is described declaratively as nodes and edges, then constructed
|
|
6
|
+
* via {@link json.read}. Nodes are component keys, edges point from a
|
|
7
|
+
* dependency to its dependent. Throws if the graph contains a cycle.
|
|
8
|
+
*/
|
|
9
|
+
function buildDependencyGraph(components, dependencies) {
|
|
10
|
+
const nodes = Object.keys(components).map((v) => ({ v }));
|
|
11
|
+
const edges = Object.entries(dependencies).flatMap(([key, deps]) => deps.map((dep) => ({ v: dep, w: key })));
|
|
12
|
+
const graph = json.read({
|
|
13
|
+
options: { directed: true },
|
|
14
|
+
nodes,
|
|
15
|
+
edges,
|
|
16
|
+
});
|
|
17
|
+
if (!alg.isAcyclic(graph)) {
|
|
18
|
+
throw new CyclicDependencyError(alg.findCycles(graph));
|
|
19
|
+
}
|
|
20
|
+
return graph;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A composed system of {@link Lifecycle} components. Holds the dependency graph
|
|
24
|
+
* built at composition time and traverses it in topological order during build.
|
|
25
|
+
*/
|
|
26
|
+
class ComposedLifecycle {
|
|
27
|
+
components;
|
|
28
|
+
dependencies;
|
|
29
|
+
graph;
|
|
30
|
+
constructor(components, dependencies) {
|
|
31
|
+
this.components = components;
|
|
32
|
+
this.dependencies = dependencies;
|
|
33
|
+
this.graph = buildDependencyGraph(components, dependencies);
|
|
34
|
+
}
|
|
35
|
+
withStacks(stacks) {
|
|
36
|
+
return {
|
|
37
|
+
build: (scope, id) => this.buildWith(scope, id, stacks),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
withStackStrategy(strategy) {
|
|
41
|
+
return {
|
|
42
|
+
build: (scope, id) => {
|
|
43
|
+
const stacks = Object.fromEntries(Object.keys(this.components).map((key) => [key, strategy.resolve(scope, id, key)]));
|
|
44
|
+
return this.buildWith(scope, id, stacks);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
build(scope, id) {
|
|
49
|
+
return this.buildWith(scope, id);
|
|
50
|
+
}
|
|
51
|
+
buildWith(scope, id, stacks) {
|
|
52
|
+
const results = {};
|
|
53
|
+
for (const key of alg.topsort(this.graph)) {
|
|
54
|
+
const componentScope = stacks?.[key] ?? scope;
|
|
55
|
+
const deps = (this.dependencies[key] ?? []);
|
|
56
|
+
const context = Object.fromEntries(deps.map((dep) => [dep, results[dep]]));
|
|
57
|
+
results[key] = this.components[key].build(componentScope, `${id}/${key}`, context);
|
|
58
|
+
}
|
|
59
|
+
return results;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Composes a set of {@link Lifecycle} components into a single system that
|
|
64
|
+
* manages their build order and dependency resolution.
|
|
65
|
+
*
|
|
66
|
+
* A directed acyclic graph is built eagerly from the declared dependencies.
|
|
67
|
+
* Cyclic dependencies are detected at composition time and throw immediately.
|
|
68
|
+
* When `build` is called, components are built in topological order, each
|
|
69
|
+
* receiving the build outputs of its dependencies as its context.
|
|
70
|
+
*
|
|
71
|
+
* The returned {@link ComposedSystem} is a {@link Lifecycle}, so it can be
|
|
72
|
+
* nested as a component in a larger `compose` call.
|
|
73
|
+
*
|
|
74
|
+
* @param components - A record of named {@link Lifecycle} components.
|
|
75
|
+
* @param dependencies - For each component, the list of other component keys it depends on.
|
|
76
|
+
* @returns A {@link ComposedSystem} whose build output is the combined {@link BuildResult} of all components.
|
|
77
|
+
*/
|
|
78
|
+
export function compose(components, dependencies) {
|
|
79
|
+
return new ComposedLifecycle(components, dependencies);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,GAAG,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAwBrE;;;;;GAKG;AACH,SAAS,oBAAoB,CAC3B,UAAsB,EACtB,YAAwE;IAExE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAE1D,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,YAAwC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAC7F,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CACxC,CAAC;IAEF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC3B,KAAK;QACL,KAAK;KACN,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAqDD;;;GAGG;AACH,MAAM,iBAAiB;IAMF;IACA;IAJF,KAAK,CAAQ;IAE9B,YACmB,UAAsB,EACtB,YAAwE;QADxE,eAAU,GAAV,UAAU,CAAY;QACtB,iBAAY,GAAZ,YAAY,CAA4D;QAEzF,IAAI,CAAC,KAAK,GAAG,oBAAoB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC9D,CAAC;IAED,UAAU,CAAC,MAAgD;QACzD,OAAO;YACL,KAAK,EAAE,CAAC,KAAiB,EAAE,EAAU,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC;SAC5E,CAAC;IACJ,CAAC;IAED,iBAAiB,CAAC,QAAuB;QACvC,OAAO;YACL,KAAK,EAAE,CAAC,KAAiB,EAAE,EAAU,EAAE,EAAE;gBACvC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CACvC,CAAC;gBAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;YAC3C,CAAC;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAiB,EAAE,EAAU;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACnC,CAAC;IAEO,SAAS,CACf,KAAiB,EACjB,EAAU,EACV,MAAiD;QAEjD,MAAM,OAAO,GAA2B,EAAE,CAAC;QAE3C,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;YAC9C,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,CAAa,CAAC;YACxD,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3E,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QACrF,CAAC;QAED,OAAO,OAAkC,CAAC;IAC5C,CAAC;CACF;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,OAAO,CACrB,UAAsB,EACtB,YAAwE;IAExE,OAAO,IAAI,iBAAiB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when {@link compose} detects a cycle in the component dependency graph.
|
|
3
|
+
* Carries the detected cycles so callers can inspect or report them programmatically.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CyclicDependencyError extends Error {
|
|
6
|
+
readonly cycles: string[][];
|
|
7
|
+
/**
|
|
8
|
+
* @param cycles - Each element is an array of component keys forming a cycle.
|
|
9
|
+
*/
|
|
10
|
+
constructor(cycles: string[][]);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=cyclic-dependency-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cyclic-dependency-error.d.ts","sourceRoot":"","sources":["../src/cyclic-dependency-error.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;aAIlB,MAAM,EAAE,MAAM,EAAE,EAAE;IAH9C;;OAEG;gBACyB,MAAM,EAAE,MAAM,EAAE,EAAE;CAI/C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown when {@link compose} detects a cycle in the component dependency graph.
|
|
3
|
+
* Carries the detected cycles so callers can inspect or report them programmatically.
|
|
4
|
+
*/
|
|
5
|
+
export class CyclicDependencyError extends Error {
|
|
6
|
+
cycles;
|
|
7
|
+
/**
|
|
8
|
+
* @param cycles - Each element is an array of component keys forming a cycle.
|
|
9
|
+
*/
|
|
10
|
+
constructor(cycles) {
|
|
11
|
+
super(`Cyclic dependencies detected: ${cycles.map((c) => c.join(" -> ")).join("; ")}`);
|
|
12
|
+
this.cycles = cycles;
|
|
13
|
+
this.name = "CyclicDependencyError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=cyclic-dependency-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cyclic-dependency-error.js","sourceRoot":"","sources":["../src/cyclic-dependency-error.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAIlB;IAH5B;;OAEG;IACH,YAA4B,MAAkB;QAC5C,KAAK,CAAC,iCAAiC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAD7D,WAAM,GAAN,MAAM,CAAY;QAE5C,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Builder, type IBuilder } from "./builder.js";
|
|
2
|
+
export { compose, type ComposedSystem } from "./compose.js";
|
|
3
|
+
export { CyclicDependencyError } from "./cyclic-dependency-error.js";
|
|
4
|
+
export { type Lifecycle } from "./lifecycle.js";
|
|
5
|
+
export { Ref, ref, resolve, isRef, type Resolvable } from "./ref.js";
|
|
6
|
+
export { type StackStrategy, type ScopeFactory, singleStack, groupedStacks, } from "./stack-strategy.js";
|
|
7
|
+
//# 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,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,WAAW,EACX,aAAa,GACd,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Builder } from "./builder.js";
|
|
2
|
+
export { compose } from "./compose.js";
|
|
3
|
+
export { CyclicDependencyError } from "./cyclic-dependency-error.js";
|
|
4
|
+
export { Ref, ref, resolve, isRef } from "./ref.js";
|
|
5
|
+
export { singleStack, groupedStacks, } from "./stack-strategy.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAiB,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,OAAO,EAAuB,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAmB,MAAM,UAAU,CAAC;AACrE,OAAO,EAGL,WAAW,EACX,aAAa,GACd,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type IConstruct } from "constructs";
|
|
2
|
+
/**
|
|
3
|
+
* Base type for the dependency context passed to a component's {@link Lifecycle.build} method.
|
|
4
|
+
* A record of named dependencies, each being a record of their build outputs.
|
|
5
|
+
*/
|
|
6
|
+
type LifecycleComponentBase = Record<string, object>;
|
|
7
|
+
/**
|
|
8
|
+
* The core interface for all ComposureCDK components. A `Lifecycle` represents
|
|
9
|
+
* a unit of infrastructure that can be built within a CDK construct tree.
|
|
10
|
+
*
|
|
11
|
+
* Components implement this interface to define what resources they create
|
|
12
|
+
* and what dependencies they require. The {@link compose} function assembles
|
|
13
|
+
* components into a system, resolving dependencies and invoking `build` in
|
|
14
|
+
* the correct order.
|
|
15
|
+
*
|
|
16
|
+
* @typeParam T - The record of resources and values this component produces when built.
|
|
17
|
+
* @typeParam Context - The resolved dependencies this component requires, keyed by component name.
|
|
18
|
+
*/
|
|
19
|
+
export interface Lifecycle<T extends object = object, Context extends LifecycleComponentBase = LifecycleComponentBase> {
|
|
20
|
+
build(scope: IConstruct, id: string, context?: Context): T;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,KAAK,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,SAAS,CACxB,CAAC,SAAS,MAAM,GAAG,MAAM,EACzB,OAAO,SAAS,sBAAsB,GAAG,sBAAsB;IAE/D,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC;CAC5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":""}
|
package/dist/ref.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lazy reference to a value produced by another component at build time.
|
|
3
|
+
*
|
|
4
|
+
* `Ref` enables declarative cross-component wiring: a builder can capture a
|
|
5
|
+
* reference to a dependency's output at configuration time, and the value is
|
|
6
|
+
* resolved when the system is built. This keeps all configuration in one
|
|
7
|
+
* place — no split between eager props and deferred hooks.
|
|
8
|
+
*
|
|
9
|
+
* Create a `Ref` with the {@link ref} factory, then optionally narrow it
|
|
10
|
+
* with {@link Ref.get | .get()} or transform it with {@link Ref.map | .map()}.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The type of the value this reference resolves to.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Reference a component's full build output
|
|
17
|
+
* ref<FunctionBuilderResult>("handler")
|
|
18
|
+
*
|
|
19
|
+
* // Narrow to a specific property
|
|
20
|
+
* ref<FunctionBuilderResult>("handler").get("function")
|
|
21
|
+
*
|
|
22
|
+
* // Transform the referenced value
|
|
23
|
+
* ref<FunctionBuilderResult>("handler")
|
|
24
|
+
* .get("function")
|
|
25
|
+
* .map(fn => new LambdaIntegration(fn))
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class Ref<T> {
|
|
29
|
+
private readonly _resolver;
|
|
30
|
+
private constructor();
|
|
31
|
+
/**
|
|
32
|
+
* Creates a `Ref` that resolves to a component's full build output.
|
|
33
|
+
*
|
|
34
|
+
* @param component - The key of the component in the composed system.
|
|
35
|
+
* @returns A `Ref` to the component's build result.
|
|
36
|
+
*/
|
|
37
|
+
static to<T extends object>(component: string): Ref<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Narrows this reference to a specific property of the resolved value.
|
|
40
|
+
*
|
|
41
|
+
* @param key - The property key to select.
|
|
42
|
+
* @returns A new `Ref` to the selected property.
|
|
43
|
+
*/
|
|
44
|
+
get<K extends keyof T>(key: K): Ref<T[K]>;
|
|
45
|
+
/**
|
|
46
|
+
* Transforms the resolved value using the provided function.
|
|
47
|
+
*
|
|
48
|
+
* This is the primary way to adapt a dependency's output into the shape
|
|
49
|
+
* a consumer needs — for example, wrapping a Lambda function in a
|
|
50
|
+
* `LambdaIntegration`.
|
|
51
|
+
*
|
|
52
|
+
* @param fn - A function that transforms the resolved value.
|
|
53
|
+
* @returns A new `Ref` whose resolved value is the result of `fn`.
|
|
54
|
+
*/
|
|
55
|
+
map<U>(fn: (value: T) => U): Ref<U>;
|
|
56
|
+
/**
|
|
57
|
+
* Resolves this reference against a build context.
|
|
58
|
+
*
|
|
59
|
+
* Called internally during the build phase. Not typically called by users.
|
|
60
|
+
*
|
|
61
|
+
* @param context - The resolved dependency outputs, keyed by component name.
|
|
62
|
+
* @returns The resolved value.
|
|
63
|
+
*/
|
|
64
|
+
resolve(context: Record<string, object>): T;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Creates a {@link Ref} to a component's build output within a composed system.
|
|
68
|
+
*
|
|
69
|
+
* Called with just a component key, it returns a `Ref` to the full build result
|
|
70
|
+
* that can be further narrowed with {@link Ref.get | .get()} or
|
|
71
|
+
* {@link Ref.map | .map()}.
|
|
72
|
+
*
|
|
73
|
+
* Called with a transform function, it returns a `Ref` whose resolved value is
|
|
74
|
+
* the result of applying the transform to the component's build output. This is
|
|
75
|
+
* a shorthand for `ref<T>(component).map(transform)`.
|
|
76
|
+
*
|
|
77
|
+
* @param component - The key of the component in the composed system.
|
|
78
|
+
* @param transform - Optional function that transforms the component's build output.
|
|
79
|
+
* @returns A `Ref` to the component's build result, optionally transformed.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* // Without transform — chain .get() / .map() as needed
|
|
84
|
+
* ref<FunctionBuilderResult>("handler")
|
|
85
|
+
* .get("function")
|
|
86
|
+
* .map(fn => new LambdaIntegration(fn))
|
|
87
|
+
*
|
|
88
|
+
* // With transform — concise single-call form
|
|
89
|
+
* ref<FunctionBuilderResult>("handler", r => new LambdaIntegration(r.function))
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export declare function ref<T extends object>(component: string): Ref<T>;
|
|
93
|
+
export declare function ref<T extends object, U>(component: string, transform: (value: T) => U): Ref<U>;
|
|
94
|
+
/**
|
|
95
|
+
* A value that is either concrete or a lazy {@link Ref} resolved at build time.
|
|
96
|
+
*
|
|
97
|
+
* Builders accept `Resolvable<T>` wherever they would normally accept `T`,
|
|
98
|
+
* making refs and concrete values interchangeable at the call site.
|
|
99
|
+
*/
|
|
100
|
+
export type Resolvable<T> = T | Ref<T>;
|
|
101
|
+
/**
|
|
102
|
+
* Type guard that checks whether a value is a {@link Ref}.
|
|
103
|
+
*/
|
|
104
|
+
export declare function isRef<T>(value: Resolvable<T>): value is Ref<T>;
|
|
105
|
+
/**
|
|
106
|
+
* Resolves a {@link Resolvable} value. If it is a {@link Ref}, resolves it
|
|
107
|
+
* against the provided context. Otherwise returns the value as-is.
|
|
108
|
+
*
|
|
109
|
+
* @param value - A concrete value or a `Ref`.
|
|
110
|
+
* @param context - The resolved dependency outputs, keyed by component name.
|
|
111
|
+
* @returns The concrete value.
|
|
112
|
+
*/
|
|
113
|
+
export declare function resolve<T>(value: Resolvable<T>, context: Record<string, object>): T;
|
|
114
|
+
//# sourceMappingURL=ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref.d.ts","sourceRoot":"","sources":["../src/ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,GAAG,CAAC,CAAC;IACI,OAAO,CAAC,QAAQ,CAAC,SAAS;IAA9C,OAAO;IAEP;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;IAYtD;;;;;OAKG;IACH,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAIzC;;;;;;;;;OASG;IACH,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAInC;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC;CAG5C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAEjE,wBAAgB,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAShG;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAEvC;;GAEG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAEnF"}
|
package/dist/ref.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lazy reference to a value produced by another component at build time.
|
|
3
|
+
*
|
|
4
|
+
* `Ref` enables declarative cross-component wiring: a builder can capture a
|
|
5
|
+
* reference to a dependency's output at configuration time, and the value is
|
|
6
|
+
* resolved when the system is built. This keeps all configuration in one
|
|
7
|
+
* place — no split between eager props and deferred hooks.
|
|
8
|
+
*
|
|
9
|
+
* Create a `Ref` with the {@link ref} factory, then optionally narrow it
|
|
10
|
+
* with {@link Ref.get | .get()} or transform it with {@link Ref.map | .map()}.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam T - The type of the value this reference resolves to.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Reference a component's full build output
|
|
17
|
+
* ref<FunctionBuilderResult>("handler")
|
|
18
|
+
*
|
|
19
|
+
* // Narrow to a specific property
|
|
20
|
+
* ref<FunctionBuilderResult>("handler").get("function")
|
|
21
|
+
*
|
|
22
|
+
* // Transform the referenced value
|
|
23
|
+
* ref<FunctionBuilderResult>("handler")
|
|
24
|
+
* .get("function")
|
|
25
|
+
* .map(fn => new LambdaIntegration(fn))
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class Ref {
|
|
29
|
+
_resolver;
|
|
30
|
+
constructor(_resolver) {
|
|
31
|
+
this._resolver = _resolver;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a `Ref` that resolves to a component's full build output.
|
|
35
|
+
*
|
|
36
|
+
* @param component - The key of the component in the composed system.
|
|
37
|
+
* @returns A `Ref` to the component's build result.
|
|
38
|
+
*/
|
|
39
|
+
static to(component) {
|
|
40
|
+
return new Ref((context) => {
|
|
41
|
+
if (!(component in context)) {
|
|
42
|
+
throw new Error(`Ref to "${component}" cannot be resolved: component not found in context. ` +
|
|
43
|
+
`Ensure "${component}" is declared as a dependency.`);
|
|
44
|
+
}
|
|
45
|
+
return context[component];
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Narrows this reference to a specific property of the resolved value.
|
|
50
|
+
*
|
|
51
|
+
* @param key - The property key to select.
|
|
52
|
+
* @returns A new `Ref` to the selected property.
|
|
53
|
+
*/
|
|
54
|
+
get(key) {
|
|
55
|
+
return new Ref((context) => this._resolver(context)[key]);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Transforms the resolved value using the provided function.
|
|
59
|
+
*
|
|
60
|
+
* This is the primary way to adapt a dependency's output into the shape
|
|
61
|
+
* a consumer needs — for example, wrapping a Lambda function in a
|
|
62
|
+
* `LambdaIntegration`.
|
|
63
|
+
*
|
|
64
|
+
* @param fn - A function that transforms the resolved value.
|
|
65
|
+
* @returns A new `Ref` whose resolved value is the result of `fn`.
|
|
66
|
+
*/
|
|
67
|
+
map(fn) {
|
|
68
|
+
return new Ref((context) => fn(this._resolver(context)));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Resolves this reference against a build context.
|
|
72
|
+
*
|
|
73
|
+
* Called internally during the build phase. Not typically called by users.
|
|
74
|
+
*
|
|
75
|
+
* @param context - The resolved dependency outputs, keyed by component name.
|
|
76
|
+
* @returns The resolved value.
|
|
77
|
+
*/
|
|
78
|
+
resolve(context) {
|
|
79
|
+
return this._resolver(context);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function ref(component, transform) {
|
|
83
|
+
const base = Ref.to(component);
|
|
84
|
+
return transform ? base.map(transform) : base;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Type guard that checks whether a value is a {@link Ref}.
|
|
88
|
+
*/
|
|
89
|
+
export function isRef(value) {
|
|
90
|
+
return value instanceof Ref;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolves a {@link Resolvable} value. If it is a {@link Ref}, resolves it
|
|
94
|
+
* against the provided context. Otherwise returns the value as-is.
|
|
95
|
+
*
|
|
96
|
+
* @param value - A concrete value or a `Ref`.
|
|
97
|
+
* @param context - The resolved dependency outputs, keyed by component name.
|
|
98
|
+
* @returns The concrete value.
|
|
99
|
+
*/
|
|
100
|
+
export function resolve(value, context) {
|
|
101
|
+
return isRef(value) ? value.resolve(context) : value;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=ref.js.map
|
package/dist/ref.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref.js","sourceRoot":"","sources":["../src/ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,OAAO,GAAG;IACuB;IAArC,YAAqC,SAAiD;QAAjD,cAAS,GAAT,SAAS,CAAwC;IAAG,CAAC;IAE1F;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAmB,SAAiB;QAC3C,OAAO,IAAI,GAAG,CAAI,CAAC,OAAO,EAAE,EAAE;YAC5B,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CACb,WAAW,SAAS,wDAAwD;oBAC1E,WAAW,SAAS,gCAAgC,CACvD,CAAC;YACJ,CAAC;YACD,OAAO,OAAO,CAAC,SAAS,CAAM,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAoB,GAAM;QAC3B,OAAO,IAAI,GAAG,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClE,CAAC;IAED;;;;;;;;;OASG;IACH,GAAG,CAAI,EAAmB;QACxB,OAAO,IAAI,GAAG,CAAI,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,OAA+B;QACrC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF;AA+BD,MAAM,UAAU,GAAG,CACjB,SAAiB,EACjB,SAA2B;IAE3B,MAAM,IAAI,GAAG,GAAG,CAAC,EAAE,CAAI,SAAS,CAAC,CAAC;IAClC,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAUD;;GAEG;AACH,MAAM,UAAU,KAAK,CAAI,KAAoB;IAC3C,OAAO,KAAK,YAAY,GAAG,CAAC;AAC9B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAI,KAAoB,EAAE,OAA+B;IAC9E,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type IConstruct } from "constructs";
|
|
2
|
+
/**
|
|
3
|
+
* A factory function that creates scopes (typically Stacks) for components.
|
|
4
|
+
* Accepts any scope constructor — `Stack`, `DeploymentStack`, or custom
|
|
5
|
+
* subclasses.
|
|
6
|
+
*
|
|
7
|
+
* @param scope - The parent scope (typically an `App`).
|
|
8
|
+
* @param id - A unique identifier for the new scope.
|
|
9
|
+
* @returns A new scope to attach components to.
|
|
10
|
+
*/
|
|
11
|
+
export type ScopeFactory = (scope: IConstruct, id: string) => IConstruct;
|
|
12
|
+
/**
|
|
13
|
+
* Determines which scope a component should be built in.
|
|
14
|
+
*
|
|
15
|
+
* A `StackStrategy` is passed the parent scope, a system identifier,
|
|
16
|
+
* and each component's key. It returns the scope that component should
|
|
17
|
+
* use. Strategies can create scopes lazily, reuse them across components,
|
|
18
|
+
* or delegate to a {@link ScopeFactory} for custom scope types.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* // Every component in one auto-created stack
|
|
23
|
+
* compose({ handler, api }, { handler: [], api: ["handler"] })
|
|
24
|
+
* .withStackStrategy(singleStack(myFactory))
|
|
25
|
+
* .build(app, "MySystem");
|
|
26
|
+
*
|
|
27
|
+
* // Components grouped by a key function
|
|
28
|
+
* compose({ handler, api, table }, { ... })
|
|
29
|
+
* .withStackStrategy(groupedStacks(key => key === "table" ? "persistence" : "service", myFactory))
|
|
30
|
+
* .build(app, "MySystem");
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export interface StackStrategy {
|
|
34
|
+
/**
|
|
35
|
+
* Returns the scope a component should be built in.
|
|
36
|
+
*
|
|
37
|
+
* @param scope - The parent scope passed to `build`.
|
|
38
|
+
* @param systemId - The system identifier passed to `build`.
|
|
39
|
+
* @param componentKey - The key of the component in the composed system.
|
|
40
|
+
* @returns The scope to use for this component.
|
|
41
|
+
*/
|
|
42
|
+
resolve(scope: IConstruct, systemId: string, componentKey: string): IConstruct;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates a strategy that places all components in a single auto-created scope.
|
|
46
|
+
*
|
|
47
|
+
* The scope is created lazily on the first call to `resolve` and reused for
|
|
48
|
+
* all subsequent components.
|
|
49
|
+
*
|
|
50
|
+
* @param factory - Factory for creating the scope (e.g. a Stack).
|
|
51
|
+
* @returns A {@link StackStrategy} that groups all components into one scope.
|
|
52
|
+
*/
|
|
53
|
+
export declare function singleStack(factory: ScopeFactory): StackStrategy;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a strategy that groups components into named scopes determined by
|
|
56
|
+
* a classifier function.
|
|
57
|
+
*
|
|
58
|
+
* Components that return the same group key share a scope. Scopes are created
|
|
59
|
+
* lazily as new group keys are encountered.
|
|
60
|
+
*
|
|
61
|
+
* @param classify - A function that maps a component key to a group name.
|
|
62
|
+
* @param factory - Factory for creating scopes (e.g. Stacks). The factory
|
|
63
|
+
* receives `${systemId}-${group}` as the id.
|
|
64
|
+
* @returns A {@link StackStrategy} that groups components by classifier output.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* groupedStacks(
|
|
69
|
+
* key => key === "table" ? "persistence" : "service",
|
|
70
|
+
* (app, id) => new Stack(app, id),
|
|
71
|
+
* )
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function groupedStacks(classify: (componentKey: string) => string, factory: ScopeFactory): StackStrategy;
|
|
75
|
+
//# sourceMappingURL=stack-strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-strategy.d.ts","sourceRoot":"","sources":["../src/stack-strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,KAAK,UAAU,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC;CAChF;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,aAAa,CAUhE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,EAC1C,OAAO,EAAE,YAAY,GACpB,aAAa,CAaf"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a strategy that places all components in a single auto-created scope.
|
|
3
|
+
*
|
|
4
|
+
* The scope is created lazily on the first call to `resolve` and reused for
|
|
5
|
+
* all subsequent components.
|
|
6
|
+
*
|
|
7
|
+
* @param factory - Factory for creating the scope (e.g. a Stack).
|
|
8
|
+
* @returns A {@link StackStrategy} that groups all components into one scope.
|
|
9
|
+
*/
|
|
10
|
+
export function singleStack(factory) {
|
|
11
|
+
return {
|
|
12
|
+
resolve: (() => {
|
|
13
|
+
let stack;
|
|
14
|
+
return (scope, systemId) => {
|
|
15
|
+
stack ??= factory(scope, systemId);
|
|
16
|
+
return stack;
|
|
17
|
+
};
|
|
18
|
+
})(),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Creates a strategy that groups components into named scopes determined by
|
|
23
|
+
* a classifier function.
|
|
24
|
+
*
|
|
25
|
+
* Components that return the same group key share a scope. Scopes are created
|
|
26
|
+
* lazily as new group keys are encountered.
|
|
27
|
+
*
|
|
28
|
+
* @param classify - A function that maps a component key to a group name.
|
|
29
|
+
* @param factory - Factory for creating scopes (e.g. Stacks). The factory
|
|
30
|
+
* receives `${systemId}-${group}` as the id.
|
|
31
|
+
* @returns A {@link StackStrategy} that groups components by classifier output.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* groupedStacks(
|
|
36
|
+
* key => key === "table" ? "persistence" : "service",
|
|
37
|
+
* (app, id) => new Stack(app, id),
|
|
38
|
+
* )
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function groupedStacks(classify, factory) {
|
|
42
|
+
const groups = new Map();
|
|
43
|
+
return {
|
|
44
|
+
resolve(scope, systemId, componentKey) {
|
|
45
|
+
const group = classify(componentKey);
|
|
46
|
+
let groupScope = groups.get(group);
|
|
47
|
+
if (!groupScope) {
|
|
48
|
+
groupScope = factory(scope, `${systemId}-${group}`);
|
|
49
|
+
groups.set(group, groupScope);
|
|
50
|
+
}
|
|
51
|
+
return groupScope;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=stack-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack-strategy.js","sourceRoot":"","sources":["../src/stack-strategy.ts"],"names":[],"mappings":"AA8CA;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,OAAqB;IAC/C,OAAO;QACL,OAAO,EAAE,CAAC,GAAG,EAAE;YACb,IAAI,KAA6B,CAAC;YAClC,OAAO,CAAC,KAAiB,EAAE,QAAgB,EAAE,EAAE;gBAC7C,KAAK,KAAK,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACnC,OAAO,KAAK,CAAC;YACf,CAAC,CAAC;QACJ,CAAC,CAAC,EAAE;KACL,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,aAAa,CAC3B,QAA0C,EAC1C,OAAqB;IAErB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC7C,OAAO;QACL,OAAO,CAAC,KAAiB,EAAE,QAAgB,EAAE,YAAoB;YAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;YACrC,IAAI,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnC,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,QAAQ,IAAI,KAAK,EAAE,CAAC,CAAC;gBACpD,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YAChC,CAAC;YACD,OAAO,UAAU,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@composurecdk/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Composable CDK component system — lifecycle, dependency resolution, and builder pattern",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"clean": "rm -rf dist",
|
|
20
|
+
"build": "tsc -p tsconfig.build.json",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest"
|
|
24
|
+
},
|
|
25
|
+
"lint-staged": {
|
|
26
|
+
"*.ts": [
|
|
27
|
+
"eslint --fix",
|
|
28
|
+
"prettier --write"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"keywords": [],
|
|
32
|
+
"author": "Jason Duffett (https://github.com/laazyj)",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"type": "module",
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"constructs": "^10.6.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^25.5.0",
|
|
43
|
+
"typescript": "^6.0.2",
|
|
44
|
+
"vitest": "^4.1.2"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@dagrejs/graphlib": "^4.0.1"
|
|
48
|
+
}
|
|
49
|
+
}
|