@capixjs/core 0.1.0-alpha.1

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +329 -0
  3. package/dist/capability.d.ts +165 -0
  4. package/dist/capability.d.ts.map +1 -0
  5. package/dist/capability.js +268 -0
  6. package/dist/capability.js.map +1 -0
  7. package/dist/context.d.ts +35 -0
  8. package/dist/context.d.ts.map +1 -0
  9. package/dist/context.js +28 -0
  10. package/dist/context.js.map +1 -0
  11. package/dist/enhancers.d.ts +92 -0
  12. package/dist/enhancers.d.ts.map +1 -0
  13. package/dist/enhancers.js +251 -0
  14. package/dist/enhancers.js.map +1 -0
  15. package/dist/errors.d.ts +53 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +74 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/event-bus.d.ts +56 -0
  20. package/dist/event-bus.d.ts.map +1 -0
  21. package/dist/event-bus.js +51 -0
  22. package/dist/event-bus.js.map +1 -0
  23. package/dist/execution-engine.d.ts +39 -0
  24. package/dist/execution-engine.d.ts.map +1 -0
  25. package/dist/execution-engine.js +210 -0
  26. package/dist/execution-engine.js.map +1 -0
  27. package/dist/guards.d.ts +78 -0
  28. package/dist/guards.d.ts.map +1 -0
  29. package/dist/guards.js +56 -0
  30. package/dist/guards.js.map +1 -0
  31. package/dist/index.d.ts +22 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +22 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/plugin.d.ts +28 -0
  36. package/dist/plugin.d.ts.map +1 -0
  37. package/dist/plugin.js +43 -0
  38. package/dist/plugin.js.map +1 -0
  39. package/dist/server.d.ts +70 -0
  40. package/dist/server.d.ts.map +1 -0
  41. package/dist/server.js +97 -0
  42. package/dist/server.js.map +1 -0
  43. package/dist/type-tests.d.ts +12 -0
  44. package/dist/type-tests.d.ts.map +1 -0
  45. package/dist/type-tests.js +175 -0
  46. package/dist/type-tests.js.map +1 -0
  47. package/package.json +47 -0
@@ -0,0 +1,210 @@
1
+ /**
2
+ * execution-engine.ts — the heart of the framework
3
+ * Depends on: capability.ts, context.ts, guards.ts, errors.ts
4
+ */
5
+ import { runInputGuards } from './guards.js';
6
+ import { isFrameworkError } from './errors.js';
7
+ function toErrorResponse(err, isDevelopment) {
8
+ if (isFrameworkError(err)) {
9
+ return {
10
+ ok: false,
11
+ error: {
12
+ status: err.status,
13
+ error: err.error,
14
+ message: err.message,
15
+ ...(err.meta !== undefined ? { meta: err.meta } : {}),
16
+ },
17
+ };
18
+ }
19
+ if (isDevelopment) {
20
+ console.error('[capix] Unexpected error:', err);
21
+ const message = err instanceof Error ? err.message : String(err);
22
+ return {
23
+ ok: false,
24
+ error: { status: 500, error: 'Internal', message },
25
+ };
26
+ }
27
+ return {
28
+ ok: false,
29
+ error: { status: 500, error: 'Internal', message: 'Internal server error' },
30
+ };
31
+ }
32
+ /**
33
+ * Creates the invoke function that runs the full capability pipeline:
34
+ * lookup → buildContext → guards → validate input → resolve → validate output
35
+ */
36
+ export function createExecutionEngine(options) {
37
+ const { registry, buildContext, isDevelopment = false } = options;
38
+ return async function invoke(req) {
39
+ // 1. Look up capability
40
+ const cap = registry.get(req.capability);
41
+ if (!cap) {
42
+ return {
43
+ ok: false,
44
+ error: {
45
+ status: 404,
46
+ error: 'NotFound',
47
+ message: `Capability '${req.capability}' not found. Did you register it in your capabilities tree?`,
48
+ },
49
+ };
50
+ }
51
+ // 2. Build context
52
+ let ctx;
53
+ try {
54
+ const rawReq = {
55
+ headers: req.headers,
56
+ method: 'POST',
57
+ url: `/${req.capability.replaceAll('.', '/')}`,
58
+ signal: req.signal,
59
+ ...(req.rawBody !== undefined ? { rawBody: req.rawBody } : {}),
60
+ };
61
+ // Async-detect: skip microtask tick for sync buildContext (common case)
62
+ const ctxResult = buildContext(rawReq);
63
+ ctx = (typeof ctxResult === 'object' && ctxResult !== null &&
64
+ typeof ctxResult.then === 'function')
65
+ ? await ctxResult
66
+ : ctxResult;
67
+ }
68
+ catch (err) {
69
+ if (isFrameworkError(err)) {
70
+ return toErrorResponse(err, isDevelopment);
71
+ }
72
+ if (isDevelopment)
73
+ console.error('[capix] buildContext error:', err);
74
+ return {
75
+ ok: false,
76
+ error: { status: 500, error: 'Internal', message: 'Failed to build request context' },
77
+ };
78
+ }
79
+ // 3. Run guards (log guard name on unexpected errors in dev mode)
80
+ try {
81
+ for (const guard of cap.guards) {
82
+ try {
83
+ // Avoid microtask tick for sync guards (void return). Only await when the guard
84
+ // actually returns a Promise (async guards or explicit return Promise<void>).
85
+ const r = guard(ctx);
86
+ if (r !== undefined && r !== null && typeof r.then === 'function') {
87
+ await r;
88
+ }
89
+ }
90
+ catch (err) {
91
+ if (isDevelopment && !isFrameworkError(err)) {
92
+ const name = guard.name || '(anonymous)';
93
+ console.error(`[capix] Guard '${name}' threw an unexpected error:`, err);
94
+ }
95
+ throw err;
96
+ }
97
+ }
98
+ }
99
+ catch (err) {
100
+ return toErrorResponse(err, isDevelopment);
101
+ }
102
+ // 4. Validate input
103
+ let validatedInput;
104
+ if (cap._skipValidation) {
105
+ // z.object({}) — nothing to validate; pass through as empty object.
106
+ validatedInput = req.input ?? {};
107
+ }
108
+ else if (cap.inputSchema !== null) {
109
+ // Try sync parse first (no Promise overhead for the common case).
110
+ // Falls back to safeParseAsync only when the schema has async refinements.
111
+ let result;
112
+ try {
113
+ result = cap.inputSchema.safeParse(req.input);
114
+ }
115
+ catch {
116
+ result = await cap.inputSchema.safeParseAsync(req.input);
117
+ }
118
+ if (!result.success) {
119
+ const issues = result.error.issues.map((i) => {
120
+ const path = i.path.length > 0 ? i.path.join('.') + ': ' : '';
121
+ return path + i.message;
122
+ });
123
+ return {
124
+ ok: false,
125
+ error: {
126
+ status: 400,
127
+ error: 'BadRequest',
128
+ message: 'Input validation failed',
129
+ meta: { issues },
130
+ },
131
+ };
132
+ }
133
+ validatedInput = result.data;
134
+ }
135
+ else {
136
+ validatedInput = undefined;
137
+ }
138
+ // 5. Run input guards (run after validation so guards receive typed input)
139
+ if (cap.inputGuards.length > 0) {
140
+ try {
141
+ await runInputGuards(cap.inputGuards, validatedInput, ctx);
142
+ }
143
+ catch (err) {
144
+ return toErrorResponse(err, isDevelopment);
145
+ }
146
+ }
147
+ // 6. Resolve — use _resolverOnly since guards already ran in step 3
148
+ let output;
149
+ try {
150
+ output = await cap._resolverOnly(validatedInput, ctx);
151
+ }
152
+ catch (err) {
153
+ return toErrorResponse(err, isDevelopment);
154
+ }
155
+ // 7. Check for streaming return (not supported)
156
+ if (output != null && typeof output === 'object' && Symbol.asyncIterator in output) {
157
+ if (isDevelopment) {
158
+ console.error(`[capix] Capability '${req.capability}' returned an async iterable/stream.`);
159
+ }
160
+ return {
161
+ ok: false,
162
+ error: {
163
+ status: 500,
164
+ error: 'Internal',
165
+ message: `Capability '${req.capability}' returned a stream or async iterable. Streaming responses are not supported. Return a plain object, string, or null instead.`,
166
+ },
167
+ };
168
+ }
169
+ // 8. Check for undefined return
170
+ if (output === undefined) {
171
+ if (isDevelopment) {
172
+ console.error(`[capix] Capability '${req.capability}' returned undefined`);
173
+ }
174
+ return {
175
+ ok: false,
176
+ error: {
177
+ status: 500,
178
+ error: 'Internal',
179
+ message: `Capability '${req.capability}' returned undefined. Resolvers must return a value or throw.`,
180
+ },
181
+ };
182
+ }
183
+ // 9. Validate output — development only. In production, TypeScript types and the
184
+ // compiled fjs serializer enforce the shape; Zod's runtime parse is redundant overhead.
185
+ if (cap.outputSchema !== null && isDevelopment) {
186
+ let result;
187
+ try {
188
+ result = cap.outputSchema.safeParse(output);
189
+ }
190
+ catch {
191
+ result = await cap.outputSchema.safeParseAsync(output);
192
+ }
193
+ if (!result.success) {
194
+ console.error(`[capix] Output validation failed for '${req.capability}':`, result.error.issues);
195
+ return {
196
+ ok: false,
197
+ error: {
198
+ status: 500,
199
+ error: 'Internal',
200
+ message: `Capability '${req.capability}' returned invalid output`,
201
+ meta: { issues: result.error.issues },
202
+ },
203
+ };
204
+ }
205
+ output = result.data;
206
+ }
207
+ return { ok: true, data: output };
208
+ };
209
+ }
210
+ //# sourceMappingURL=execution-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution-engine.js","sourceRoot":"","sources":["../src/execution-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * guards.ts — guard types and execution
3
+ * Depends on: context.ts
4
+ */
5
+ import type { BaseContext } from './context.js';
6
+ /** A guard that passes silently or throws. May be async. */
7
+ export type Guard<TContext extends BaseContext> = (ctx: TContext) => void | Promise<void>;
8
+ /**
9
+ * A guard that narrows the context type via TypeScript asserts.
10
+ *
11
+ * `TNarrowed extends TContext` ensures the asserted type is always a subtype of
12
+ * the parameter type, satisfying TS2677 without requiring @ts-ignore.
13
+ * `TNarrowed` is the full narrowed type — e.g. `AppContext & { user: User }`.
14
+ */
15
+ export type NarrowingGuard<TContext extends BaseContext, TNarrowed extends TContext> = (ctx: TContext) => asserts ctx is TNarrowed;
16
+ /** Any guard — uses `any` context so guards typed for specific contexts are assignable. */
17
+ export type AnyGuard = (ctx: any) => void | Promise<void>;
18
+ /**
19
+ * Utility type: if TGuard is a NarrowingGuard, extract the narrowed type.
20
+ * Otherwise return TContext unchanged.
21
+ *
22
+ * KNOWN LIMITATION: NarrowContext uses 'any' due to TypeScript's function-parameter
23
+ * contravariance. Guards are often typed for a specific AppContext, but a capability
24
+ * starts with TContext = BaseContext. Matching on `(ctx: TContext)` fails because
25
+ * `(ctx: AppContext)` is not assignable to `(ctx: BaseContext)` — the guard demands
26
+ * a more specific type than the capability provides at definition time.
27
+ * Using `any` as the match parameter bypasses contravariance and correctly infers
28
+ * TNarrowed from the asserted type. Track: GitHub issue #1
29
+ * Attempted fixes: explicit generic `(ctx: TContext)` — breaks guards with specific
30
+ * contexts; `(ctx: unknown)` — same failure. Revisit when TypeScript improves
31
+ * conditional assertion inference.
32
+ */
33
+ export type NarrowContext<TContext extends BaseContext, TGuard> = TGuard extends (ctx: any) => asserts ctx is infer TNarrowed ? TNarrowed extends TContext ? TNarrowed : TContext : TContext;
34
+ /**
35
+ * Pass-through for type inference.
36
+ * Wrap your guard function with this for proper TypeScript narrowing.
37
+ *
38
+ * Two forms:
39
+ * - `defineGuard(fn)` — infers types from the function signature (common case)
40
+ * - `defineGuard<TContext, TNarrowed>(fn)` — explicit narrowing when TypeScript
41
+ * can't infer the asserted type (e.g. guards stored in variables before use)
42
+ */
43
+ export declare function defineGuard<TContext extends BaseContext, TNarrowed extends TContext>(fn: (ctx: TContext) => asserts ctx is TNarrowed): (ctx: TContext) => asserts ctx is TNarrowed;
44
+ export declare function defineGuard<TFn extends AnyGuard>(fn: TFn): TFn;
45
+ /**
46
+ * Returns a guard factory pre-bound to a specific context type.
47
+ * Avoids repeating the context type annotation on every guard.
48
+ *
49
+ * @example
50
+ * const defineAppGuard = defineGuardFor<AppContext>();
51
+ * const mustBeAdmin = defineAppGuard((ctx): asserts ctx is AppContext & { user: Admin } => {
52
+ * if (!ctx.user?.admin) throw Errors.Forbidden();
53
+ * });
54
+ */
55
+ export declare function defineGuardFor<TContext extends BaseContext>(): <TFn extends (ctx: TContext) => any>(fn: TFn) => TFn;
56
+ /**
57
+ * Runs guards in order. Stops at the first guard that throws.
58
+ * Supports async guards.
59
+ */
60
+ export declare function runGuards(guards: ReadonlyArray<AnyGuard>, ctx: BaseContext): Promise<void>;
61
+ /** A guard that receives both validated input and context. May be async. */
62
+ export type InputGuard<TInput = any, TContext extends BaseContext = BaseContext> = (input: TInput, ctx: TContext) => void | Promise<void>;
63
+ export type AnyInputGuard = InputGuard<any, any>;
64
+ /**
65
+ * Pass-through for type inference.
66
+ *
67
+ * @example
68
+ * const mustOwnOrder = defineInputGuard(async ({ id }: { id: string }, ctx: AuthContext) => {
69
+ * const order = ctx.db.orders.get(id);
70
+ * if (!order || order.customerId !== ctx.user.id) throw errors.Forbidden();
71
+ * });
72
+ *
73
+ * export const cancelOrder = authCap(Input, resolver).inputGuard(mustOwnOrder);
74
+ */
75
+ export declare function defineInputGuard<TInput, TContext extends BaseContext>(fn: InputGuard<TInput, TContext>): InputGuard<TInput, TContext>;
76
+ /** Runs input guards in order. Skips microtask tick for synchronous guards. */
77
+ export declare function runInputGuards(guards: ReadonlyArray<AnyInputGuard>, input: unknown, ctx: BaseContext): Promise<void>;
78
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,4DAA4D;AAC5D,MAAM,MAAM,KAAK,CAAC,QAAQ,SAAS,WAAW,IAAI,CAChD,GAAG,EAAE,QAAQ,KACV,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,QAAQ,SAAS,WAAW,EAAE,SAAS,SAAS,QAAQ,IAAI,CACrF,GAAG,EAAE,QAAQ,KACV,OAAO,CAAC,GAAG,IAAI,SAAS,CAAC;AAG9B,2FAA2F;AAC3F,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,CACvB,QAAQ,SAAS,WAAW,EAC5B,MAAM,IAEJ,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,IAAI,MAAM,SAAS,GAC3D,SAAS,SAAS,QAAQ,GACxB,SAAS,GACT,QAAQ,GACV,QAAQ,CAAC;AAEb;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,QAAQ,SAAS,WAAW,EAC5B,SAAS,SAAS,QAAQ,EAC1B,EAAE,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,IAAI,SAAS,GAAG,CAAC,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,IAAI,SAAS,CAAC;AAChG,wBAAgB,WAAW,CAAC,GAAG,SAAS,QAAQ,EAAE,EAAE,EAAE,GAAG,GAAG,GAAG,CAAC;AAKhE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAS,WAAW,MACxC,GAAG,SAAS,CAAC,GAAG,EAAE,QAAQ,KAAK,GAAG,EAAE,IAAI,GAAG,KAAG,GAAG,CAGnE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,EAC/B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,IAAI,CAAC,CAIf;AAOD,4EAA4E;AAE5E,MAAM,MAAM,UAAU,CAAC,MAAM,GAAG,GAAG,EAAE,QAAQ,SAAS,WAAW,GAAG,WAAW,IAAI,CACjF,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,QAAQ,KACV,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAG1B,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,SAAS,WAAW,EACnE,EAAE,EAAE,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,GAC/B,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,CAE9B;AAED,+EAA+E;AAC/E,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,EACpC,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,IAAI,CAAC,CAQf"}
package/dist/guards.js ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * guards.ts — guard types and execution
3
+ * Depends on: context.ts
4
+ */
5
+ export function defineGuard(fn) {
6
+ return fn;
7
+ }
8
+ /**
9
+ * Returns a guard factory pre-bound to a specific context type.
10
+ * Avoids repeating the context type annotation on every guard.
11
+ *
12
+ * @example
13
+ * const defineAppGuard = defineGuardFor<AppContext>();
14
+ * const mustBeAdmin = defineAppGuard((ctx): asserts ctx is AppContext & { user: Admin } => {
15
+ * if (!ctx.user?.admin) throw Errors.Forbidden();
16
+ * });
17
+ */
18
+ export function defineGuardFor() {
19
+ return function (fn) {
20
+ return fn;
21
+ };
22
+ }
23
+ /**
24
+ * Runs guards in order. Stops at the first guard that throws.
25
+ * Supports async guards.
26
+ */
27
+ export async function runGuards(guards, ctx) {
28
+ for (const guard of guards) {
29
+ await guard(ctx);
30
+ }
31
+ }
32
+ /**
33
+ * Pass-through for type inference.
34
+ *
35
+ * @example
36
+ * const mustOwnOrder = defineInputGuard(async ({ id }: { id: string }, ctx: AuthContext) => {
37
+ * const order = ctx.db.orders.get(id);
38
+ * if (!order || order.customerId !== ctx.user.id) throw errors.Forbidden();
39
+ * });
40
+ *
41
+ * export const cancelOrder = authCap(Input, resolver).inputGuard(mustOwnOrder);
42
+ */
43
+ export function defineInputGuard(fn) {
44
+ return fn;
45
+ }
46
+ /** Runs input guards in order. Skips microtask tick for synchronous guards. */
47
+ export async function runInputGuards(guards, input, ctx) {
48
+ for (const guard of guards) {
49
+ const result = guard(input, ctx);
50
+ if (result !== undefined && result !== null &&
51
+ typeof result.then === 'function') {
52
+ await result;
53
+ }
54
+ }
55
+ }
56
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+DH,MAAM,UAAU,WAAW,CAAC,EAAY;IACtC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,UAA8C,EAAO;QAC1D,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,MAA+B,EAC/B,GAAgB;IAEhB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAiBD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAgC;IAEhC,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAoC,EACpC,KAAc,EACd,GAAgB;IAEhB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI;YACvC,OAAQ,MAA6B,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9D,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * index.ts — public API exports for the 'capix' package
3
+ */
4
+ export { defineError, isFrameworkError, defaultErrors } from './errors.js';
5
+ export type { FrameworkError, ErrorFactory } from './errors.js';
6
+ export { defineContext, getHeader } from './context.js';
7
+ export type { RawRequest, BaseContext, ContextBuilder } from './context.js';
8
+ export { defineGuard, defineGuardFor, runGuards, defineInputGuard, runInputGuards } from './guards.js';
9
+ export type { Guard, NarrowingGuard, AnyGuard, NarrowContext, InputGuard, AnyInputGuard } from './guards.js';
10
+ export { capability, isCapability, compileRegistry, inferIntent } from './capability.js';
11
+ export type { Intent, Enhancer, Resolver, Capability, AnyCapability, CapabilityRegistry, GroupTree, InferInput, InferOutput, InferContext, ScopedCapabilityFactory, } from './capability.js';
12
+ export { defineEnhancer, withLogging, withCache, withTimeout, withRetry, withRateLimit, withRollback, withMetrics, withCircuitBreaker, consoleMetricsCollector, } from './enhancers.js';
13
+ export type { RateLimitOptions, MetricsCollector, CircuitBreakerOptions, RollbackFn, WithRollback, } from './enhancers.js';
14
+ export { createExecutionEngine } from './execution-engine.js';
15
+ export type { CapabilityRequest, CapabilityResponse, SerializedError, InvokeFn, ExecutionEngineOptions, } from './execution-engine.js';
16
+ export { definePlugin, mergePlugins } from './plugin.js';
17
+ export type { Plugin, MergedPlugins } from './plugin.js';
18
+ export { createServer, defineConfig } from './server.js';
19
+ export type { Transport, TransportWithCapabilities, MountOptions, ServerConfig, Server } from './server.js';
20
+ export { createEventBus } from './event-bus.js';
21
+ export type { EventBus, EventMap, SubscribeOptions } from './event-bus.js';
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3E,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG5E,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACvG,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG7G,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACzF,YAAY,EACV,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,EACZ,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,cAAc,EACd,WAAW,EACX,SAAS,EACT,WAAW,EACX,SAAS,EACT,aAAa,EACb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACV,YAAY,GACb,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,QAAQ,EACR,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,yBAAyB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG5G,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * index.ts — public API exports for the 'capix' package
3
+ */
4
+ // Errors
5
+ export { defineError, isFrameworkError, defaultErrors } from './errors.js';
6
+ // Context
7
+ export { defineContext, getHeader } from './context.js';
8
+ // Guards
9
+ export { defineGuard, defineGuardFor, runGuards, defineInputGuard, runInputGuards } from './guards.js';
10
+ // Capability
11
+ export { capability, isCapability, compileRegistry, inferIntent } from './capability.js';
12
+ // Enhancers
13
+ export { defineEnhancer, withLogging, withCache, withTimeout, withRetry, withRateLimit, withRollback, withMetrics, withCircuitBreaker, consoleMetricsCollector, } from './enhancers.js';
14
+ // Execution engine
15
+ export { createExecutionEngine } from './execution-engine.js';
16
+ // Plugin
17
+ export { definePlugin, mergePlugins } from './plugin.js';
18
+ // Server
19
+ export { createServer, defineConfig } from './server.js';
20
+ // Event bus
21
+ export { createEventBus } from './event-bus.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG3E,UAAU;AACV,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGxD,SAAS;AACT,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGvG,aAAa;AACb,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAezF,YAAY;AACZ,OAAO,EACL,cAAc,EACd,WAAW,EACX,SAAS,EACT,WAAW,EACX,SAAS,EACT,aAAa,EACb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AASxB,mBAAmB;AACnB,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAS9D,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGzD,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGzD,YAAY;AACZ,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * plugin.ts — plugin system
3
+ * Depends on: capability.ts, errors.ts, guards.ts, context.ts
4
+ */
5
+ import type { AnyCapability } from './capability.js';
6
+ import type { BaseContext, ContextBuilder, RawRequest } from './context.js';
7
+ export type Plugin = {
8
+ readonly name: string;
9
+ /**
10
+ * Extend the request context after it has been built by the user's ContextBuilder.
11
+ * Receives both the built context and the original raw request so plugins can
12
+ * read headers, URLs, etc. May be async.
13
+ */
14
+ readonly context?: (base: BaseContext, req: RawRequest) => BaseContext | Promise<BaseContext>;
15
+ readonly capabilities?: Record<string, AnyCapability>;
16
+ };
17
+ /** Pass-through for type inference. */
18
+ export declare function definePlugin(plugin: Plugin): Plugin;
19
+ export type MergedPlugins = {
20
+ readonly wrapContext: (builder: ContextBuilder) => ContextBuilder;
21
+ readonly additionalCapabilities: Record<string, AnyCapability>;
22
+ };
23
+ /**
24
+ * Merges multiple plugins into a single result.
25
+ * Throws at startup if any capability names collide.
26
+ */
27
+ export declare function mergePlugins(plugins: Plugin[]): MergedPlugins;
28
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE5E,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,UAAU,KAAK,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9F,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAKvD,CAAC;AAEF,uCAAuC;AACvC,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,cAAc,CAAC;IAClE,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAChE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,aAAa,CAmC7D"}
package/dist/plugin.js ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * plugin.ts — plugin system
3
+ * Depends on: capability.ts, errors.ts, guards.ts, context.ts
4
+ */
5
+ /** Pass-through for type inference. */
6
+ export function definePlugin(plugin) {
7
+ return plugin;
8
+ }
9
+ /**
10
+ * Merges multiple plugins into a single result.
11
+ * Throws at startup if any capability names collide.
12
+ */
13
+ export function mergePlugins(plugins) {
14
+ const allCaps = {};
15
+ for (const plugin of plugins) {
16
+ for (const [key, cap] of Object.entries(plugin.capabilities ?? {})) {
17
+ if (key in allCaps) {
18
+ throw new Error(`[capix] Plugin capability name collision: '${key}' is defined by multiple plugins`);
19
+ }
20
+ allCaps[key] = cap;
21
+ }
22
+ }
23
+ const contextExtensions = plugins
24
+ .filter((p) => p.context !== undefined)
25
+ .map((p) => p.context);
26
+ function wrapContext(builder) {
27
+ // Fast path: no plugin context extensions to apply
28
+ if (contextExtensions.length === 0)
29
+ return builder;
30
+ return async (req) => {
31
+ let ctx = await builder(req);
32
+ for (const extend of contextExtensions) {
33
+ ctx = (await extend(ctx, req));
34
+ }
35
+ return ctx;
36
+ };
37
+ }
38
+ return {
39
+ wrapContext,
40
+ additionalCapabilities: allCaps,
41
+ };
42
+ }
43
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH,uCAAuC;AACvC,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAiB;IAC5C,MAAM,OAAO,GAAkC,EAAE,CAAC;IAElD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,CAAC;YACnE,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CACb,8CAA8C,GAAG,kCAAkC,CACpF,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,iBAAiB,GAAG,OAAO;SAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAQ,CAAC,CAAC;IAE1B,SAAS,WAAW,CAAC,OAAuB;QAC1C,mDAAmD;QACnD,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QAEnD,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;YACnB,IAAI,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7B,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;gBACvC,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAwC,CAAC;YACxE,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW;QACX,sBAAsB,EAAE,OAAO;KAChC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * server.ts — server creation and transport orchestration
3
+ * Depends on: all above
4
+ */
5
+ import type { AnyCapability, CapabilityRegistry, GroupTree } from './capability.js';
6
+ import type { ContextBuilder } from './context.js';
7
+ import type { InvokeFn } from './execution-engine.js';
8
+ import type { Plugin } from './plugin.js';
9
+ export type MountOptions = {
10
+ readonly registry: CapabilityRegistry;
11
+ readonly invoke: InvokeFn;
12
+ };
13
+ export interface Transport {
14
+ mount(invoke: InvokeFn, options: MountOptions): void | Promise<void>;
15
+ unmount(): Promise<void>;
16
+ }
17
+ /**
18
+ * A Transport that declares its own capability registry.
19
+ * `createServer` reads `_capabilities` during `start()` and compiles a
20
+ * separate registry for this transport, overriding the server-level default.
21
+ */
22
+ export type TransportWithCapabilities = Transport & {
23
+ /** Set by transport factories when the caller passes a `capabilities` option. */
24
+ readonly _capabilities?: GroupTree;
25
+ };
26
+ export type ServerConfig = {
27
+ readonly context: ContextBuilder;
28
+ /**
29
+ * Default capability registry for all transports that don't declare their own.
30
+ * Optional when every transport specifies its own `capabilities`.
31
+ */
32
+ readonly capabilities?: Record<string, AnyCapability | Record<string, unknown>>;
33
+ readonly transports: Transport[];
34
+ readonly plugins?: Plugin[];
35
+ readonly isDevelopment?: boolean;
36
+ };
37
+ export type Server = {
38
+ start(): Promise<void>;
39
+ stop(): Promise<void>;
40
+ readonly invoke: InvokeFn;
41
+ };
42
+ /**
43
+ * Creates a Capix server from a config object.
44
+ *
45
+ * Compiles the capability tree into a registry, wires plugins, and returns a
46
+ * server with `start()` / `stop()` lifecycle methods and a direct `invoke()`
47
+ * entry point (useful for testing without HTTP).
48
+ *
49
+ * Per-transport capabilities: pass `capabilities` to a transport factory to
50
+ * override the server-level default for that transport only:
51
+ *
52
+ * ```ts
53
+ * createServer({
54
+ * context: buildContext,
55
+ * transports: [
56
+ * restTransport({ port: 3000, capabilities: publicCaps }),
57
+ * queueTransport({ queues: ['jobs'], adapter, capabilities: jobCaps }),
58
+ * ],
59
+ * });
60
+ * ```
61
+ *
62
+ * @throws {Error} At construction time if a plugin capability name collides with
63
+ * a user capability name.
64
+ * @throws {Error} In `start()` if a transport has no capabilities (neither its
65
+ * own nor a server-level default).
66
+ */
67
+ export declare function createServer(config: ServerConfig): Server;
68
+ /** Pass-through for config type inference. */
69
+ export declare function defineConfig(config: ServerConfig): ServerConfig;
70
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG;IAClD,iFAAiF;IACjF,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAiFzD;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D"}