@spaceteams/warp 0.2.0 → 0.3.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/index.d.mts CHANGED
@@ -13,24 +13,27 @@ type ComponentRef<Ctx, ScopeContext, RunOptions, Out> = {
13
13
  readonly __runOptions?: RunOptions;
14
14
  readonly __out?: Out;
15
15
  };
16
- type ComponentFactory<Ctx, ScopeContext, RunOptions, Deps, Out> = (ctx: Run<Ctx & Deps, ScopeContext, RunOptions>) => Out;
16
+ type ComponentKind = "repo" | "service" | "usecase" | "client";
17
+ type ComponentMeta = {
18
+ name?: string;
19
+ kind?: ComponentKind;
20
+ tags?: string[];
21
+ };
22
+ type ComponentFactoryFn<Ctx, ScopeContext, RunOptions, Deps, Out> = (ctx: Run<Ctx & Deps, ScopeContext, RunOptions>) => Out;
23
+ type ComponentFactory<Ctx, ScopeContext, RunOptions, Deps, Out> = ComponentFactoryFn<Ctx, ScopeContext, RunOptions, Deps, Out> & {
24
+ meta?: ComponentMeta;
25
+ };
17
26
  type ComponentInput<Ctx, ScopeContext, RunOptions, Out> = ComponentRef<Ctx, ScopeContext, RunOptions, Out> | Out;
18
27
  type Component<Ctx, ScopeContext, RunOptions, Deps, Out> = ComponentRef<Ctx, ScopeContext, RunOptions, Out> & {
19
28
  factory: ComponentFactory<Ctx, ScopeContext, RunOptions, Deps, Out>;
20
29
  deps?: { [K in keyof Deps]: ComponentRef<Ctx, ScopeContext, RunOptions, Deps[K]> };
21
- name?: string;
30
+ meta?: ComponentMeta;
22
31
  };
23
32
  type ComponentDefinition<Ctx, ScopeContext, RunOptions, Deps, Out> = {
24
33
  factory: ComponentFactory<Ctx, ScopeContext, RunOptions, Deps, Out>;
25
34
  deps?: { [K in keyof Deps]: ComponentInput<Ctx, ScopeContext, RunOptions, Deps[K]> };
26
- name?: string;
35
+ meta?: ComponentMeta;
27
36
  };
28
- type InferComponentParams<T> = T extends Component<infer Ctx, infer ScopeContext, infer RunOptions, infer Deps, infer Out> ? [Ctx, ScopeContext, RunOptions, Deps, Out] : never;
29
- type InferComponentCtx<T> = InferComponentParams<T>[0];
30
- type InferComponentScopeContext<T> = InferComponentParams<T>[1];
31
- type InferComponentRunOptions<T> = InferComponentParams<T>[2];
32
- type InferComponentDeps<T> = InferComponentParams<T>[3];
33
- type InferComponentOut<T> = InferComponentParams<T>[4];
34
37
  declare function brandComponent<T extends object, Ctx, ScopeContext, RunOptions, Out>(obj: T): T & ComponentRef<Ctx, ScopeContext, RunOptions, Out>;
35
38
  declare function isComponent(value: unknown): value is Component<unknown, unknown, unknown, unknown, unknown>;
36
39
  //#endregion
@@ -39,12 +42,22 @@ type NoRunOptions = NonNullable<unknown>;
39
42
  type NoScopeContext = NonNullable<unknown>;
40
43
  type Middleware<AmbientContext, RunOptions = NoRunOptions, ScopeContext = NoScopeContext> = <T>(ctx: AmbientContext, options: Partial<RunOptions>, next: (ctx: AmbientContext & ScopeContext) => Promise<T> | T) => Promise<T> | T;
41
44
  //#endregion
42
- //#region src/runtime/explain.d.ts
45
+ //#region src/explain/index.d.ts
43
46
  type ExplainResult = {
44
47
  name: string | undefined;
48
+ kind?: string;
49
+ tags?: string[];
45
50
  deps?: Record<string, ExplainResult>;
46
51
  };
47
52
  //#endregion
53
+ //#region src/lazy.d.ts
54
+ type Lazy<T> = () => T;
55
+ declare const Lazy: {
56
+ cached<T>(factory: () => T): Lazy<T>;
57
+ and<S, T>(l: Lazy<S>, r: Lazy<T>): Lazy<S & T>;
58
+ map<S, T>(l: Lazy<S>, fn: (v: S) => T): Lazy<T>;
59
+ };
60
+ //#endregion
48
61
  //#region src/runtime/runtime.d.ts
49
62
  type SafeIntersect<A, B> = A extends undefined ? B : A & B;
50
63
  type OptionalArg<A> = A extends undefined ? [] : [A];
@@ -52,19 +65,18 @@ declare class Runtime<Ctx, ActualContext extends Ctx, ScopeContext, RunOptions,
52
65
  private readonly middleware;
53
66
  private readonly ctx;
54
67
  private readonly resolveFn;
55
- constructor(middleware: Middleware<Ctx, RunOptions, ScopeContext>, ctx: ActualContext);
68
+ constructor(middleware: Middleware<Ctx, RunOptions, ScopeContext>, ctx: Lazy<ActualContext>);
56
69
  provide<Extension>(ext: Extension): Runtime<Ctx, ActualContext & Extension, ScopeContext, RunOptions, Requirements>;
70
+ provideLazy<Extension>(ext: () => Extension): Runtime<Ctx, ActualContext & Extension, ScopeContext, RunOptions, Requirements>;
57
71
  require<Extension>(): Runtime<Ctx, ActualContext, ScopeContext, RunOptions, SafeIntersect<Requirements, Extension>>;
58
72
  resolve: <Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, ...requirements: OptionalArg<Requirements>) => Out | Promise<Out>;
59
- get component(): <Deps, F extends ComponentFactory<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, ReturnType<F>>>(factory: F, deps?: { [T in keyof Deps]: ComponentInput<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps[T]> } | undefined, opts?: {
60
- name?: string | undefined;
61
- } | undefined) => Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, ReturnType<F>>;
62
- get classComponent(): <Deps, Ctor extends new (deps: Run<SafeIntersect<Requirements, ActualContext> & Deps, ScopeContext, RunOptions>) => InstanceType<Ctor>>(ctor: Ctor, deps?: { [K in keyof Deps]: ComponentInput<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps[K]> } | undefined, opts?: {
63
- name?: string | undefined;
64
- } | undefined) => Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, InstanceType<Ctor>>;
65
- explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, format: "native"): ExplainResult;
66
- explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, format: "ascii"): string;
67
- explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, format: "mermaid"): string;
73
+ get component(): <Deps, F extends ComponentFactory<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, ReturnType<F>>>(factory: F, deps?: { [T in keyof Deps]: ComponentInput<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps[T]> } | undefined, meta?: ComponentMeta | undefined) => Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, ReturnType<F>>;
74
+ get classComponent(): <Deps, Ctor extends (new (deps: Run<SafeIntersect<Requirements, ActualContext> & Deps, ScopeContext, RunOptions>) => InstanceType<Ctor>) & {
75
+ meta?: ComponentMeta | undefined;
76
+ }>(ctor: Ctor, deps?: { [K in keyof Deps]: ComponentInput<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps[K]> } | undefined, meta?: ComponentMeta | undefined) => Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, InstanceType<Ctor>>;
77
+ explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, format: "native", showMeta?: boolean): ExplainResult;
78
+ explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, format: "ascii", showMeta?: boolean): string;
79
+ explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>, format: "mermaid", showMeta?: boolean): string;
68
80
  explain<Deps, Out>(component: Component<SafeIntersect<Requirements, ActualContext>, ScopeContext, RunOptions, Deps, Out>): ExplainResult;
69
81
  }
70
82
  //#endregion
@@ -74,10 +86,36 @@ declare class RuntimeBuilder<AmbientContext, ScopeContext = unknown, Options = u
74
86
  constructor(middlewares?: Middleware<AmbientContext, Options, ScopeContext>[]);
75
87
  use<A, S, H>(mw: Middleware<A, H, S>): RuntimeBuilder<AmbientContext & A, ScopeContext & S, Options & H>;
76
88
  provide<ActualCtx extends AmbientContext>(ctx: ActualCtx): Runtime<AmbientContext, ActualCtx, ScopeContext, Options, undefined>;
89
+ provideLazy<ActualCtx extends AmbientContext>(ctx: () => ActualCtx): Runtime<AmbientContext, ActualCtx, ScopeContext, Options, undefined>;
77
90
  private buildMiddleware;
78
91
  }
79
92
  //#endregion
80
93
  //#region src/runtime/index.d.ts
81
94
  declare function buildRuntime(): RuntimeBuilder<Record<string, unknown>, unknown>;
82
95
  //#endregion
83
- export { Component, ComponentDefinition, ComponentFactory, ComponentInput, ComponentRef, InferComponentCtx, InferComponentDeps, InferComponentOut, InferComponentParams, InferComponentRunOptions, InferComponentScopeContext, Middleware, NoDeps, NoRunOptions, NoScopeContext, Run, brandComponent, buildRuntime, isComponent };
96
+ //#region src/semantic/callable.d.ts
97
+ type Callable<Ctx, ScopeContext, Args extends unknown[], Result, RunOptions> = ComponentFactory<Ctx, ScopeContext, RunOptions, unknown, (...args: Args) => Promise<Result>>;
98
+ declare function callable<Ctx, Args extends unknown[], Result, RunOptions = NoRunOptions, ScopeContext = NoScopeContext>(options: RunOptions & ComponentMeta, fn: (app: Run<Ctx, ScopeContext, RunOptions>) => (...args: Args) => Promise<Result>): Callable<Ctx, ScopeContext, Args, Result, RunOptions>;
99
+ type InferCallable<T> = T extends Callable<infer _Ctx, infer _ScopeContext, infer Args, infer Result, infer _RunOptions> ? (...args: Args) => Promise<Result> : never;
100
+ //#endregion
101
+ //#region src/semantic/client.d.ts
102
+ type Client<Ctx, ScopeContext, Out, RunOptions> = ComponentFactory<Ctx, ScopeContext, RunOptions, unknown, Out>;
103
+ declare function client<Ctx, Out, RunOptions = NoRunOptions, ScopeContext = NoScopeContext>(options: Omit<ComponentMeta, "kind">, fn: (app: Run<Ctx, ScopeContext, RunOptions>) => Out): Client<Ctx, ScopeContext, Out, RunOptions>;
104
+ type InferClient<T> = T extends Client<infer _Ctx, infer _ScopeContext, infer Out, infer _RunOptions> ? Out : never;
105
+ //#endregion
106
+ //#region src/semantic/repo.d.ts
107
+ type Repo<Ctx, ScopeContext, Out, RunOptions> = ComponentFactory<Ctx, ScopeContext, RunOptions, unknown, Out>;
108
+ declare function repo<Ctx, Out, RunOptions = NoRunOptions, ScopeContext = NoScopeContext>(options: Omit<ComponentMeta, "kind">, fn: (app: Run<Ctx, ScopeContext, RunOptions>) => Out): Repo<Ctx, ScopeContext, Out, RunOptions>;
109
+ type InferRepo<T> = T extends Repo<infer _Ctx, infer _ScopeContext, infer Out, infer _RunOptions> ? Out : never;
110
+ //#endregion
111
+ //#region src/semantic/service.d.ts
112
+ type Service<Ctx, ScopeContext, Out, RunOptions> = ComponentFactory<Ctx, ScopeContext, RunOptions, unknown, Out>;
113
+ declare function service<Ctx, Out, RunOptions = NoRunOptions, ScopeContext = NoScopeContext>(options: Omit<ComponentMeta, "kind"> | undefined, fn: (app: Run<Ctx, ScopeContext, RunOptions>) => Out): Service<Ctx, ScopeContext, Out, RunOptions>;
114
+ type InferService<T> = T extends Service<infer _Ctx, infer _ScopeContext, infer Out, infer _RunOptions> ? Out : never;
115
+ //#endregion
116
+ //#region src/semantic/usecase.d.ts
117
+ type Usecase<Ctx, ScopeContext, Args extends unknown[], Result, RunOptions> = Callable<Ctx, ScopeContext, Args, Result, RunOptions>;
118
+ declare function usecase<Ctx, Args extends unknown[], Result, RunOptions = NoRunOptions, ScopeContext = NoScopeContext>(options: RunOptions & Omit<ComponentMeta, "kind">, fn: (app: Run<Ctx, ScopeContext, RunOptions>) => (...args: Args) => Promise<Result>): Usecase<Ctx, ScopeContext, Args, Result, RunOptions>;
119
+ type InferUsecase<T> = InferCallable<T>;
120
+ //#endregion
121
+ export { Callable, Client, Component, ComponentDefinition, ComponentFactory, ComponentFactoryFn, ComponentInput, ComponentKind, ComponentMeta, ComponentRef, InferCallable, InferClient, InferRepo, InferService, InferUsecase, Middleware, NoDeps, NoRunOptions, NoScopeContext, Repo, Run, Service, Usecase, brandComponent, buildRuntime, callable, client, isComponent, repo, service, usecase };
package/dist/index.mjs CHANGED
@@ -13,31 +13,115 @@ function isComponent(value) {
13
13
  return typeof value === "object" && value !== null && value[COMPONENT] === true;
14
14
  }
15
15
  //#endregion
16
+ //#region src/lazy.ts
17
+ const Lazy = {
18
+ cached(factory) {
19
+ let cached;
20
+ return () => {
21
+ if (cached === void 0) cached = factory();
22
+ return cached;
23
+ };
24
+ },
25
+ and(l, r) {
26
+ return () => ({
27
+ ...l(),
28
+ ...r()
29
+ });
30
+ },
31
+ map(l, fn) {
32
+ return () => fn(l());
33
+ }
34
+ };
35
+ //#endregion
16
36
  //#region src/component/class-component.ts
17
37
  function defineClassComponent() {
18
- return (ctor, deps, opts) => {
38
+ return (ctor, deps, meta) => {
19
39
  const factory = (ctx) => {
20
40
  return new ctor(ctx);
21
41
  };
22
42
  return brandComponent({
23
43
  factory,
24
44
  deps,
25
- name: opts?.name ?? ctor.name
45
+ meta: {
46
+ name: (meta?.name ?? ctor.meta?.name) || void 0,
47
+ tags: (meta?.tags ?? ctor.meta?.tags) || void 0,
48
+ kind: (meta?.kind ?? ctor.meta?.kind) || void 0
49
+ }
26
50
  });
27
51
  };
28
52
  }
29
53
  //#endregion
30
54
  //#region src/component/functional-component.ts
31
55
  function defineFunctionalComponent() {
32
- return (factory, deps, opts) => {
56
+ return (factory, deps, meta) => {
33
57
  return brandComponent({
34
58
  factory,
35
59
  deps,
36
- name: opts?.name
60
+ meta: {
61
+ name: (meta?.name ?? factory.meta?.name) || void 0,
62
+ tags: (meta?.tags ?? factory.meta?.tags) || void 0,
63
+ kind: (meta?.kind ?? factory.meta?.kind) || void 0
64
+ }
37
65
  });
38
66
  };
39
67
  }
40
68
  //#endregion
69
+ //#region src/explain/index.ts
70
+ const explain = (c) => {
71
+ const deps = {};
72
+ for (const [key, comp] of Object.entries(c.deps ?? {})) deps[key] = explain(comp);
73
+ return {
74
+ name: c.meta?.name,
75
+ kind: c.meta?.kind,
76
+ tags: c.meta?.tags,
77
+ deps
78
+ };
79
+ };
80
+ //#endregion
81
+ //#region src/explain/ascii.ts
82
+ const formatExplainLabel = (node, showMeta, edgeLabel) => {
83
+ let label = edgeLabel ?? node.name ?? "unnamed";
84
+ if (edgeLabel && showMeta && node.name) label += ` -> ${node.name}`;
85
+ if (showMeta && node.kind) label += ` [${node.kind}]`;
86
+ if (showMeta && node.tags?.length) label += ` {${node.tags.join(", ")}}`;
87
+ return label;
88
+ };
89
+ const toAsciiTree = (result, prefix = "", isLast = true, showMeta = false, edgeLabel) => {
90
+ const line = `${prefix}${isLast ? "└── " : "├── "}${formatExplainLabel(result, showMeta, edgeLabel)}`;
91
+ const deps = Object.entries(result.deps ?? {});
92
+ if (deps.length === 0) return line;
93
+ const childPrefix = prefix + (isLast ? " " : "│ ");
94
+ return [line, ...deps.map(([key, dep], index) => toAsciiTree(dep, childPrefix, index === deps.length - 1, showMeta, key))].join("\n");
95
+ };
96
+ //#endregion
97
+ //#region src/explain/mermaid.ts
98
+ const sanitizeMermaidId = (value) => value.replace(/[^a-zA-Z0-9_]/g, "_");
99
+ const escapeMermaidLabel = (value) => value.replace(/"/g, "\\\"");
100
+ const formatMermaidLabel = (node, showMeta, fallbackName) => {
101
+ let label = node.name ?? fallbackName;
102
+ if (showMeta) {
103
+ const metaParts = [];
104
+ if (node.kind) metaParts.push(node.kind);
105
+ if (node.tags?.length) metaParts.push(node.tags.join(", "));
106
+ if (metaParts.length > 0) label += `<br/>[${metaParts.join(" | ")}]`;
107
+ }
108
+ return escapeMermaidLabel(label);
109
+ };
110
+ const collectMermaidLines = (node, nodeId, showMeta, fallbackName) => {
111
+ const lines = [];
112
+ lines.push(` ${nodeId}["${formatMermaidLabel(node, showMeta, fallbackName)}"]`);
113
+ Object.entries(node.deps ?? {}).forEach(([key, dep], index) => {
114
+ const childId = sanitizeMermaidId(`${nodeId}__${key}__${dep.name ?? key ?? `node_${index}`}`);
115
+ lines.push(` ${nodeId} -->|${escapeMermaidLabel(key)}| ${childId}`);
116
+ lines.push(...collectMermaidLines(dep, childId, showMeta, key));
117
+ });
118
+ return lines;
119
+ };
120
+ const toMermaid = (result, showMeta = false) => {
121
+ const rootName = result.name ?? "root";
122
+ return ["graph TD", ...collectMermaidLines(result, sanitizeMermaidId(rootName), showMeta, rootName)].join("\n");
123
+ };
124
+ //#endregion
41
125
  //#region src/runtime/create-resolver.ts
42
126
  function createResolver(mw) {
43
127
  return (root, ctx) => {
@@ -99,49 +183,6 @@ function createResolver(mw) {
99
183
  };
100
184
  }
101
185
  //#endregion
102
- //#region src/runtime/explain.ts
103
- const explain = (c) => {
104
- const deps = {};
105
- for (const [key, comp] of Object.entries(c.deps ?? {})) deps[key] = explain(comp);
106
- return {
107
- name: c.name,
108
- deps
109
- };
110
- };
111
- const toAsciiTree = (result, prefix = "", isLast = true) => {
112
- const lines = [];
113
- const connector = isLast ? "└── " : "├── ";
114
- lines.push(prefix + connector + result.name);
115
- const deps = Object.entries(result.deps ?? {});
116
- const newPrefix = prefix + (isLast ? " " : "│ ");
117
- deps.forEach(([key, dep], index) => {
118
- const isLastDep = index === deps.length - 1;
119
- const connector = isLastDep ? "└── " : "├── ";
120
- lines.push(`${newPrefix}${connector}[${key}]`);
121
- const childLines = toAsciiTree(dep, newPrefix + (isLastDep ? " " : "│ "), true).split("\n").slice(1);
122
- lines.push(...childLines);
123
- });
124
- return lines.join("\n");
125
- };
126
- const toMermaid = (result, nodeId, isRoot = true) => {
127
- const lines = [];
128
- if (isRoot) {
129
- lines.push("graph TD");
130
- nodeId = result.name ?? "root";
131
- }
132
- const sanitizedId = nodeId.replace(/[^a-zA-Z0-9_]/g, "_");
133
- if (isRoot) lines.push(` ${sanitizedId}["${result.name}"]`);
134
- Object.entries(result.deps ?? {}).forEach(([key, dep]) => {
135
- const sanitizedDepId = (dep.name ? `${sanitizedId}_${dep.name}` : `${sanitizedId}_${key}`).replace(/[^a-zA-Z0-9_]/g, "_");
136
- const displayName = dep.name ?? key;
137
- lines.push(` ${sanitizedDepId}["${displayName}"]`);
138
- lines.push(` ${sanitizedId} -->|${key}| ${sanitizedDepId}`);
139
- const childLines = toMermaid(dep, sanitizedDepId, false).split("\n").slice(1);
140
- lines.push(...childLines);
141
- });
142
- return lines.join("\n");
143
- };
144
- //#endregion
145
186
  //#region src/runtime/runtime.ts
146
187
  var Runtime = class Runtime {
147
188
  resolveFn;
@@ -151,10 +192,10 @@ var Runtime = class Runtime {
151
192
  this.resolveFn = createResolver(middleware);
152
193
  }
153
194
  provide(ext) {
154
- return new Runtime(this.middleware, {
155
- ...this.ctx,
156
- ...ext
157
- });
195
+ return new Runtime(this.middleware, Lazy.and(this.ctx, () => ext));
196
+ }
197
+ provideLazy(ext) {
198
+ return new Runtime(this.middleware, Lazy.and(this.ctx, Lazy.cached(ext)));
158
199
  }
159
200
  require() {
160
201
  return new Runtime(this.middleware, this.ctx);
@@ -162,9 +203,9 @@ var Runtime = class Runtime {
162
203
  resolve = (component, ...requirements) => {
163
204
  const req = requirements[0];
164
205
  const ctx = req ? {
165
- ...this.ctx,
206
+ ...this.ctx(),
166
207
  ...req
167
- } : { ...this.ctx };
208
+ } : { ...this.ctx() };
168
209
  return this.resolveFn(component, ctx);
169
210
  };
170
211
  get component() {
@@ -173,11 +214,11 @@ var Runtime = class Runtime {
173
214
  get classComponent() {
174
215
  return defineClassComponent();
175
216
  }
176
- explain(component, format = "native") {
217
+ explain(component, format = "native", showMeta = false) {
177
218
  const result = explain(component);
178
219
  switch (format) {
179
- case "ascii": return toAsciiTree(result);
180
- case "mermaid": return toMermaid(result);
220
+ case "ascii": return toAsciiTree(result, "", true, showMeta);
221
+ case "mermaid": return toMermaid(result, showMeta);
181
222
  case "native": return result;
182
223
  }
183
224
  }
@@ -193,7 +234,10 @@ var RuntimeBuilder = class RuntimeBuilder {
193
234
  return new RuntimeBuilder([...this.middlewares, mw]);
194
235
  }
195
236
  provide(ctx) {
196
- return new Runtime(this.buildMiddleware(), ctx);
237
+ return new Runtime(this.buildMiddleware(), () => ctx);
238
+ }
239
+ provideLazy(ctx) {
240
+ return new Runtime(this.buildMiddleware(), Lazy.cached(ctx));
197
241
  }
198
242
  buildMiddleware() {
199
243
  const middlewares = this.middlewares;
@@ -216,4 +260,58 @@ function buildRuntime() {
216
260
  return new RuntimeBuilder();
217
261
  }
218
262
  //#endregion
219
- export { brandComponent, buildRuntime, isComponent };
263
+ //#region src/semantic/callable.ts
264
+ function callable(options, fn) {
265
+ const factory = (ctx) => (...args) => {
266
+ return ctx.run(options, (inner) => fn(inner)(...args));
267
+ };
268
+ Object.assign(factory, { meta: {
269
+ kind: options.kind,
270
+ name: options.name,
271
+ tags: options.tags
272
+ } });
273
+ return factory;
274
+ }
275
+ //#endregion
276
+ //#region src/semantic/client.ts
277
+ function client(options, fn) {
278
+ const factory = fn;
279
+ Object.assign(factory, { meta: {
280
+ kind: "client",
281
+ name: options.name,
282
+ tags: options.tags
283
+ } });
284
+ return factory;
285
+ }
286
+ //#endregion
287
+ //#region src/semantic/repo.ts
288
+ function repo(options, fn) {
289
+ const factory = fn;
290
+ Object.assign(factory, { meta: {
291
+ kind: "repo",
292
+ name: options.name,
293
+ tags: options.tags
294
+ } });
295
+ return factory;
296
+ }
297
+ //#endregion
298
+ //#region src/semantic/service.ts
299
+ function service(options = {}, fn) {
300
+ const factory = fn;
301
+ Object.assign(factory, { meta: {
302
+ kind: "service",
303
+ name: options.name,
304
+ tags: options.tags
305
+ } });
306
+ return factory;
307
+ }
308
+ //#endregion
309
+ //#region src/semantic/usecase.ts
310
+ function usecase(options, fn) {
311
+ return callable({
312
+ kind: "usecase",
313
+ ...options
314
+ }, fn);
315
+ }
316
+ //#endregion
317
+ export { brandComponent, buildRuntime, callable, client, isComponent, repo, service, usecase };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaceteams/warp",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Type-safe composition with execution scopes ",
5
5
  "type": "module",
6
6
  "files": [