@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.
- package/LICENSE +21 -0
- package/README.md +329 -0
- package/dist/capability.d.ts +165 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +268 -0
- package/dist/capability.js.map +1 -0
- package/dist/context.d.ts +35 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +28 -0
- package/dist/context.js.map +1 -0
- package/dist/enhancers.d.ts +92 -0
- package/dist/enhancers.d.ts.map +1 -0
- package/dist/enhancers.js +251 -0
- package/dist/enhancers.js.map +1 -0
- package/dist/errors.d.ts +53 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/event-bus.d.ts +56 -0
- package/dist/event-bus.d.ts.map +1 -0
- package/dist/event-bus.js +51 -0
- package/dist/event-bus.js.map +1 -0
- package/dist/execution-engine.d.ts +39 -0
- package/dist/execution-engine.d.ts.map +1 -0
- package/dist/execution-engine.js +210 -0
- package/dist/execution-engine.js.map +1 -0
- package/dist/guards.d.ts +78 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +56 -0
- package/dist/guards.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +28 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +43 -0
- package/dist/plugin.js.map +1 -0
- package/dist/server.d.ts +70 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +97 -0
- package/dist/server.js.map +1 -0
- package/dist/type-tests.d.ts +12 -0
- package/dist/type-tests.d.ts.map +1 -0
- package/dist/type-tests.js +175 -0
- package/dist/type-tests.js.map +1 -0
- 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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"}
|
package/dist/guards.d.ts
ADDED
|
@@ -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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -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"}
|
package/dist/server.d.ts
ADDED
|
@@ -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"}
|