@gramio/composer 0.1.0 → 0.2.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/README.md +46 -0
- package/dist/index.cjs +28 -3
- package/dist/index.d.cts +50 -33
- package/dist/index.d.ts +50 -33
- package/dist/index.js +28 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -305,6 +305,52 @@ const app = new Composer()
|
|
|
305
305
|
});
|
|
306
306
|
```
|
|
307
307
|
|
|
308
|
+
#### `types` + `eventTypes()` — phantom type inference
|
|
309
|
+
|
|
310
|
+
TypeScript cannot partially infer type arguments, so when you need both `TEventMap` and `TMethods` inferred together, use the `types` phantom field with the `eventTypes()` helper instead of explicit type parameters:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
import { createComposer, eventTypes } from "@gramio/composer";
|
|
314
|
+
|
|
315
|
+
// eventTypes<T>() returns undefined at runtime — purely for inference
|
|
316
|
+
const { Composer } = createComposer({
|
|
317
|
+
discriminator: (ctx: BaseCtx) => ctx.updateType,
|
|
318
|
+
types: eventTypes<{ message: MessageCtx; callback_query: CallbackCtx }>(),
|
|
319
|
+
});
|
|
320
|
+
// TBase inferred from discriminator, TEventMap inferred from types
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### `methods` — custom prototype methods
|
|
324
|
+
|
|
325
|
+
Inject framework-specific DX sugar directly onto the Composer prototype via the `methods` config option. Method bodies receive `this` typed as the full `EventComposer`, giving access to `.on()`, `.use()`, `.derive()`, etc.
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
const { Composer } = createComposer({
|
|
329
|
+
discriminator: (ctx: BaseCtx) => ctx.updateType,
|
|
330
|
+
types: eventTypes<{ message: MessageCtx }>(),
|
|
331
|
+
methods: {
|
|
332
|
+
hears(trigger: RegExp | string, handler: (ctx: MessageCtx) => unknown) {
|
|
333
|
+
return this.on("message", (ctx, next) => {
|
|
334
|
+
const text = ctx.text;
|
|
335
|
+
if (
|
|
336
|
+
(typeof trigger === "string" && text === trigger) ||
|
|
337
|
+
(trigger instanceof RegExp && text && trigger.test(text))
|
|
338
|
+
) {
|
|
339
|
+
return handler(ctx);
|
|
340
|
+
}
|
|
341
|
+
return next();
|
|
342
|
+
});
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const bot = new Composer();
|
|
348
|
+
bot.hears(/hello/, handler); // custom method
|
|
349
|
+
bot.on("message", h).hears(/hi/, h2); // chaining works — TMethods preserved
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Custom methods are preserved through **all** method chains (`on`, `use`, `derive`, `extend`, etc.). A runtime conflict check throws if a method name collides with a built-in (e.g. `on`, `use`, `derive`).
|
|
353
|
+
|
|
308
354
|
### `EventQueue`
|
|
309
355
|
|
|
310
356
|
Concurrent event queue with graceful shutdown.
|
package/dist/index.cjs
CHANGED
|
@@ -311,15 +311,23 @@ class Composer {
|
|
|
311
311
|
if (this["~"].extended.has(key)) return this;
|
|
312
312
|
this["~"].extended.add(key);
|
|
313
313
|
}
|
|
314
|
+
const alreadyExtended = new Set(this["~"].extended);
|
|
314
315
|
for (const key of other["~"].extended) {
|
|
315
316
|
this["~"].extended.add(key);
|
|
316
317
|
}
|
|
317
318
|
Object.assign(this["~"].errorsDefinitions, other["~"].errorsDefinitions);
|
|
318
319
|
this["~"].onErrors.push(...other["~"].onErrors);
|
|
319
320
|
const pluginName = other["~"].name;
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
const isNew = (m) => {
|
|
322
|
+
if (!m.plugin) return true;
|
|
323
|
+
for (const key of alreadyExtended) {
|
|
324
|
+
if (key.startsWith(m.plugin + ":")) return false;
|
|
325
|
+
}
|
|
326
|
+
return true;
|
|
327
|
+
};
|
|
328
|
+
const localMws = other["~"].middlewares.filter((m) => m.scope === "local" && isNew(m));
|
|
329
|
+
const scopedMws = other["~"].middlewares.filter((m) => m.scope === "scoped" && isNew(m));
|
|
330
|
+
const globalMws = other["~"].middlewares.filter((m) => m.scope === "global" && isNew(m));
|
|
323
331
|
if (localMws.length > 0) {
|
|
324
332
|
const chain = compose(localMws.map((m) => m.fn));
|
|
325
333
|
const isolated = async (ctx, next) => {
|
|
@@ -467,6 +475,9 @@ class EventQueue {
|
|
|
467
475
|
}
|
|
468
476
|
}
|
|
469
477
|
|
|
478
|
+
function eventTypes() {
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
470
481
|
function createComposer(config) {
|
|
471
482
|
class EventComposerImpl extends Composer {
|
|
472
483
|
on(event, handler) {
|
|
@@ -504,6 +515,19 @@ function createComposer(config) {
|
|
|
504
515
|
return this;
|
|
505
516
|
}
|
|
506
517
|
}
|
|
518
|
+
if (config.methods) {
|
|
519
|
+
for (const [name, fn] of Object.entries(config.methods)) {
|
|
520
|
+
if (name in EventComposerImpl.prototype) {
|
|
521
|
+
throw new Error(`Custom method "${name}" conflicts with built-in method`);
|
|
522
|
+
}
|
|
523
|
+
Object.defineProperty(EventComposerImpl.prototype, name, {
|
|
524
|
+
value: fn,
|
|
525
|
+
writable: true,
|
|
526
|
+
configurable: true,
|
|
527
|
+
enumerable: false
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
507
531
|
return {
|
|
508
532
|
Composer: EventComposerImpl,
|
|
509
533
|
compose,
|
|
@@ -515,6 +539,7 @@ exports.Composer = Composer;
|
|
|
515
539
|
exports.EventQueue = EventQueue;
|
|
516
540
|
exports.compose = compose;
|
|
517
541
|
exports.createComposer = createComposer;
|
|
542
|
+
exports.eventTypes = eventTypes;
|
|
518
543
|
exports.noopNext = noopNext;
|
|
519
544
|
exports.skip = skip;
|
|
520
545
|
exports.stop = stop;
|
package/dist/index.d.cts
CHANGED
|
@@ -15,7 +15,7 @@ type DeriveHandler<T, D> = (context: T) => D | Promise<D>;
|
|
|
15
15
|
/** Lazy middleware factory — called per invocation */
|
|
16
16
|
type LazyFactory<T> = (context: T) => Middleware<T> | Promise<Middleware<T>>;
|
|
17
17
|
/** Single value or array */
|
|
18
|
-
type MaybeArray<T> = T | T[];
|
|
18
|
+
type MaybeArray<T> = T | readonly T[];
|
|
19
19
|
/** Scope level for middleware propagation */
|
|
20
20
|
type Scope = "local" | "scoped" | "global";
|
|
21
21
|
/** Which method created a middleware entry */
|
|
@@ -136,39 +136,39 @@ declare class EventQueue<T> {
|
|
|
136
136
|
* Array of events → discriminated union where each branch has correct derives.
|
|
137
137
|
*/
|
|
138
138
|
type ResolveEventCtx<TOut extends object, TEventMap extends Record<string, any>, TDerives extends Record<string, object>, E extends string> = E extends any ? TOut & (E extends keyof TEventMap ? TEventMap[E] : {}) & (E extends keyof TDerives ? TDerives[E] : {}) : never;
|
|
139
|
-
/** EventComposer interface — Composer + .on() + per-event derive tracking */
|
|
140
|
-
interface EventComposer<TBase extends object, TEventMap extends Record<string, TBase>, TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}> {
|
|
141
|
-
on<E extends keyof TEventMap & string>(event: MaybeArray<E>, handler: Middleware<ResolveEventCtx<TOut, TEventMap, TDerives, E>>):
|
|
142
|
-
|
|
139
|
+
/** EventComposer interface — Composer + .on() + per-event derive tracking + custom methods */
|
|
140
|
+
interface EventComposer<TBase extends object, TEventMap extends Record<string, TBase>, TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}, TMethods extends Record<string, (...args: any[]) => any> = {}> {
|
|
141
|
+
on<E extends keyof TEventMap & string>(event: MaybeArray<E>, handler: Middleware<ResolveEventCtx<TOut, TEventMap, TDerives, E>>): this;
|
|
142
|
+
use(...middleware: Middleware<TOut>[]): this;
|
|
143
|
+
guard<S extends TOut>(predicate: ((context: TOut) => context is S) | ((context: TOut) => boolean | Promise<boolean>), ...middleware: Middleware<any>[]): this;
|
|
144
|
+
branch(predicate: ((context: TOut) => boolean | Promise<boolean>) | boolean, onTrue: Middleware<TOut>, onFalse?: Middleware<TOut>): this;
|
|
145
|
+
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, cases: Partial<Record<K, (composer: Composer<TOut, TOut, {}>) => Composer<any, any, any>>>, fallback?: (composer: Composer<TOut, TOut, {}>) => Composer<any, any, any>): this;
|
|
146
|
+
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, builder: (route: RouteBuilder<TOut, K>) => void): this;
|
|
147
|
+
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, cases: Partial<Record<K, Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>>>, fallback?: Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>): this;
|
|
148
|
+
fork(...middleware: Middleware<TOut>[]): this;
|
|
149
|
+
tap(...middleware: Middleware<TOut>[]): this;
|
|
150
|
+
lazy(factory: LazyFactory<TOut>): this;
|
|
151
|
+
onError(handler: ErrorHandler<TOut>): this;
|
|
152
|
+
error(kind: string, errorClass: {
|
|
153
|
+
new (...args: any): any;
|
|
154
|
+
prototype: Error;
|
|
155
|
+
}): this;
|
|
156
|
+
group(fn: (composer: Composer<TOut, TOut, {}>) => void): this;
|
|
157
|
+
decorate<D extends object>(values: D): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed, TDerives, TMethods> & TMethods;
|
|
143
158
|
decorate<D extends object>(values: D, options: {
|
|
144
159
|
as: "scoped" | "global";
|
|
145
|
-
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives
|
|
146
|
-
|
|
147
|
-
derive<D extends object>(handler: DeriveHandler<TOut, D>): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed, TDerives>;
|
|
160
|
+
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives, TMethods> & TMethods;
|
|
161
|
+
derive<D extends object>(handler: DeriveHandler<TOut, D>): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed, TDerives, TMethods> & TMethods;
|
|
148
162
|
derive<D extends object>(handler: DeriveHandler<TOut, D>, options: {
|
|
149
163
|
as: "scoped" | "global";
|
|
150
|
-
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives
|
|
164
|
+
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives, TMethods> & TMethods;
|
|
151
165
|
derive<E extends keyof TEventMap & string, D extends object>(event: MaybeArray<E>, handler: DeriveHandler<ResolveEventCtx<TOut, TEventMap, TDerives, E>, D>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives & {
|
|
152
166
|
[K in E]: D;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, cases: Partial<Record<K, Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>>>, fallback?: Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
159
|
-
fork(...middleware: Middleware<TOut>[]): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
160
|
-
tap(...middleware: Middleware<TOut>[]): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
161
|
-
lazy(factory: LazyFactory<TOut>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
162
|
-
onError(handler: ErrorHandler<TOut>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
163
|
-
when<UOut extends TOut>(condition: boolean, fn: (composer: Composer<TOut, TOut, {}>) => Composer<TOut, UOut, any>): EventComposer<TBase, TEventMap, TIn, TOut & Partial<Omit<UOut, keyof TOut>>, TExposed, TDerives>;
|
|
164
|
-
error(kind: string, errorClass: {
|
|
165
|
-
new (...args: any): any;
|
|
166
|
-
prototype: Error;
|
|
167
|
-
}): this;
|
|
168
|
-
as(scope: "scoped" | "global"): EventComposer<TBase, TEventMap, TIn, TOut, TOut, TDerives>;
|
|
169
|
-
group(fn: (composer: Composer<TOut, TOut, {}>) => void): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
170
|
-
extend<UIn extends TBase, UOut extends UIn, UExposed extends object, UDerives extends Record<string, object>>(other: EventComposer<TBase, TEventMap, UIn, UOut, UExposed, UDerives>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives & UDerives>;
|
|
171
|
-
extend<UIn extends object, UOut extends UIn, UExposed extends object>(other: Composer<UIn, UOut, UExposed>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives>;
|
|
167
|
+
}, TMethods> & TMethods;
|
|
168
|
+
when<UOut extends TOut>(condition: boolean, fn: (composer: Composer<TOut, TOut, {}>) => Composer<TOut, UOut, any>): EventComposer<TBase, TEventMap, TIn, TOut & Partial<Omit<UOut, keyof TOut>>, TExposed, TDerives, TMethods> & TMethods;
|
|
169
|
+
as(scope: "scoped" | "global"): EventComposer<TBase, TEventMap, TIn, TOut, TOut, TDerives, TMethods> & TMethods;
|
|
170
|
+
extend<UIn extends TBase, UOut extends UIn, UExposed extends object, UDerives extends Record<string, object>>(other: EventComposer<TBase, TEventMap, UIn, UOut, UExposed, UDerives, any>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives & UDerives, TMethods> & TMethods;
|
|
171
|
+
extend<UIn extends object, UOut extends UIn, UExposed extends object>(other: Composer<UIn, UOut, UExposed>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives, TMethods> & TMethods;
|
|
172
172
|
inspect(): MiddlewareInfo[];
|
|
173
173
|
trace(handler: TraceHandler): this;
|
|
174
174
|
compose(): ComposedMiddleware<TIn>;
|
|
@@ -189,16 +189,33 @@ interface EventComposer<TBase extends object, TEventMap extends Record<string, T
|
|
|
189
189
|
};
|
|
190
190
|
invalidate(): void;
|
|
191
191
|
}
|
|
192
|
-
interface EventComposerConstructor<TBase extends object, TEventMap extends Record<string, TBase
|
|
193
|
-
new <TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}>(options?: ComposerOptions): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives
|
|
192
|
+
interface EventComposerConstructor<TBase extends object, TEventMap extends Record<string, TBase>, TMethods extends Record<string, (...args: any[]) => any> = {}> {
|
|
193
|
+
new <TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}>(options?: ComposerOptions): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives, TMethods> & TMethods;
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Phantom type carrier for event map inference.
|
|
197
|
+
* Returns `undefined` at runtime — exists purely for type-level inference
|
|
198
|
+
* so that `TEventMap` can be inferred from the `types` config field.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* const { Composer } = createComposer({
|
|
203
|
+
* discriminator: (ctx: BaseCtx) => ctx.updateType,
|
|
204
|
+
* types: eventTypes<EventMap>(),
|
|
205
|
+
* methods: { hears(trigger) { return this.on("message", ...); } },
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
declare function eventTypes<TEventMap extends Record<string, any>>(): TEventMap;
|
|
195
210
|
/**
|
|
196
211
|
* Creates a configured Composer class with type-safe .on() event discrimination.
|
|
197
212
|
*/
|
|
198
|
-
declare function createComposer<TBase extends object, TEventMap extends Record<string, TBase> = {}>(config: {
|
|
213
|
+
declare function createComposer<TBase extends object, TEventMap extends Record<string, TBase> = {}, TMethods extends Record<string, (...args: any[]) => any> = {}>(config: {
|
|
199
214
|
discriminator: (context: TBase) => string;
|
|
215
|
+
types?: TEventMap;
|
|
216
|
+
methods?: TMethods & ThisType<EventComposer<TBase, TEventMap, TBase, TBase, {}, {}, TMethods> & TMethods>;
|
|
200
217
|
}): {
|
|
201
|
-
Composer: EventComposerConstructor<TBase, TEventMap>;
|
|
218
|
+
Composer: EventComposerConstructor<TBase, TEventMap, TMethods>;
|
|
202
219
|
compose: typeof compose;
|
|
203
220
|
EventQueue: typeof EventQueue;
|
|
204
221
|
};
|
|
@@ -210,5 +227,5 @@ declare const skip: Middleware<any>;
|
|
|
210
227
|
/** Terminal middleware: does NOT call next() */
|
|
211
228
|
declare const stop: Middleware<any>;
|
|
212
229
|
|
|
213
|
-
export { Composer, EventQueue, compose, createComposer, noopNext, skip, stop };
|
|
230
|
+
export { Composer, EventQueue, compose, createComposer, eventTypes, noopNext, skip, stop };
|
|
214
231
|
export type { ComposedMiddleware, ComposerOptions, DeriveHandler, ErrorHandler, EventComposer, EventComposerConstructor, LazyFactory, MaybeArray, Middleware, MiddlewareInfo, MiddlewareType, Next, RouteBuilder, RouteHandler, Scope, TraceHandler };
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type DeriveHandler<T, D> = (context: T) => D | Promise<D>;
|
|
|
15
15
|
/** Lazy middleware factory — called per invocation */
|
|
16
16
|
type LazyFactory<T> = (context: T) => Middleware<T> | Promise<Middleware<T>>;
|
|
17
17
|
/** Single value or array */
|
|
18
|
-
type MaybeArray<T> = T | T[];
|
|
18
|
+
type MaybeArray<T> = T | readonly T[];
|
|
19
19
|
/** Scope level for middleware propagation */
|
|
20
20
|
type Scope = "local" | "scoped" | "global";
|
|
21
21
|
/** Which method created a middleware entry */
|
|
@@ -136,39 +136,39 @@ declare class EventQueue<T> {
|
|
|
136
136
|
* Array of events → discriminated union where each branch has correct derives.
|
|
137
137
|
*/
|
|
138
138
|
type ResolveEventCtx<TOut extends object, TEventMap extends Record<string, any>, TDerives extends Record<string, object>, E extends string> = E extends any ? TOut & (E extends keyof TEventMap ? TEventMap[E] : {}) & (E extends keyof TDerives ? TDerives[E] : {}) : never;
|
|
139
|
-
/** EventComposer interface — Composer + .on() + per-event derive tracking */
|
|
140
|
-
interface EventComposer<TBase extends object, TEventMap extends Record<string, TBase>, TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}> {
|
|
141
|
-
on<E extends keyof TEventMap & string>(event: MaybeArray<E>, handler: Middleware<ResolveEventCtx<TOut, TEventMap, TDerives, E>>):
|
|
142
|
-
|
|
139
|
+
/** EventComposer interface — Composer + .on() + per-event derive tracking + custom methods */
|
|
140
|
+
interface EventComposer<TBase extends object, TEventMap extends Record<string, TBase>, TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}, TMethods extends Record<string, (...args: any[]) => any> = {}> {
|
|
141
|
+
on<E extends keyof TEventMap & string>(event: MaybeArray<E>, handler: Middleware<ResolveEventCtx<TOut, TEventMap, TDerives, E>>): this;
|
|
142
|
+
use(...middleware: Middleware<TOut>[]): this;
|
|
143
|
+
guard<S extends TOut>(predicate: ((context: TOut) => context is S) | ((context: TOut) => boolean | Promise<boolean>), ...middleware: Middleware<any>[]): this;
|
|
144
|
+
branch(predicate: ((context: TOut) => boolean | Promise<boolean>) | boolean, onTrue: Middleware<TOut>, onFalse?: Middleware<TOut>): this;
|
|
145
|
+
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, cases: Partial<Record<K, (composer: Composer<TOut, TOut, {}>) => Composer<any, any, any>>>, fallback?: (composer: Composer<TOut, TOut, {}>) => Composer<any, any, any>): this;
|
|
146
|
+
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, builder: (route: RouteBuilder<TOut, K>) => void): this;
|
|
147
|
+
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, cases: Partial<Record<K, Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>>>, fallback?: Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>): this;
|
|
148
|
+
fork(...middleware: Middleware<TOut>[]): this;
|
|
149
|
+
tap(...middleware: Middleware<TOut>[]): this;
|
|
150
|
+
lazy(factory: LazyFactory<TOut>): this;
|
|
151
|
+
onError(handler: ErrorHandler<TOut>): this;
|
|
152
|
+
error(kind: string, errorClass: {
|
|
153
|
+
new (...args: any): any;
|
|
154
|
+
prototype: Error;
|
|
155
|
+
}): this;
|
|
156
|
+
group(fn: (composer: Composer<TOut, TOut, {}>) => void): this;
|
|
157
|
+
decorate<D extends object>(values: D): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed, TDerives, TMethods> & TMethods;
|
|
143
158
|
decorate<D extends object>(values: D, options: {
|
|
144
159
|
as: "scoped" | "global";
|
|
145
|
-
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives
|
|
146
|
-
|
|
147
|
-
derive<D extends object>(handler: DeriveHandler<TOut, D>): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed, TDerives>;
|
|
160
|
+
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives, TMethods> & TMethods;
|
|
161
|
+
derive<D extends object>(handler: DeriveHandler<TOut, D>): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed, TDerives, TMethods> & TMethods;
|
|
148
162
|
derive<D extends object>(handler: DeriveHandler<TOut, D>, options: {
|
|
149
163
|
as: "scoped" | "global";
|
|
150
|
-
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives
|
|
164
|
+
}): EventComposer<TBase, TEventMap, TIn, TOut & D, TExposed & D, TDerives, TMethods> & TMethods;
|
|
151
165
|
derive<E extends keyof TEventMap & string, D extends object>(event: MaybeArray<E>, handler: DeriveHandler<ResolveEventCtx<TOut, TEventMap, TDerives, E>, D>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives & {
|
|
152
166
|
[K in E]: D;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
route<K extends string>(router: (context: TOut) => K | undefined | Promise<K | undefined>, cases: Partial<Record<K, Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>>>, fallback?: Middleware<TOut> | Middleware<TOut>[] | Composer<any, any, any>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
159
|
-
fork(...middleware: Middleware<TOut>[]): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
160
|
-
tap(...middleware: Middleware<TOut>[]): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
161
|
-
lazy(factory: LazyFactory<TOut>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
162
|
-
onError(handler: ErrorHandler<TOut>): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
163
|
-
when<UOut extends TOut>(condition: boolean, fn: (composer: Composer<TOut, TOut, {}>) => Composer<TOut, UOut, any>): EventComposer<TBase, TEventMap, TIn, TOut & Partial<Omit<UOut, keyof TOut>>, TExposed, TDerives>;
|
|
164
|
-
error(kind: string, errorClass: {
|
|
165
|
-
new (...args: any): any;
|
|
166
|
-
prototype: Error;
|
|
167
|
-
}): this;
|
|
168
|
-
as(scope: "scoped" | "global"): EventComposer<TBase, TEventMap, TIn, TOut, TOut, TDerives>;
|
|
169
|
-
group(fn: (composer: Composer<TOut, TOut, {}>) => void): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives>;
|
|
170
|
-
extend<UIn extends TBase, UOut extends UIn, UExposed extends object, UDerives extends Record<string, object>>(other: EventComposer<TBase, TEventMap, UIn, UOut, UExposed, UDerives>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives & UDerives>;
|
|
171
|
-
extend<UIn extends object, UOut extends UIn, UExposed extends object>(other: Composer<UIn, UOut, UExposed>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives>;
|
|
167
|
+
}, TMethods> & TMethods;
|
|
168
|
+
when<UOut extends TOut>(condition: boolean, fn: (composer: Composer<TOut, TOut, {}>) => Composer<TOut, UOut, any>): EventComposer<TBase, TEventMap, TIn, TOut & Partial<Omit<UOut, keyof TOut>>, TExposed, TDerives, TMethods> & TMethods;
|
|
169
|
+
as(scope: "scoped" | "global"): EventComposer<TBase, TEventMap, TIn, TOut, TOut, TDerives, TMethods> & TMethods;
|
|
170
|
+
extend<UIn extends TBase, UOut extends UIn, UExposed extends object, UDerives extends Record<string, object>>(other: EventComposer<TBase, TEventMap, UIn, UOut, UExposed, UDerives, any>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives & UDerives, TMethods> & TMethods;
|
|
171
|
+
extend<UIn extends object, UOut extends UIn, UExposed extends object>(other: Composer<UIn, UOut, UExposed>): EventComposer<TBase, TEventMap, TIn, TOut & UExposed, TExposed, TDerives, TMethods> & TMethods;
|
|
172
172
|
inspect(): MiddlewareInfo[];
|
|
173
173
|
trace(handler: TraceHandler): this;
|
|
174
174
|
compose(): ComposedMiddleware<TIn>;
|
|
@@ -189,16 +189,33 @@ interface EventComposer<TBase extends object, TEventMap extends Record<string, T
|
|
|
189
189
|
};
|
|
190
190
|
invalidate(): void;
|
|
191
191
|
}
|
|
192
|
-
interface EventComposerConstructor<TBase extends object, TEventMap extends Record<string, TBase
|
|
193
|
-
new <TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}>(options?: ComposerOptions): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives
|
|
192
|
+
interface EventComposerConstructor<TBase extends object, TEventMap extends Record<string, TBase>, TMethods extends Record<string, (...args: any[]) => any> = {}> {
|
|
193
|
+
new <TIn extends TBase = TBase, TOut extends TIn = TIn, TExposed extends object = {}, TDerives extends Record<string, object> = {}>(options?: ComposerOptions): EventComposer<TBase, TEventMap, TIn, TOut, TExposed, TDerives, TMethods> & TMethods;
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Phantom type carrier for event map inference.
|
|
197
|
+
* Returns `undefined` at runtime — exists purely for type-level inference
|
|
198
|
+
* so that `TEventMap` can be inferred from the `types` config field.
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* const { Composer } = createComposer({
|
|
203
|
+
* discriminator: (ctx: BaseCtx) => ctx.updateType,
|
|
204
|
+
* types: eventTypes<EventMap>(),
|
|
205
|
+
* methods: { hears(trigger) { return this.on("message", ...); } },
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
declare function eventTypes<TEventMap extends Record<string, any>>(): TEventMap;
|
|
195
210
|
/**
|
|
196
211
|
* Creates a configured Composer class with type-safe .on() event discrimination.
|
|
197
212
|
*/
|
|
198
|
-
declare function createComposer<TBase extends object, TEventMap extends Record<string, TBase> = {}>(config: {
|
|
213
|
+
declare function createComposer<TBase extends object, TEventMap extends Record<string, TBase> = {}, TMethods extends Record<string, (...args: any[]) => any> = {}>(config: {
|
|
199
214
|
discriminator: (context: TBase) => string;
|
|
215
|
+
types?: TEventMap;
|
|
216
|
+
methods?: TMethods & ThisType<EventComposer<TBase, TEventMap, TBase, TBase, {}, {}, TMethods> & TMethods>;
|
|
200
217
|
}): {
|
|
201
|
-
Composer: EventComposerConstructor<TBase, TEventMap>;
|
|
218
|
+
Composer: EventComposerConstructor<TBase, TEventMap, TMethods>;
|
|
202
219
|
compose: typeof compose;
|
|
203
220
|
EventQueue: typeof EventQueue;
|
|
204
221
|
};
|
|
@@ -210,5 +227,5 @@ declare const skip: Middleware<any>;
|
|
|
210
227
|
/** Terminal middleware: does NOT call next() */
|
|
211
228
|
declare const stop: Middleware<any>;
|
|
212
229
|
|
|
213
|
-
export { Composer, EventQueue, compose, createComposer, noopNext, skip, stop };
|
|
230
|
+
export { Composer, EventQueue, compose, createComposer, eventTypes, noopNext, skip, stop };
|
|
214
231
|
export type { ComposedMiddleware, ComposerOptions, DeriveHandler, ErrorHandler, EventComposer, EventComposerConstructor, LazyFactory, MaybeArray, Middleware, MiddlewareInfo, MiddlewareType, Next, RouteBuilder, RouteHandler, Scope, TraceHandler };
|
package/dist/index.js
CHANGED
|
@@ -308,15 +308,23 @@ class Composer {
|
|
|
308
308
|
if (this["~"].extended.has(key)) return this;
|
|
309
309
|
this["~"].extended.add(key);
|
|
310
310
|
}
|
|
311
|
+
const alreadyExtended = new Set(this["~"].extended);
|
|
311
312
|
for (const key of other["~"].extended) {
|
|
312
313
|
this["~"].extended.add(key);
|
|
313
314
|
}
|
|
314
315
|
Object.assign(this["~"].errorsDefinitions, other["~"].errorsDefinitions);
|
|
315
316
|
this["~"].onErrors.push(...other["~"].onErrors);
|
|
316
317
|
const pluginName = other["~"].name;
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
318
|
+
const isNew = (m) => {
|
|
319
|
+
if (!m.plugin) return true;
|
|
320
|
+
for (const key of alreadyExtended) {
|
|
321
|
+
if (key.startsWith(m.plugin + ":")) return false;
|
|
322
|
+
}
|
|
323
|
+
return true;
|
|
324
|
+
};
|
|
325
|
+
const localMws = other["~"].middlewares.filter((m) => m.scope === "local" && isNew(m));
|
|
326
|
+
const scopedMws = other["~"].middlewares.filter((m) => m.scope === "scoped" && isNew(m));
|
|
327
|
+
const globalMws = other["~"].middlewares.filter((m) => m.scope === "global" && isNew(m));
|
|
320
328
|
if (localMws.length > 0) {
|
|
321
329
|
const chain = compose(localMws.map((m) => m.fn));
|
|
322
330
|
const isolated = async (ctx, next) => {
|
|
@@ -464,6 +472,9 @@ class EventQueue {
|
|
|
464
472
|
}
|
|
465
473
|
}
|
|
466
474
|
|
|
475
|
+
function eventTypes() {
|
|
476
|
+
return void 0;
|
|
477
|
+
}
|
|
467
478
|
function createComposer(config) {
|
|
468
479
|
class EventComposerImpl extends Composer {
|
|
469
480
|
on(event, handler) {
|
|
@@ -501,6 +512,19 @@ function createComposer(config) {
|
|
|
501
512
|
return this;
|
|
502
513
|
}
|
|
503
514
|
}
|
|
515
|
+
if (config.methods) {
|
|
516
|
+
for (const [name, fn] of Object.entries(config.methods)) {
|
|
517
|
+
if (name in EventComposerImpl.prototype) {
|
|
518
|
+
throw new Error(`Custom method "${name}" conflicts with built-in method`);
|
|
519
|
+
}
|
|
520
|
+
Object.defineProperty(EventComposerImpl.prototype, name, {
|
|
521
|
+
value: fn,
|
|
522
|
+
writable: true,
|
|
523
|
+
configurable: true,
|
|
524
|
+
enumerable: false
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
}
|
|
504
528
|
return {
|
|
505
529
|
Composer: EventComposerImpl,
|
|
506
530
|
compose,
|
|
@@ -508,4 +532,4 @@ function createComposer(config) {
|
|
|
508
532
|
};
|
|
509
533
|
}
|
|
510
534
|
|
|
511
|
-
export { Composer, EventQueue, compose, createComposer, noopNext, skip, stop };
|
|
535
|
+
export { Composer, EventQueue, compose, createComposer, eventTypes, noopNext, skip, stop };
|