telemeister 0.1.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.
Files changed (133) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +460 -0
  3. package/bin/telemeister.js +18 -0
  4. package/dist/bot/polling.d.ts +20 -0
  5. package/dist/bot/polling.d.ts.map +1 -0
  6. package/dist/bot/polling.js +115 -0
  7. package/dist/bot/polling.js.map +1 -0
  8. package/dist/bot/session.d.ts +50 -0
  9. package/dist/bot/session.d.ts.map +1 -0
  10. package/dist/bot/session.js +92 -0
  11. package/dist/bot/session.js.map +1 -0
  12. package/dist/bot/webhook.d.ts +36 -0
  13. package/dist/bot/webhook.d.ts.map +1 -0
  14. package/dist/bot/webhook.js +199 -0
  15. package/dist/bot/webhook.js.map +1 -0
  16. package/dist/bot-state-types.d.ts +10 -0
  17. package/dist/bot-state-types.d.ts.map +1 -0
  18. package/dist/bot-state-types.js +3 -0
  19. package/dist/bot-state-types.js.map +1 -0
  20. package/dist/cli/cli.d.ts +14 -0
  21. package/dist/cli/cli.d.ts.map +1 -0
  22. package/dist/cli/cli.js +57 -0
  23. package/dist/cli/cli.js.map +1 -0
  24. package/dist/cli/create-bot.d.ts +5 -0
  25. package/dist/cli/create-bot.d.ts.map +1 -0
  26. package/dist/cli/create-bot.js +275 -0
  27. package/dist/cli/create-bot.js.map +1 -0
  28. package/dist/cli/index.d.ts +4 -0
  29. package/dist/cli/index.d.ts.map +1 -0
  30. package/dist/cli/index.js +4 -0
  31. package/dist/cli/index.js.map +1 -0
  32. package/dist/cli/state-manager.d.ts +9 -0
  33. package/dist/cli/state-manager.d.ts.map +1 -0
  34. package/dist/cli/state-manager.js +381 -0
  35. package/dist/cli/state-manager.js.map +1 -0
  36. package/dist/config.d.ts +24 -0
  37. package/dist/config.d.ts.map +1 -0
  38. package/dist/config.js +52 -0
  39. package/dist/config.js.map +1 -0
  40. package/dist/core/app-states.d.ts +8 -0
  41. package/dist/core/app-states.d.ts.map +1 -0
  42. package/dist/core/app-states.js +8 -0
  43. package/dist/core/app-states.js.map +1 -0
  44. package/dist/core/builder.d.ts +138 -0
  45. package/dist/core/builder.d.ts.map +1 -0
  46. package/dist/core/builder.js +195 -0
  47. package/dist/core/builder.js.map +1 -0
  48. package/dist/core/compact-machine.d.ts +57 -0
  49. package/dist/core/compact-machine.d.ts.map +1 -0
  50. package/dist/core/compact-machine.js +113 -0
  51. package/dist/core/compact-machine.js.map +1 -0
  52. package/dist/core/index.d.ts +13 -0
  53. package/dist/core/index.d.ts.map +1 -0
  54. package/dist/core/index.js +9 -0
  55. package/dist/core/index.js.map +1 -0
  56. package/dist/core/types.d.ts +47 -0
  57. package/dist/core/types.d.ts.map +1 -0
  58. package/dist/core/types.js +3 -0
  59. package/dist/core/types.js.map +1 -0
  60. package/dist/database.d.ts +43 -0
  61. package/dist/database.d.ts.map +1 -0
  62. package/dist/database.js +127 -0
  63. package/dist/database.js.map +1 -0
  64. package/dist/generated/prisma/browser.d.ts +15 -0
  65. package/dist/generated/prisma/browser.d.ts.map +1 -0
  66. package/dist/generated/prisma/browser.js +18 -0
  67. package/dist/generated/prisma/browser.js.map +1 -0
  68. package/dist/generated/prisma/client.d.ts +32 -0
  69. package/dist/generated/prisma/client.d.ts.map +1 -0
  70. package/dist/generated/prisma/client.js +33 -0
  71. package/dist/generated/prisma/client.js.map +1 -0
  72. package/dist/generated/prisma/commonInputTypes.d.ts +166 -0
  73. package/dist/generated/prisma/commonInputTypes.d.ts.map +1 -0
  74. package/dist/generated/prisma/commonInputTypes.js +11 -0
  75. package/dist/generated/prisma/commonInputTypes.js.map +1 -0
  76. package/dist/generated/prisma/enums.d.ts +2 -0
  77. package/dist/generated/prisma/enums.d.ts.map +1 -0
  78. package/dist/generated/prisma/enums.js +11 -0
  79. package/dist/generated/prisma/enums.js.map +1 -0
  80. package/dist/generated/prisma/internal/class.d.ts +138 -0
  81. package/dist/generated/prisma/internal/class.d.ts.map +1 -0
  82. package/dist/generated/prisma/internal/class.js +50 -0
  83. package/dist/generated/prisma/internal/class.js.map +1 -0
  84. package/dist/generated/prisma/internal/prismaNamespace.d.ts +591 -0
  85. package/dist/generated/prisma/internal/prismaNamespace.d.ts.map +1 -0
  86. package/dist/generated/prisma/internal/prismaNamespace.js +96 -0
  87. package/dist/generated/prisma/internal/prismaNamespace.js.map +1 -0
  88. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +56 -0
  89. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -0
  90. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +67 -0
  91. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -0
  92. package/dist/generated/prisma/models/User.d.ts +1181 -0
  93. package/dist/generated/prisma/models/User.d.ts.map +1 -0
  94. package/dist/generated/prisma/models/User.js +2 -0
  95. package/dist/generated/prisma/models/User.js.map +1 -0
  96. package/dist/generated/prisma/models/UserInfo.d.ts +1101 -0
  97. package/dist/generated/prisma/models/UserInfo.d.ts.map +1 -0
  98. package/dist/generated/prisma/models/UserInfo.js +2 -0
  99. package/dist/generated/prisma/models/UserInfo.js.map +1 -0
  100. package/dist/generated/prisma/models.d.ts +4 -0
  101. package/dist/generated/prisma/models.d.ts.map +1 -0
  102. package/dist/generated/prisma/models.js +2 -0
  103. package/dist/generated/prisma/models.js.map +1 -0
  104. package/dist/handlers/idle/index.d.ts +2 -0
  105. package/dist/handlers/idle/index.d.ts.map +1 -0
  106. package/dist/handlers/idle/index.js +22 -0
  107. package/dist/handlers/idle/index.js.map +1 -0
  108. package/dist/handlers/index.d.ts +12 -0
  109. package/dist/handlers/index.d.ts.map +1 -0
  110. package/dist/handlers/index.js +14 -0
  111. package/dist/handlers/index.js.map +1 -0
  112. package/dist/handlers/menu/index.d.ts +2 -0
  113. package/dist/handlers/menu/index.d.ts.map +1 -0
  114. package/dist/handlers/menu/index.js +35 -0
  115. package/dist/handlers/menu/index.js.map +1 -0
  116. package/dist/handlers/menu.d.ts +2 -0
  117. package/dist/handlers/menu.d.ts.map +1 -0
  118. package/dist/handlers/menu.js +37 -0
  119. package/dist/handlers/menu.js.map +1 -0
  120. package/dist/handlers/welcome/index.d.ts +2 -0
  121. package/dist/handlers/welcome/index.d.ts.map +1 -0
  122. package/dist/handlers/welcome/index.js +22 -0
  123. package/dist/handlers/welcome/index.js.map +1 -0
  124. package/dist/handlers/welcome.d.ts +2 -0
  125. package/dist/handlers/welcome.d.ts.map +1 -0
  126. package/dist/handlers/welcome.js +30 -0
  127. package/dist/handlers/welcome.js.map +1 -0
  128. package/dist/index.d.ts +3 -0
  129. package/dist/index.d.ts.map +1 -0
  130. package/dist/index.js +39 -0
  131. package/dist/index.js.map +1 -0
  132. package/package.json +111 -0
  133. package/templates/handler.ts.ejs +36 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * State Builder - Fluent API for configuring a single state
3
+ *
4
+ * @template TState - Union type of all valid states
5
+ */
6
+ class StateBuilder {
7
+ state;
8
+ handlers;
9
+ constructor(state, handlers) {
10
+ this.state = state;
11
+ this.handlers = handlers;
12
+ }
13
+ /**
14
+ * Set the onEnter handler for this state
15
+ * Called when the user enters this state
16
+ * Can optionally return a state name to immediately transition to
17
+ *
18
+ * Example:
19
+ * .onEnter(async (ctx) => {
20
+ * await ctx.send('Welcome!');
21
+ * // Optionally transition immediately:
22
+ * return 'anotherState';
23
+ * })
24
+ */
25
+ onEnter(handler) {
26
+ const existing = this.handlers.get(this.state) || {};
27
+ existing.onEnter = handler;
28
+ this.handlers.set(this.state, existing);
29
+ return this;
30
+ }
31
+ /**
32
+ * Set the onResponse handler for this state
33
+ * Called when the user sends a message while in this state
34
+ *
35
+ * Example:
36
+ * .onResponse(async (ctx, response) => {
37
+ * if (response === 'yes') {
38
+ * return 'confirmed';
39
+ * }
40
+ * return 'cancelled';
41
+ * })
42
+ */
43
+ onResponse(handler) {
44
+ const existing = this.handlers.get(this.state) || {};
45
+ existing.onResponse = handler;
46
+ this.handlers.set(this.state, existing);
47
+ return this;
48
+ }
49
+ }
50
+ /**
51
+ * Multi-State Builder - Registers handlers for multiple states at once
52
+ *
53
+ * @template TState - Union type of all valid states
54
+ */
55
+ class MultiStateBuilder {
56
+ states;
57
+ handlers;
58
+ constructor(states, handlers) {
59
+ this.states = states;
60
+ this.handlers = handlers;
61
+ }
62
+ onEnter(handler) {
63
+ for (const state of this.states) {
64
+ const existing = this.handlers.get(state) || {};
65
+ existing.onEnter = handler;
66
+ this.handlers.set(state, existing);
67
+ }
68
+ return this;
69
+ }
70
+ onResponse(handler) {
71
+ for (const state of this.states) {
72
+ const existing = this.handlers.get(state) || {};
73
+ existing.onResponse = handler;
74
+ this.handlers.set(state, existing);
75
+ }
76
+ return this;
77
+ }
78
+ }
79
+ /**
80
+ * Bot Builder - Main API for registering state handlers
81
+ *
82
+ * For type-safe state returns, define your states as a union type:
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // Define your states
87
+ * type MyStates = 'idle' | 'welcome' | 'menu' | 'collectName';
88
+ *
89
+ * // Create typed builder
90
+ * const typedBuilder = botBuilder as BotBuilder<MyStates>;
91
+ *
92
+ * typedBuilder
93
+ * .forState('welcome')
94
+ * .onEnter(async (ctx) => {
95
+ * await ctx.send('Welcome!');
96
+ * return 'menu'; // ✅ Type-safe: only 'idle' | 'welcome' | 'menu' | 'collectName' allowed
97
+ * })
98
+ * .onResponse(async (ctx, response) => {
99
+ * return 'collectName'; // ✅ Also type-safe
100
+ * });
101
+ * ```
102
+ *
103
+ * @template TState - Union type of all valid states (defaults to string)
104
+ */
105
+ export class BotBuilder {
106
+ handlers = new Map();
107
+ forState(state) {
108
+ if (Array.isArray(state)) {
109
+ return new MultiStateBuilder(state, this.handlers);
110
+ }
111
+ return new StateBuilder(state, this.handlers);
112
+ }
113
+ /**
114
+ * Register an onEnter handler for a state
115
+ * @param state - State name
116
+ * @param handler - Handler function
117
+ * @returns this for chaining
118
+ */
119
+ onEnter(state, handler) {
120
+ const existing = this.handlers.get(state) || {};
121
+ existing.onEnter = handler;
122
+ this.handlers.set(state, existing);
123
+ return this;
124
+ }
125
+ /**
126
+ * Register an onResponse handler for a state
127
+ * @param state - State name
128
+ * @param handler - Handler function
129
+ * @returns this for chaining
130
+ */
131
+ onResponse(state, handler) {
132
+ const existing = this.handlers.get(state) || {};
133
+ existing.onResponse = handler;
134
+ this.handlers.set(state, existing);
135
+ return this;
136
+ }
137
+ /**
138
+ * Execute the onEnter handler for a given state
139
+ * @internal Called by the bot handlers
140
+ * @returns The next state to transition to (if any), or void
141
+ */
142
+ async executeOnEnter(state, context) {
143
+ const handlers = this.handlers.get(state);
144
+ const handler = handlers?.onEnter;
145
+ if (handler) {
146
+ return await handler(context);
147
+ }
148
+ }
149
+ /**
150
+ * Execute the onResponse handler for a given state
151
+ * @internal Called by the bot handlers
152
+ * @returns The next state to transition to, or void
153
+ */
154
+ async executeOnResponse(state, context, response) {
155
+ const handlers = this.handlers.get(state);
156
+ const handler = handlers?.onResponse;
157
+ if (handler) {
158
+ return await handler(context, response);
159
+ }
160
+ }
161
+ /**
162
+ * Check if a state has an onEnter handler
163
+ */
164
+ hasOnEnter(state) {
165
+ return !!this.handlers.get(state)?.onEnter;
166
+ }
167
+ /**
168
+ * Check if a state has an onResponse handler
169
+ */
170
+ hasOnResponse(state) {
171
+ return !!this.handlers.get(state)?.onResponse;
172
+ }
173
+ /**
174
+ * Get all registered state names
175
+ */
176
+ getRegisteredStates() {
177
+ return Array.from(this.handlers.keys());
178
+ }
179
+ /**
180
+ * Get handlers for a specific state
181
+ */
182
+ getHandlers(state) {
183
+ return this.handlers.get(state);
184
+ }
185
+ }
186
+ /**
187
+ * Global bot builder instance (untyped - accepts any string state)
188
+ *
189
+ * For type safety, cast to BotBuilder<YourStateUnion>:
190
+ * ```typescript
191
+ * const typedBuilder = botBuilder as BotBuilder<'idle' | 'welcome' | 'menu'>;
192
+ * ```
193
+ */
194
+ export const botBuilder = new BotBuilder();
195
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/core/builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { BotContext, BotMachineInput } from './types.js';
2
+ /**
3
+ * Compact XState Machine for Telemeister
4
+ *
5
+ * Uses the "states as data" pattern - a single state node handles
6
+ * all bot states. The actual state value is stored in context.currentState.
7
+ *
8
+ * Benefits:
9
+ * - No need to modify machine when adding new states
10
+ * - Compact, maintainable code
11
+ * - Builder pattern is the source of truth for valid states
12
+ * - Re-entry triggers onEnter handler for new states
13
+ */
14
+ export declare const compactMachine: import("xstate").StateMachine<BotContext, {
15
+ type: "USER_MESSAGE";
16
+ message: string;
17
+ } | {
18
+ type: "TRANSITION";
19
+ toState: string;
20
+ } | {
21
+ type: "REENTER";
22
+ }, {}, never, {
23
+ type: "updateState";
24
+ params: import("xstate").NonReducibleUnknown;
25
+ } | {
26
+ type: "persistState";
27
+ params: unknown;
28
+ }, never, never, "active", string, BotMachineInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
29
+ id: "telemeister-bot";
30
+ states: {
31
+ readonly active: {};
32
+ };
33
+ }>;
34
+ /**
35
+ * Create a new machine instance with the given initial state
36
+ */
37
+ export declare function createBotMachine(_input: BotMachineInput): import("xstate").StateMachine<BotContext, {
38
+ type: "USER_MESSAGE";
39
+ message: string;
40
+ } | {
41
+ type: "TRANSITION";
42
+ toState: string;
43
+ } | {
44
+ type: "REENTER";
45
+ }, {}, never, {
46
+ type: "updateState";
47
+ params: import("xstate").NonReducibleUnknown;
48
+ } | {
49
+ type: "persistState";
50
+ params: unknown;
51
+ }, never, never, "active", string, BotMachineInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
52
+ id: "telemeister-bot";
53
+ states: {
54
+ readonly active: {};
55
+ };
56
+ }>;
57
+ //# sourceMappingURL=compact-machine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-machine.d.ts","sourceRoot":"","sources":["../../src/core/compact-machine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAY,eAAe,EAAE,MAAM,YAAY,CAAC;AAExE;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;EAqDzB,CAAC;AAEH;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe;;;;;;;;;;;;;;;;;;;GA0CvD"}
@@ -0,0 +1,113 @@
1
+ import { setup, assign } from 'xstate';
2
+ /**
3
+ * Compact XState Machine for Telemeister
4
+ *
5
+ * Uses the "states as data" pattern - a single state node handles
6
+ * all bot states. The actual state value is stored in context.currentState.
7
+ *
8
+ * Benefits:
9
+ * - No need to modify machine when adding new states
10
+ * - Compact, maintainable code
11
+ * - Builder pattern is the source of truth for valid states
12
+ * - Re-entry triggers onEnter handler for new states
13
+ */
14
+ export const compactMachine = setup({
15
+ types: {
16
+ context: {},
17
+ events: {},
18
+ input: {},
19
+ },
20
+ actions: {
21
+ /**
22
+ * Update the current state in context
23
+ */
24
+ updateState: assign({
25
+ currentState: ({ event }) => (event.type === 'TRANSITION' ? event.toState : ''),
26
+ }),
27
+ /**
28
+ * Persist state to database
29
+ * This is called as an action, but actual DB calls happen
30
+ * in the bot handlers to keep the machine pure.
31
+ */
32
+ persistState: ({ context }) => {
33
+ // The actual persistence is handled by the bot layer
34
+ // This action serves as a hook for inspection/logging
35
+ console.log(`[XState] State changed to: ${context.currentState}`);
36
+ },
37
+ },
38
+ }).createMachine({
39
+ id: 'telemeister-bot',
40
+ initial: 'active',
41
+ context: ({ input: _input }) => ({
42
+ userId: _input.userId,
43
+ telegramId: _input.telegramId,
44
+ chatId: _input.chatId,
45
+ currentState: _input.currentState,
46
+ stateData: _input.stateData,
47
+ }),
48
+ states: {
49
+ active: {
50
+ entry: ['persistState'],
51
+ on: {
52
+ TRANSITION: {
53
+ actions: ['updateState', 'persistState'],
54
+ // Self-transition with reentry to trigger onEnter
55
+ target: 'active',
56
+ reenter: true,
57
+ },
58
+ REENTER: {
59
+ // Re-enter current state (e.g., to re-trigger onEnter)
60
+ target: 'active',
61
+ reenter: true,
62
+ },
63
+ },
64
+ },
65
+ },
66
+ });
67
+ /**
68
+ * Create a new machine instance with the given initial state
69
+ */
70
+ export function createBotMachine(_input) {
71
+ return setup({
72
+ types: {
73
+ context: {},
74
+ events: {},
75
+ input: {},
76
+ },
77
+ actions: {
78
+ updateState: assign({
79
+ currentState: ({ event }) => (event.type === 'TRANSITION' ? event.toState : ''),
80
+ }),
81
+ persistState: ({ context }) => {
82
+ console.log(`[XState] State changed to: ${context.currentState}`);
83
+ },
84
+ },
85
+ }).createMachine({
86
+ id: 'telemeister-bot',
87
+ initial: 'active',
88
+ context: ({ input }) => ({
89
+ userId: input.userId,
90
+ telegramId: input.telegramId,
91
+ chatId: input.chatId,
92
+ currentState: input.currentState,
93
+ stateData: input.stateData,
94
+ }),
95
+ states: {
96
+ active: {
97
+ entry: ['persistState'],
98
+ on: {
99
+ TRANSITION: {
100
+ actions: ['updateState', 'persistState'],
101
+ target: 'active',
102
+ reenter: true,
103
+ },
104
+ REENTER: {
105
+ target: 'active',
106
+ reenter: true,
107
+ },
108
+ },
109
+ },
110
+ },
111
+ });
112
+ }
113
+ //# sourceMappingURL=compact-machine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compact-machine.js","sourceRoot":"","sources":["../../src/core/compact-machine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Core module for Telemeister
3
+ *
4
+ * This module exports the centralized state types and typed builder.
5
+ * Import from here in your handlers for type safety.
6
+ */
7
+ export { BotBuilder, botBuilder } from './builder.js';
8
+ export type { AppStates } from '../bot-state-types.js';
9
+ export type { StateTransitions } from '../bot-state-types.js';
10
+ export { appBuilder } from './types.js';
11
+ export type { AppContext } from './types.js';
12
+ export type { BotHandlerContext, BotState, EnterHandler, ResponseHandler, StateHandlers, } from './types.js';
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEtD,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,YAAY,EACV,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Core module for Telemeister
3
+ *
4
+ * This module exports the centralized state types and typed builder.
5
+ * Import from here in your handlers for type safety.
6
+ */
7
+ export { BotBuilder, botBuilder } from './builder.js';
8
+ export { appBuilder } from './types.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAKtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { AppStates } from '../bot-state-types.js';
2
+ import { BotBuilder } from './builder.js';
3
+ export declare const appBuilder: BotBuilder<AppStates>;
4
+ export type AppContext = BotHandlerContext<AppStates>;
5
+ export type BotState = string;
6
+ export interface BotHandlerContext<TState extends BotState = BotState> {
7
+ userId: number;
8
+ telegramId: number;
9
+ chatId: number;
10
+ currentState: TState;
11
+ send: (text: string) => Promise<unknown>;
12
+ setData: <T>(key: string, value: T) => void;
13
+ getData: <T>(key: string) => T | undefined;
14
+ transition: (toState: TState) => Promise<void>;
15
+ }
16
+ export type EnterHandler<TState extends BotState = BotState> = (context: BotHandlerContext<TState>) => Promise<TState | void>;
17
+ export type ResponseHandler<TState extends BotState = BotState> = (context: BotHandlerContext<TState>, response: string) => Promise<TState | void>;
18
+ export interface StateHandlers<TState extends BotState = BotState> {
19
+ onEnter?: EnterHandler<TState>;
20
+ onResponse?: ResponseHandler<TState>;
21
+ }
22
+ export type ExtractStates<T> = T extends StateHandlers<infer S> ? S : never;
23
+ export interface BotContext {
24
+ userId: number;
25
+ telegramId: number;
26
+ chatId: number;
27
+ currentState: string;
28
+ stateData: Record<string, unknown>;
29
+ }
30
+ export type BotEvent = {
31
+ type: 'USER_MESSAGE';
32
+ message: string;
33
+ } | {
34
+ type: 'TRANSITION';
35
+ toState: string;
36
+ } | {
37
+ type: 'REENTER';
38
+ };
39
+ export interface BotMachineInput {
40
+ userId: number;
41
+ telegramId: number;
42
+ chatId: number;
43
+ currentState: string;
44
+ stateData: Record<string, unknown>;
45
+ }
46
+ export type { StateTransitions } from '../bot-state-types.js';
47
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,eAAO,MAAM,UAAU,uBAA8B,CAAC;AAEtD,MAAM,MAAM,UAAU,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAEtD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,WAAW,iBAAiB,CAAC,MAAM,SAAS,QAAQ,GAAG,QAAQ;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3C,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,YAAY,CAAC,MAAM,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAC7D,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,KAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE5B,MAAM,MAAM,eAAe,CAAC,MAAM,SAAS,QAAQ,GAAG,QAAQ,IAAI,CAChE,OAAO,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAClC,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE5B,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,QAAQ,GAAG,QAAQ;IAC/D,OAAO,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE5E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExB,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { BotBuilder } from './builder.js';
2
+ export const appBuilder = new BotBuilder();
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAa,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Database Entry Point
3
+ *
4
+ * Uses Prisma ORM 7.x with driver adapters for database operations.
5
+ *
6
+ * Switch between SQLite and MySQL by changing DATABASE_URL in .env:
7
+ * - SQLite: DATABASE_URL="file:./dev.db"
8
+ * - MySQL: DATABASE_URL="mysql://user:password@localhost:3306/dbname"
9
+ *
10
+ * Note: When switching providers, update the provider in prisma/schema.prisma:
11
+ * - SQLite: provider = "sqlite"
12
+ * - MySQL: provider = "mysql"
13
+ */
14
+ import 'dotenv/config';
15
+ import { User, UserInfo } from './generated/prisma/client.js';
16
+ declare const prisma: import("./generated/prisma/internal/class.js").PrismaClient<never, import("./generated/prisma/internal/prismaNamespace.js").GlobalOmitConfig | undefined, import("@prisma/client/runtime/client").DefaultArgs>;
17
+ export type { User, UserInfo };
18
+ export type UserWithInfo = User & {
19
+ info: UserInfo | null;
20
+ };
21
+ /**
22
+ * Get user by Telegram ID with joined user info
23
+ */
24
+ export declare function getUserByTelegramId(telegramId: number): Promise<UserWithInfo | null>;
25
+ /**
26
+ * Create or update a user
27
+ */
28
+ export declare function createOrUpdateUser(data: {
29
+ telegramId: number;
30
+ chatId: number;
31
+ currentState?: string;
32
+ stateData?: Record<string, unknown>;
33
+ }): Promise<UserWithInfo>;
34
+ /**
35
+ * Update user state and optional state data
36
+ */
37
+ export declare function updateUserState(telegramId: number, currentState: string, stateData?: Record<string, unknown>): Promise<void>;
38
+ /**
39
+ * Disconnect from database
40
+ */
41
+ export declare function disconnectDB(): Promise<void>;
42
+ export { prisma };
43
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAgB,IAAI,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAmB5E,QAAA,MAAM,MAAM,gNAAgC,CAAC;AAG7C,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAG/B,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG;IAChC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAO1F;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,GAAG,OAAO,CAAC,YAAY,CAAC,CAkDxB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Database Entry Point
3
+ *
4
+ * Uses Prisma ORM 7.x with driver adapters for database operations.
5
+ *
6
+ * Switch between SQLite and MySQL by changing DATABASE_URL in .env:
7
+ * - SQLite: DATABASE_URL="file:./dev.db"
8
+ * - MySQL: DATABASE_URL="mysql://user:password@localhost:3306/dbname"
9
+ *
10
+ * Note: When switching providers, update the provider in prisma/schema.prisma:
11
+ * - SQLite: provider = "sqlite"
12
+ * - MySQL: provider = "mysql"
13
+ */
14
+ import 'dotenv/config';
15
+ import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3';
16
+ import { PrismaClient } from './generated/prisma/client.js';
17
+ // Determine database provider from URL
18
+ const databaseUrl = process.env.DATABASE_URL || 'file:./dev.db';
19
+ const isMysql = databaseUrl.startsWith('mysql:');
20
+ // Create adapter based on database type
21
+ // For now, SQLite is fully supported. MySQL adapter requires additional setup.
22
+ const adapter = isMysql
23
+ ? (() => {
24
+ throw new Error('MySQL adapter not yet configured. Please configure @prisma/adapter-mariadb in src/database.ts');
25
+ })()
26
+ : new PrismaBetterSqlite3({
27
+ url: databaseUrl,
28
+ });
29
+ // Prisma client instance with adapter
30
+ const prisma = new PrismaClient({ adapter });
31
+ /**
32
+ * Get user by Telegram ID with joined user info
33
+ */
34
+ export async function getUserByTelegramId(telegramId) {
35
+ const user = await prisma.user.findUnique({
36
+ where: { telegramId },
37
+ include: { info: true },
38
+ });
39
+ return user;
40
+ }
41
+ /**
42
+ * Create or update a user
43
+ */
44
+ export async function createOrUpdateUser(data) {
45
+ const existingUser = await getUserByTelegramId(data.telegramId);
46
+ if (existingUser) {
47
+ // Update existing user
48
+ const updatedUser = await prisma.user.update({
49
+ where: { telegramId: data.telegramId },
50
+ data: {
51
+ chatId: data.chatId,
52
+ ...(data.currentState && { currentState: data.currentState }),
53
+ },
54
+ include: { info: true },
55
+ });
56
+ // Update or create user info if stateData provided
57
+ if (data.stateData) {
58
+ await prisma.userInfo.upsert({
59
+ where: { userId: updatedUser.id },
60
+ create: {
61
+ userId: updatedUser.id,
62
+ stateData: JSON.stringify(data.stateData),
63
+ },
64
+ update: {
65
+ stateData: JSON.stringify(data.stateData),
66
+ },
67
+ });
68
+ // Return updated user with info
69
+ return (await getUserByTelegramId(data.telegramId));
70
+ }
71
+ return updatedUser;
72
+ }
73
+ else {
74
+ // Create new user with info
75
+ const newUser = await prisma.user.create({
76
+ data: {
77
+ telegramId: data.telegramId,
78
+ chatId: data.chatId,
79
+ currentState: data.currentState || 'idle',
80
+ info: {
81
+ create: {
82
+ stateData: JSON.stringify(data.stateData || {}),
83
+ },
84
+ },
85
+ },
86
+ include: { info: true },
87
+ });
88
+ return newUser;
89
+ }
90
+ }
91
+ /**
92
+ * Update user state and optional state data
93
+ */
94
+ export async function updateUserState(telegramId, currentState, stateData) {
95
+ const user = await prisma.user.findUnique({
96
+ where: { telegramId },
97
+ });
98
+ if (!user) {
99
+ throw new Error(`User with telegramId ${telegramId} not found`);
100
+ }
101
+ // Update user state
102
+ await prisma.user.update({
103
+ where: { telegramId },
104
+ data: { currentState },
105
+ });
106
+ // Update state data if provided
107
+ if (stateData) {
108
+ await prisma.userInfo.upsert({
109
+ where: { userId: user.id },
110
+ create: {
111
+ userId: user.id,
112
+ stateData: JSON.stringify(stateData),
113
+ },
114
+ update: {
115
+ stateData: JSON.stringify(stateData),
116
+ },
117
+ });
118
+ }
119
+ }
120
+ /**
121
+ * Disconnect from database
122
+ */
123
+ export async function disconnectDB() {
124
+ await prisma.$disconnect();
125
+ }
126
+ export { prisma };
127
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAkB,MAAM,8BAA8B,CAAC;AAE5E,uCAAuC;AACvC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,eAAe,CAAC;AAChE,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AAEjD,wCAAwC;AACxC,+EAA+E;AAC/E,MAAM,OAAO,GAAG,OAAO;IACrB,CAAC,CAAC,CAAC,GAAG,EAAE;QACJ,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAC;IACJ,CAAC,CAAC,EAAE;IACN,CAAC,CAAC,IAAI,mBAAmB,CAAC;QACtB,GAAG,EAAE,WAAW;KACjB,CAAC,CAAC;AAEP,sCAAsC;AACtC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;AAU7C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAkB;IAC1D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;QACxC,KAAK,EAAE,EAAE,UAAU,EAAE;QACrB,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;KACxB,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAKxC;IACC,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEhE,IAAI,YAAY,EAAE,CAAC;QACjB,uBAAuB;QACvB,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC3C,KAAK,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;YACtC,IAAI,EAAE;gBACJ,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;aAC9D;YACD,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;SACxB,CAAC,CAAC;QAEH,mDAAmD;QACnD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC3B,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE;gBACjC,MAAM,EAAE;oBACN,MAAM,EAAE,WAAW,CAAC,EAAE;oBACtB,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;iBAC1C;gBACD,MAAM,EAAE;oBACN,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC;iBAC1C;aACF,CAAC,CAAC;YAEH,gCAAgC;YAChC,OAAO,CAAC,MAAM,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAE,CAAC;QACvD,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;SAAM,CAAC;QACN,4BAA4B;QAC5B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACvC,IAAI,EAAE;gBACJ,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,MAAM;gBACzC,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;qBAChD;iBACF;aACF;YACD,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;SACxB,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,YAAoB,EACpB,SAAmC;IAEnC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;QACxC,KAAK,EAAE,EAAE,UAAU,EAAE;KACtB,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,YAAY,CAAC,CAAC;IAClE,CAAC;IAED,oBAAoB;IACpB,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACvB,KAAK,EAAE,EAAE,UAAU,EAAE;QACrB,IAAI,EAAE,EAAE,YAAY,EAAE;KACvB,CAAC,CAAC;IAEH,gCAAgC;IAChC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC3B,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE;YAC1B,MAAM,EAAE;gBACN,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;aACrC;YACD,MAAM,EAAE;gBACN,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;aACrC;SACF,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}