@tgify/tgify 0.1.0 → 0.1.4

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 (42) hide show
  1. package/LICENSE +23 -23
  2. package/README.md +356 -356
  3. package/lib/cli.mjs +9 -9
  4. package/package.json +1 -1
  5. package/src/button.ts +182 -182
  6. package/src/composer.ts +1008 -1008
  7. package/src/context.ts +1661 -1661
  8. package/src/core/helpers/args.ts +63 -63
  9. package/src/core/helpers/check.ts +71 -71
  10. package/src/core/helpers/compact.ts +18 -18
  11. package/src/core/helpers/deunionize.ts +26 -26
  12. package/src/core/helpers/formatting.ts +119 -119
  13. package/src/core/helpers/util.ts +96 -96
  14. package/src/core/network/client.ts +396 -396
  15. package/src/core/network/error.ts +29 -29
  16. package/src/core/network/multipart-stream.ts +45 -45
  17. package/src/core/network/polling.ts +94 -94
  18. package/src/core/network/webhook.ts +58 -58
  19. package/src/core/types/typegram.ts +54 -54
  20. package/src/filters.ts +109 -109
  21. package/src/format.ts +110 -110
  22. package/src/future.ts +213 -213
  23. package/src/index.ts +17 -17
  24. package/src/input.ts +59 -59
  25. package/src/markup.ts +142 -142
  26. package/src/middleware.ts +24 -24
  27. package/src/reactions.ts +118 -118
  28. package/src/router.ts +55 -55
  29. package/src/scenes/base.ts +52 -52
  30. package/src/scenes/context.ts +136 -136
  31. package/src/scenes/index.ts +21 -21
  32. package/src/scenes/stage.ts +71 -71
  33. package/src/scenes/wizard/context.ts +58 -58
  34. package/src/scenes/wizard/index.ts +63 -63
  35. package/src/scenes.ts +1 -1
  36. package/src/session.ts +204 -204
  37. package/src/telegraf.ts +354 -354
  38. package/src/telegram-types.ts +219 -219
  39. package/src/telegram.ts +1635 -1635
  40. package/src/types.ts +2 -2
  41. package/src/utils.ts +1 -1
  42. package/typings/telegraf.d.ts.map +1 -1
package/src/markup.ts CHANGED
@@ -1,142 +1,142 @@
1
- import {
2
- ForceReply,
3
- InlineKeyboardButton,
4
- InlineKeyboardMarkup,
5
- KeyboardButton,
6
- ReplyKeyboardMarkup,
7
- ReplyKeyboardRemove,
8
- } from './core/types/typegram'
9
- import { is2D } from './core/helpers/check'
10
-
11
- type Hideable<B> = B & { hide?: boolean }
12
- type HideableKBtn = Hideable<KeyboardButton>
13
- type HideableIKBtn = Hideable<InlineKeyboardButton>
14
-
15
- export class Markup<
16
- T extends
17
- | InlineKeyboardMarkup
18
- | ReplyKeyboardMarkup
19
- | ReplyKeyboardRemove
20
- | ForceReply,
21
- > {
22
- constructor(readonly reply_markup: T) {}
23
-
24
- selective<T extends ForceReply | ReplyKeyboardMarkup>(
25
- this: Markup<T>,
26
- value = true
27
- ) {
28
- return new Markup<T>({ ...this.reply_markup, selective: value })
29
- }
30
-
31
- placeholder<T extends ForceReply | ReplyKeyboardMarkup>(
32
- this: Markup<T>,
33
- placeholder: string
34
- ) {
35
- return new Markup<T>({
36
- ...this.reply_markup,
37
- input_field_placeholder: placeholder,
38
- })
39
- }
40
-
41
- resize(this: Markup<ReplyKeyboardMarkup>, value = true) {
42
- return new Markup<ReplyKeyboardMarkup>({
43
- ...this.reply_markup,
44
- resize_keyboard: value,
45
- })
46
- }
47
-
48
- oneTime(this: Markup<ReplyKeyboardMarkup>, value = true) {
49
- return new Markup<ReplyKeyboardMarkup>({
50
- ...this.reply_markup,
51
- one_time_keyboard: value,
52
- })
53
- }
54
-
55
- persistent(this: Markup<ReplyKeyboardMarkup>, value = true) {
56
- return new Markup<ReplyKeyboardMarkup>({
57
- ...this.reply_markup,
58
- is_persistent: value,
59
- })
60
- }
61
- }
62
-
63
- export * as button from './button'
64
-
65
- export function removeKeyboard(): Markup<ReplyKeyboardRemove> {
66
- return new Markup<ReplyKeyboardRemove>({ remove_keyboard: true })
67
- }
68
-
69
- export function forceReply(): Markup<ForceReply> {
70
- return new Markup<ForceReply>({ force_reply: true })
71
- }
72
-
73
- export function keyboard(buttons: HideableKBtn[][]): Markup<ReplyKeyboardMarkup>
74
- export function keyboard(
75
- buttons: HideableKBtn[],
76
- options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
77
- ): Markup<ReplyKeyboardMarkup>
78
- export function keyboard(
79
- buttons: HideableKBtn[] | HideableKBtn[][],
80
- options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
81
- ): Markup<ReplyKeyboardMarkup> {
82
- const keyboard = buildKeyboard(buttons, {
83
- columns: 1,
84
- ...options,
85
- })
86
- return new Markup<ReplyKeyboardMarkup>({ keyboard })
87
- }
88
-
89
- export function inlineKeyboard(
90
- buttons: HideableIKBtn[][]
91
- ): Markup<InlineKeyboardMarkup>
92
- export function inlineKeyboard(
93
- buttons: HideableIKBtn[],
94
- options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
95
- ): Markup<InlineKeyboardMarkup>
96
- export function inlineKeyboard(
97
- buttons: HideableIKBtn[] | HideableIKBtn[][],
98
- options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
99
- ): Markup<InlineKeyboardMarkup> {
100
- const inlineKeyboard = buildKeyboard(buttons, {
101
- columns: buttons.length,
102
- ...options,
103
- })
104
- return new Markup<InlineKeyboardMarkup>({ inline_keyboard: inlineKeyboard })
105
- }
106
-
107
- interface KeyboardBuildingOptions<B extends HideableKBtn | HideableIKBtn> {
108
- wrap?: (btn: B, index: number, currentRow: B[]) => boolean
109
- columns: number
110
- }
111
-
112
- function buildKeyboard<B extends HideableKBtn | HideableIKBtn>(
113
- buttons: B[] | B[][],
114
- options: KeyboardBuildingOptions<B>
115
- ): B[][] {
116
- const result: B[][] = []
117
- if (!Array.isArray(buttons)) {
118
- return result
119
- }
120
- if (is2D(buttons)) {
121
- return buttons.map((row) => row.filter((button) => !button.hide))
122
- }
123
- const wrapFn =
124
- options.wrap !== undefined
125
- ? options.wrap
126
- : (_btn: B, _index: number, currentRow: B[]) =>
127
- currentRow.length >= options.columns
128
- let currentRow: B[] = []
129
- let index = 0
130
- for (const btn of buttons.filter((button) => !button.hide)) {
131
- if (wrapFn(btn, index, currentRow) && currentRow.length > 0) {
132
- result.push(currentRow)
133
- currentRow = []
134
- }
135
- currentRow.push(btn)
136
- index++
137
- }
138
- if (currentRow.length > 0) {
139
- result.push(currentRow)
140
- }
141
- return result
142
- }
1
+ import {
2
+ ForceReply,
3
+ InlineKeyboardButton,
4
+ InlineKeyboardMarkup,
5
+ KeyboardButton,
6
+ ReplyKeyboardMarkup,
7
+ ReplyKeyboardRemove,
8
+ } from './core/types/typegram'
9
+ import { is2D } from './core/helpers/check'
10
+
11
+ type Hideable<B> = B & { hide?: boolean }
12
+ type HideableKBtn = Hideable<KeyboardButton>
13
+ type HideableIKBtn = Hideable<InlineKeyboardButton>
14
+
15
+ export class Markup<
16
+ T extends
17
+ | InlineKeyboardMarkup
18
+ | ReplyKeyboardMarkup
19
+ | ReplyKeyboardRemove
20
+ | ForceReply,
21
+ > {
22
+ constructor(readonly reply_markup: T) {}
23
+
24
+ selective<T extends ForceReply | ReplyKeyboardMarkup>(
25
+ this: Markup<T>,
26
+ value = true
27
+ ) {
28
+ return new Markup<T>({ ...this.reply_markup, selective: value })
29
+ }
30
+
31
+ placeholder<T extends ForceReply | ReplyKeyboardMarkup>(
32
+ this: Markup<T>,
33
+ placeholder: string
34
+ ) {
35
+ return new Markup<T>({
36
+ ...this.reply_markup,
37
+ input_field_placeholder: placeholder,
38
+ })
39
+ }
40
+
41
+ resize(this: Markup<ReplyKeyboardMarkup>, value = true) {
42
+ return new Markup<ReplyKeyboardMarkup>({
43
+ ...this.reply_markup,
44
+ resize_keyboard: value,
45
+ })
46
+ }
47
+
48
+ oneTime(this: Markup<ReplyKeyboardMarkup>, value = true) {
49
+ return new Markup<ReplyKeyboardMarkup>({
50
+ ...this.reply_markup,
51
+ one_time_keyboard: value,
52
+ })
53
+ }
54
+
55
+ persistent(this: Markup<ReplyKeyboardMarkup>, value = true) {
56
+ return new Markup<ReplyKeyboardMarkup>({
57
+ ...this.reply_markup,
58
+ is_persistent: value,
59
+ })
60
+ }
61
+ }
62
+
63
+ export * as button from './button'
64
+
65
+ export function removeKeyboard(): Markup<ReplyKeyboardRemove> {
66
+ return new Markup<ReplyKeyboardRemove>({ remove_keyboard: true })
67
+ }
68
+
69
+ export function forceReply(): Markup<ForceReply> {
70
+ return new Markup<ForceReply>({ force_reply: true })
71
+ }
72
+
73
+ export function keyboard(buttons: HideableKBtn[][]): Markup<ReplyKeyboardMarkup>
74
+ export function keyboard(
75
+ buttons: HideableKBtn[],
76
+ options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
77
+ ): Markup<ReplyKeyboardMarkup>
78
+ export function keyboard(
79
+ buttons: HideableKBtn[] | HideableKBtn[][],
80
+ options?: Partial<KeyboardBuildingOptions<HideableKBtn>>
81
+ ): Markup<ReplyKeyboardMarkup> {
82
+ const keyboard = buildKeyboard(buttons, {
83
+ columns: 1,
84
+ ...options,
85
+ })
86
+ return new Markup<ReplyKeyboardMarkup>({ keyboard })
87
+ }
88
+
89
+ export function inlineKeyboard(
90
+ buttons: HideableIKBtn[][]
91
+ ): Markup<InlineKeyboardMarkup>
92
+ export function inlineKeyboard(
93
+ buttons: HideableIKBtn[],
94
+ options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
95
+ ): Markup<InlineKeyboardMarkup>
96
+ export function inlineKeyboard(
97
+ buttons: HideableIKBtn[] | HideableIKBtn[][],
98
+ options?: Partial<KeyboardBuildingOptions<HideableIKBtn>>
99
+ ): Markup<InlineKeyboardMarkup> {
100
+ const inlineKeyboard = buildKeyboard(buttons, {
101
+ columns: buttons.length,
102
+ ...options,
103
+ })
104
+ return new Markup<InlineKeyboardMarkup>({ inline_keyboard: inlineKeyboard })
105
+ }
106
+
107
+ interface KeyboardBuildingOptions<B extends HideableKBtn | HideableIKBtn> {
108
+ wrap?: (btn: B, index: number, currentRow: B[]) => boolean
109
+ columns: number
110
+ }
111
+
112
+ function buildKeyboard<B extends HideableKBtn | HideableIKBtn>(
113
+ buttons: B[] | B[][],
114
+ options: KeyboardBuildingOptions<B>
115
+ ): B[][] {
116
+ const result: B[][] = []
117
+ if (!Array.isArray(buttons)) {
118
+ return result
119
+ }
120
+ if (is2D(buttons)) {
121
+ return buttons.map((row) => row.filter((button) => !button.hide))
122
+ }
123
+ const wrapFn =
124
+ options.wrap !== undefined
125
+ ? options.wrap
126
+ : (_btn: B, _index: number, currentRow: B[]) =>
127
+ currentRow.length >= options.columns
128
+ let currentRow: B[] = []
129
+ let index = 0
130
+ for (const btn of buttons.filter((button) => !button.hide)) {
131
+ if (wrapFn(btn, index, currentRow) && currentRow.length > 0) {
132
+ result.push(currentRow)
133
+ currentRow = []
134
+ }
135
+ currentRow.push(btn)
136
+ index++
137
+ }
138
+ if (currentRow.length > 0) {
139
+ result.push(currentRow)
140
+ }
141
+ return result
142
+ }
package/src/middleware.ts CHANGED
@@ -1,24 +1,24 @@
1
- import { Context } from './context'
2
- import { Update } from './core/types/typegram'
3
-
4
- /*
5
- next's parameter is in a contravariant position, and thus, trying to type it
6
- prevents assigning `MiddlewareFn<ContextMessageUpdate>`
7
- to `MiddlewareFn<CustomContext>`.
8
- Middleware passing the parameter should be a separate type instead.
9
- */
10
- export type MiddlewareFn<C extends Context<U>, U extends Update = Update> = (
11
- ctx: C,
12
- next: () => Promise<void>
13
- ) => Promise<unknown> | void
14
-
15
- export interface MiddlewareObj<
16
- C extends Context<U>,
17
- U extends Update = Update,
18
- > {
19
- middleware: () => MiddlewareFn<C, U>
20
- }
21
-
22
- export type Middleware<C extends Context<U>, U extends Update = Update> =
23
- | MiddlewareFn<C, U>
24
- | MiddlewareObj<C, U>
1
+ import { Context } from './context'
2
+ import { Update } from './core/types/typegram'
3
+
4
+ /*
5
+ next's parameter is in a contravariant position, and thus, trying to type it
6
+ prevents assigning `MiddlewareFn<ContextMessageUpdate>`
7
+ to `MiddlewareFn<CustomContext>`.
8
+ Middleware passing the parameter should be a separate type instead.
9
+ */
10
+ export type MiddlewareFn<C extends Context<U>, U extends Update = Update> = (
11
+ ctx: C,
12
+ next: () => Promise<void>
13
+ ) => Promise<unknown> | void
14
+
15
+ export interface MiddlewareObj<
16
+ C extends Context<U>,
17
+ U extends Update = Update,
18
+ > {
19
+ middleware: () => MiddlewareFn<C, U>
20
+ }
21
+
22
+ export type Middleware<C extends Context<U>, U extends Update = Update> =
23
+ | MiddlewareFn<C, U>
24
+ | MiddlewareObj<C, U>
package/src/reactions.ts CHANGED
@@ -1,118 +1,118 @@
1
- import { Deunionize } from './core/helpers/deunionize'
2
- import { indexed } from './core/helpers/util'
3
- import * as tg from './core/types/typegram'
4
-
5
- export type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
6
- export const Digit = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])
7
- export type Reaction =
8
- | tg.TelegramEmoji
9
- | `${Digit}${string}`
10
- | Deunionize<tg.ReactionType>
11
-
12
- type ReactionCtx = { update: Partial<tg.Update.MessageReactionUpdate> }
13
-
14
- const inspectReaction = (reaction: tg.ReactionType) => {
15
- if (reaction.type === 'custom_emoji')
16
- return `Custom(${reaction.custom_emoji_id})`
17
- else return reaction.emoji
18
- }
19
-
20
- export class ReactionList {
21
- // this is a lie, proxy will be used to access the properties
22
- [index: number]: Deunionize<tg.ReactionType>
23
-
24
- protected constructor(protected list: tg.ReactionType[]) {}
25
-
26
- static fromArray(list: tg.ReactionType[] = []): ReactionList {
27
- return indexed(
28
- new ReactionList(list),
29
- function (this: ReactionList, index) {
30
- return this.list[index]
31
- }
32
- )
33
- }
34
-
35
- static has(reactions: tg.ReactionType[], reaction: Reaction): boolean {
36
- if (typeof reaction === 'string')
37
- if (Digit.has(reaction[0] as string))
38
- return reactions.some(
39
- (r: Deunionize<tg.ReactionType>) => r.custom_emoji_id === reaction
40
- )
41
- else
42
- return reactions.some(
43
- (r: Deunionize<tg.ReactionType>) => r.emoji === reaction
44
- )
45
-
46
- return reactions.some((r: Deunionize<tg.ReactionType>) => {
47
- if (r.type === 'custom_emoji')
48
- return r.custom_emoji_id === reaction.custom_emoji_id
49
- else if (r.type === 'emoji') return r.emoji === reaction.emoji
50
- })
51
- }
52
-
53
- toArray(): tg.ReactionType[] {
54
- return [...this.list]
55
- }
56
-
57
- filter(
58
- filterFn: (value: tg.ReactionType, index: number) => boolean
59
- ): ReactionList {
60
- return ReactionList.fromArray(this.list.filter(filterFn))
61
- }
62
-
63
- has(reaction: Reaction): boolean {
64
- return ReactionList.has(this.list, reaction)
65
- }
66
-
67
- get count(): number {
68
- return this.list.length
69
- }
70
-
71
- [Symbol.iterator]() {
72
- return this.list[Symbol.iterator]()
73
- }
74
-
75
- [Symbol.for('nodejs.util.inspect.custom')]() {
76
- const flattened = this.list.map(inspectReaction).join(', ')
77
- return ['ReactionList {', flattened, '}'].join(' ')
78
- }
79
- }
80
-
81
- export class MessageReactions extends ReactionList {
82
- private constructor(public ctx: ReactionCtx) {
83
- super(ctx.update.message_reaction?.new_reaction ?? [])
84
- }
85
-
86
- static from(ctx: ReactionCtx) {
87
- return indexed(
88
- new MessageReactions(ctx),
89
- function (this: MessageReactions, index) {
90
- return this.list[index]
91
- }
92
- )
93
- }
94
-
95
- get old() {
96
- return ReactionList.fromArray(
97
- this.ctx.update.message_reaction?.old_reaction
98
- )
99
- }
100
-
101
- get new() {
102
- return ReactionList.fromArray(
103
- this.ctx.update.message_reaction?.new_reaction
104
- )
105
- }
106
-
107
- get added(): ReactionList {
108
- return this.new.filter((reaction) => !this.old.has(reaction))
109
- }
110
-
111
- get removed(): ReactionList {
112
- return this.old.filter((reaction) => !this.new.has(reaction))
113
- }
114
-
115
- get kept(): ReactionList {
116
- return this.new.filter((reaction) => this.old.has(reaction))
117
- }
118
- }
1
+ import { Deunionize } from './core/helpers/deunionize'
2
+ import { indexed } from './core/helpers/util'
3
+ import * as tg from './core/types/typegram'
4
+
5
+ export type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
6
+ export const Digit = new Set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])
7
+ export type Reaction =
8
+ | tg.TelegramEmoji
9
+ | `${Digit}${string}`
10
+ | Deunionize<tg.ReactionType>
11
+
12
+ type ReactionCtx = { update: Partial<tg.Update.MessageReactionUpdate> }
13
+
14
+ const inspectReaction = (reaction: tg.ReactionType) => {
15
+ if (reaction.type === 'custom_emoji')
16
+ return `Custom(${reaction.custom_emoji_id})`
17
+ else return reaction.emoji
18
+ }
19
+
20
+ export class ReactionList {
21
+ // this is a lie, proxy will be used to access the properties
22
+ [index: number]: Deunionize<tg.ReactionType>
23
+
24
+ protected constructor(protected list: tg.ReactionType[]) {}
25
+
26
+ static fromArray(list: tg.ReactionType[] = []): ReactionList {
27
+ return indexed(
28
+ new ReactionList(list),
29
+ function (this: ReactionList, index) {
30
+ return this.list[index]
31
+ }
32
+ )
33
+ }
34
+
35
+ static has(reactions: tg.ReactionType[], reaction: Reaction): boolean {
36
+ if (typeof reaction === 'string')
37
+ if (Digit.has(reaction[0] as string))
38
+ return reactions.some(
39
+ (r: Deunionize<tg.ReactionType>) => r.custom_emoji_id === reaction
40
+ )
41
+ else
42
+ return reactions.some(
43
+ (r: Deunionize<tg.ReactionType>) => r.emoji === reaction
44
+ )
45
+
46
+ return reactions.some((r: Deunionize<tg.ReactionType>) => {
47
+ if (r.type === 'custom_emoji')
48
+ return r.custom_emoji_id === reaction.custom_emoji_id
49
+ else if (r.type === 'emoji') return r.emoji === reaction.emoji
50
+ })
51
+ }
52
+
53
+ toArray(): tg.ReactionType[] {
54
+ return [...this.list]
55
+ }
56
+
57
+ filter(
58
+ filterFn: (value: tg.ReactionType, index: number) => boolean
59
+ ): ReactionList {
60
+ return ReactionList.fromArray(this.list.filter(filterFn))
61
+ }
62
+
63
+ has(reaction: Reaction): boolean {
64
+ return ReactionList.has(this.list, reaction)
65
+ }
66
+
67
+ get count(): number {
68
+ return this.list.length
69
+ }
70
+
71
+ [Symbol.iterator]() {
72
+ return this.list[Symbol.iterator]()
73
+ }
74
+
75
+ [Symbol.for('nodejs.util.inspect.custom')]() {
76
+ const flattened = this.list.map(inspectReaction).join(', ')
77
+ return ['ReactionList {', flattened, '}'].join(' ')
78
+ }
79
+ }
80
+
81
+ export class MessageReactions extends ReactionList {
82
+ private constructor(public ctx: ReactionCtx) {
83
+ super(ctx.update.message_reaction?.new_reaction ?? [])
84
+ }
85
+
86
+ static from(ctx: ReactionCtx) {
87
+ return indexed(
88
+ new MessageReactions(ctx),
89
+ function (this: MessageReactions, index) {
90
+ return this.list[index]
91
+ }
92
+ )
93
+ }
94
+
95
+ get old() {
96
+ return ReactionList.fromArray(
97
+ this.ctx.update.message_reaction?.old_reaction
98
+ )
99
+ }
100
+
101
+ get new() {
102
+ return ReactionList.fromArray(
103
+ this.ctx.update.message_reaction?.new_reaction
104
+ )
105
+ }
106
+
107
+ get added(): ReactionList {
108
+ return this.new.filter((reaction) => !this.old.has(reaction))
109
+ }
110
+
111
+ get removed(): ReactionList {
112
+ return this.old.filter((reaction) => !this.new.has(reaction))
113
+ }
114
+
115
+ get kept(): ReactionList {
116
+ return this.new.filter((reaction) => this.old.has(reaction))
117
+ }
118
+ }
package/src/router.ts CHANGED
@@ -1,55 +1,55 @@
1
- /** @format */
2
-
3
- import { Middleware, MiddlewareObj } from './middleware'
4
- import Composer from './composer'
5
- import Context from './context'
6
-
7
- type NonemptyReadonlyArray<T> = readonly [T, ...T[]]
8
-
9
- type RouteFn<TContext extends Context> = (ctx: TContext) => {
10
- route: string
11
- context?: Partial<TContext>
12
- state?: Partial<TContext['state']>
13
- } | null
14
-
15
- /** @deprecated in favor of {@link Composer.dispatch} */
16
- export class Router<C extends Context> implements MiddlewareObj<C> {
17
- private otherwiseHandler: Middleware<C> = Composer.passThru()
18
-
19
- constructor(
20
- private readonly routeFn: RouteFn<C>,
21
- public handlers = new Map<string, Middleware<C>>()
22
- ) {
23
- if (typeof routeFn !== 'function') {
24
- throw new Error('Missing routing function')
25
- }
26
- }
27
-
28
- on(route: string, ...fns: NonemptyReadonlyArray<Middleware<C>>) {
29
- if (fns.length === 0) {
30
- throw new TypeError('At least one handler must be provided')
31
- }
32
- this.handlers.set(route, Composer.compose(fns))
33
- return this
34
- }
35
-
36
- otherwise(...fns: NonemptyReadonlyArray<Middleware<C>>) {
37
- if (fns.length === 0) {
38
- throw new TypeError('At least one otherwise handler must be provided')
39
- }
40
- this.otherwiseHandler = Composer.compose(fns)
41
- return this
42
- }
43
-
44
- middleware() {
45
- return Composer.lazy<C>((ctx) => {
46
- const result = this.routeFn(ctx)
47
- if (result == null) {
48
- return this.otherwiseHandler
49
- }
50
- Object.assign(ctx, result.context)
51
- Object.assign(ctx.state, result.state)
52
- return this.handlers.get(result.route) ?? this.otherwiseHandler
53
- })
54
- }
55
- }
1
+ /** @format */
2
+
3
+ import { Middleware, MiddlewareObj } from './middleware'
4
+ import Composer from './composer'
5
+ import Context from './context'
6
+
7
+ type NonemptyReadonlyArray<T> = readonly [T, ...T[]]
8
+
9
+ type RouteFn<TContext extends Context> = (ctx: TContext) => {
10
+ route: string
11
+ context?: Partial<TContext>
12
+ state?: Partial<TContext['state']>
13
+ } | null
14
+
15
+ /** @deprecated in favor of {@link Composer.dispatch} */
16
+ export class Router<C extends Context> implements MiddlewareObj<C> {
17
+ private otherwiseHandler: Middleware<C> = Composer.passThru()
18
+
19
+ constructor(
20
+ private readonly routeFn: RouteFn<C>,
21
+ public handlers = new Map<string, Middleware<C>>()
22
+ ) {
23
+ if (typeof routeFn !== 'function') {
24
+ throw new Error('Missing routing function')
25
+ }
26
+ }
27
+
28
+ on(route: string, ...fns: NonemptyReadonlyArray<Middleware<C>>) {
29
+ if (fns.length === 0) {
30
+ throw new TypeError('At least one handler must be provided')
31
+ }
32
+ this.handlers.set(route, Composer.compose(fns))
33
+ return this
34
+ }
35
+
36
+ otherwise(...fns: NonemptyReadonlyArray<Middleware<C>>) {
37
+ if (fns.length === 0) {
38
+ throw new TypeError('At least one otherwise handler must be provided')
39
+ }
40
+ this.otherwiseHandler = Composer.compose(fns)
41
+ return this
42
+ }
43
+
44
+ middleware() {
45
+ return Composer.lazy<C>((ctx) => {
46
+ const result = this.routeFn(ctx)
47
+ if (result == null) {
48
+ return this.otherwiseHandler
49
+ }
50
+ Object.assign(ctx, result.context)
51
+ Object.assign(ctx.state, result.state)
52
+ return this.handlers.get(result.route) ?? this.otherwiseHandler
53
+ })
54
+ }
55
+ }