@adriangalilea/utils 0.17.1 → 0.19.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 (97) hide show
  1. package/README.md +9 -9
  2. package/dist/bot/access-control.d.ts.map +1 -1
  3. package/dist/bot/access-control.js +62 -45
  4. package/dist/bot/access-control.js.map +1 -1
  5. package/dist/bot/callbacks.d.ts +89 -0
  6. package/dist/bot/callbacks.d.ts.map +1 -0
  7. package/dist/bot/callbacks.js +128 -0
  8. package/dist/bot/callbacks.js.map +1 -0
  9. package/dist/bot/ctx.d.ts +219 -0
  10. package/dist/bot/ctx.d.ts.map +1 -0
  11. package/dist/bot/ctx.js +52 -0
  12. package/dist/bot/ctx.js.map +1 -0
  13. package/dist/bot/index.d.ts +4 -0
  14. package/dist/bot/index.d.ts.map +1 -1
  15. package/dist/bot/index.js +4 -0
  16. package/dist/bot/index.js.map +1 -1
  17. package/dist/bot/kit.d.ts +93 -41
  18. package/dist/bot/kit.d.ts.map +1 -1
  19. package/dist/bot/kit.js +153 -30
  20. package/dist/bot/kit.js.map +1 -1
  21. package/dist/bot/menu.d.ts +31 -11
  22. package/dist/bot/menu.d.ts.map +1 -1
  23. package/dist/bot/menu.js +34 -9
  24. package/dist/bot/menu.js.map +1 -1
  25. package/dist/bot/payments/callbacks.d.ts +28 -0
  26. package/dist/bot/payments/callbacks.d.ts.map +1 -0
  27. package/dist/bot/payments/callbacks.js +102 -0
  28. package/dist/bot/payments/callbacks.js.map +1 -0
  29. package/dist/bot/payments/commands.d.ts +26 -0
  30. package/dist/bot/payments/commands.d.ts.map +1 -0
  31. package/dist/bot/payments/commands.js +41 -0
  32. package/dist/bot/payments/commands.js.map +1 -0
  33. package/dist/bot/payments/config.d.ts +30 -0
  34. package/dist/bot/payments/config.d.ts.map +1 -0
  35. package/dist/bot/payments/config.js +166 -0
  36. package/dist/bot/payments/config.js.map +1 -0
  37. package/dist/bot/payments/derive.d.ts +75 -0
  38. package/dist/bot/payments/derive.d.ts.map +1 -0
  39. package/dist/bot/payments/derive.js +151 -0
  40. package/dist/bot/payments/derive.js.map +1 -0
  41. package/dist/bot/payments/handlers.d.ts +113 -0
  42. package/dist/bot/payments/handlers.d.ts.map +1 -0
  43. package/dist/bot/payments/handlers.js +284 -0
  44. package/dist/bot/payments/handlers.js.map +1 -0
  45. package/dist/bot/payments/index.d.ts +17 -0
  46. package/dist/bot/payments/index.d.ts.map +1 -0
  47. package/dist/bot/payments/index.js +14 -0
  48. package/dist/bot/payments/index.js.map +1 -0
  49. package/dist/bot/payments/invoice.d.ts +101 -0
  50. package/dist/bot/payments/invoice.d.ts.map +1 -0
  51. package/dist/bot/payments/invoice.js +213 -0
  52. package/dist/bot/payments/invoice.js.map +1 -0
  53. package/dist/bot/payments/menu-item.d.ts +41 -0
  54. package/dist/bot/payments/menu-item.d.ts.map +1 -0
  55. package/dist/bot/payments/menu-item.js +259 -0
  56. package/dist/bot/payments/menu-item.js.map +1 -0
  57. package/dist/bot/payments/payload.d.ts +42 -0
  58. package/dist/bot/payments/payload.d.ts.map +1 -0
  59. package/dist/bot/payments/payload.js +69 -0
  60. package/dist/bot/payments/payload.js.map +1 -0
  61. package/dist/bot/payments/payouts.d.ts +88 -0
  62. package/dist/bot/payments/payouts.d.ts.map +1 -0
  63. package/dist/bot/payments/payouts.js +133 -0
  64. package/dist/bot/payments/payouts.js.map +1 -0
  65. package/dist/bot/payments/plugin.d.ts +271 -0
  66. package/dist/bot/payments/plugin.d.ts.map +1 -0
  67. package/dist/bot/payments/plugin.js +141 -0
  68. package/dist/bot/payments/plugin.js.map +1 -0
  69. package/dist/bot/payments/refund.d.ts +124 -0
  70. package/dist/bot/payments/refund.d.ts.map +1 -0
  71. package/dist/bot/payments/refund.js +308 -0
  72. package/dist/bot/payments/refund.js.map +1 -0
  73. package/dist/bot/payments/schemas.d.ts +58 -0
  74. package/dist/bot/payments/schemas.d.ts.map +1 -0
  75. package/dist/bot/payments/schemas.js +55 -0
  76. package/dist/bot/payments/schemas.js.map +1 -0
  77. package/dist/bot/payments/state.d.ts +90 -0
  78. package/dist/bot/payments/state.d.ts.map +1 -0
  79. package/dist/bot/payments/state.js +149 -0
  80. package/dist/bot/payments/state.js.map +1 -0
  81. package/dist/bot/payments/stores.d.ts +44 -0
  82. package/dist/bot/payments/stores.d.ts.map +1 -0
  83. package/dist/bot/payments/stores.js +39 -0
  84. package/dist/bot/payments/stores.js.map +1 -0
  85. package/dist/bot/payments/types.d.ts +299 -0
  86. package/dist/bot/payments/types.d.ts.map +1 -0
  87. package/dist/bot/payments/types.js +39 -0
  88. package/dist/bot/payments/types.js.map +1 -0
  89. package/dist/bot/payments/waiver.d.ts +81 -0
  90. package/dist/bot/payments/waiver.d.ts.map +1 -0
  91. package/dist/bot/payments/waiver.js +145 -0
  92. package/dist/bot/payments/waiver.js.map +1 -0
  93. package/dist/bot/storage.d.ts +154 -0
  94. package/dist/bot/storage.d.ts.map +1 -0
  95. package/dist/bot/storage.js +222 -0
  96. package/dist/bot/storage.js.map +1 -0
  97. package/package.json +24 -3
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Namespaced callback-data registry.
3
+ *
4
+ * gramio's `CallbackData` schemas are dispatched by name (hashed to a
5
+ * 6-char prefix on the wire). When multiple plugins each declare their
6
+ * own short schema names (`payWcs`, `acA`, `mNav`, …) two real risks
7
+ * accumulate:
8
+ *
9
+ * 1. **Cross-plugin name collision.** A future plugin picks a name
10
+ * another plugin already uses and gramio dispatches to the wrong
11
+ * handler. Silent.
12
+ *
13
+ * 2. **Drift in name shape.** Each plugin invents its own
14
+ * abbreviation style. `payWcs` vs `pay_w_consent` vs
15
+ * `payments:waiver:consent` — no convention.
16
+ *
17
+ * `callbackNs(prefix)` solves both:
18
+ *
19
+ * - Reserves a prefix per plugin (`pay`, `ac`, `m`, …) so names
20
+ * can't collide across plugins by construction (`pay:wcs` is
21
+ * disjoint from `ac:wcs`).
22
+ *
23
+ * - Maintains a process-wide `Set<string>` of registered fully-
24
+ * qualified names. A second registration of the same name with
25
+ * conflicting field shape throws at construction (loud + early);
26
+ * an identical re-registration is idempotent (HMR / dual-import
27
+ * safe).
28
+ *
29
+ * The encoded callback_data length is unaffected — gramio hashes the
30
+ * full name to a 6-char prefix regardless of how long the name is. So
31
+ * `pay:waiver:consent` packs as compactly as `pwc`.
32
+ *
33
+ * ## Usage
34
+ *
35
+ * ```ts
36
+ * // src/bot/payments/waiver.ts
37
+ * import { callbackNs } from "../callbacks.js";
38
+ *
39
+ * const cb = callbackNs("pay");
40
+ *
41
+ * export const waiverConsent = cb.data("waiver:consent", { pk: "string" });
42
+ * export const waiverCancel = cb.data("waiver:cancel", {});
43
+ *
44
+ * // usage matches gramio's CallbackData verbatim — same .pack / .unpack:
45
+ * waiverConsent.pack({ pk: "vip.1" })
46
+ * bot.callbackQuery(waiverConsent, (ctx) => { ctx.queryData.pk })
47
+ * ```
48
+ */
49
+ import { CallbackData } from "gramio";
50
+ import { panic } from "../offensive.js";
51
+ /** Process-wide registry of every fully-qualified schema name we've seen. */
52
+ const registry = new Map();
53
+ const fieldsEqual = (a, b) => {
54
+ const aKeys = Object.keys(a);
55
+ const bKeys = Object.keys(b);
56
+ if (aKeys.length !== bKeys.length)
57
+ return false;
58
+ for (const k of aKeys)
59
+ if (a[k] !== b[k])
60
+ return false;
61
+ return true;
62
+ };
63
+ const buildCallbackData = (fullName, fields) => {
64
+ let cb = new CallbackData(fullName);
65
+ for (const [key, type] of Object.entries(fields)) {
66
+ const optional = type.endsWith("?");
67
+ const base = optional ? type.slice(0, -1) : type;
68
+ if (base === "string") {
69
+ cb = cb.string(key, optional ? { optional: true } : undefined);
70
+ }
71
+ else {
72
+ cb = cb.number(key, optional ? { optional: true } : undefined);
73
+ }
74
+ }
75
+ return cb;
76
+ };
77
+ /**
78
+ * Reserve a callback-data prefix for a plugin. Returns a namespace
79
+ * with a `data(name, fields)` factory.
80
+ *
81
+ * Prefix must be `[a-z][a-z0-9]*` — lowercased letter + alphanumerics,
82
+ * no separator chars. Names within a namespace can use `:` for
83
+ * sub-grouping (`waiver:consent`, `refund:approve`).
84
+ */
85
+ export const callbackNs = (prefix) => {
86
+ if (!/^[a-z][a-z0-9]*$/.test(prefix)) {
87
+ panic(`bot/callbacks: callbackNs prefix "${prefix}" must match /^[a-z][a-z0-9]*$/ — ` +
88
+ `lowercased letter + alphanumerics, no colons or hyphens.`);
89
+ }
90
+ return {
91
+ prefix,
92
+ data: (name, fields) => {
93
+ if (!/^[a-zA-Z][a-zA-Z0-9_:]*$/.test(name)) {
94
+ panic(`bot/callbacks: callback name "${name}" must match /^[a-zA-Z][a-zA-Z0-9_:]*$/`);
95
+ }
96
+ const fullName = `${prefix}:${name}`;
97
+ const existing = registry.get(fullName);
98
+ if (existing) {
99
+ if (!fieldsEqual(existing.fields, fields)) {
100
+ panic(`bot/callbacks: collision — "${fullName}" already registered ` +
101
+ `with different fields ${JSON.stringify(existing.fields)}; ` +
102
+ `re-registration tried ${JSON.stringify(fields)}.`);
103
+ }
104
+ return existing.cb;
105
+ }
106
+ const cb = buildCallbackData(fullName, fields);
107
+ registry.set(fullName, { fullName, fields, cb });
108
+ return cb;
109
+ },
110
+ };
111
+ };
112
+ // ─── introspection ────────────────────────────────────────────────
113
+ /**
114
+ * Read-only view of every callback schema registered so far. Useful in
115
+ * tests or boot-time sanity checks. Not part of the hot path.
116
+ */
117
+ export const registeredCallbacks = () => Array.from(registry.values(), (r) => ({
118
+ fullName: r.fullName,
119
+ fields: r.fields,
120
+ }));
121
+ /**
122
+ * Internal — for tests that need a clean slate. Don't call from app code.
123
+ * @internal
124
+ */
125
+ export const _resetCallbackRegistry = () => {
126
+ registry.clear();
127
+ };
128
+ //# sourceMappingURL=callbacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callbacks.js","sourceRoot":"","sources":["../../src/bot/callbacks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Canonical structural ctx types every plugin in this package imports.
3
+ *
4
+ * gramio's real `MessageContext` / `CallbackQueryContext` /
5
+ * `SuccessfulPaymentContext` / etc. are fully-typed classes, but to
6
+ * keep this library's handler signatures decoupled from gramio's exact
7
+ * import chain (and to let action callbacks in `bot/menu` stay
8
+ * plugin-agnostic), we declare the **minimum structural shape** each
9
+ * plugin handler needs. Real gramio ctxs satisfy these shapes by duck
10
+ * typing; the `narrow<T>(ctx)` helper documents the unavoidable cast.
11
+ *
12
+ * ## Why this exists
13
+ *
14
+ * Before this file, every plugin repeated the same dozen-line cast at
15
+ * the top of every callback / derive / handler:
16
+ *
17
+ * const c = ctx as unknown as {
18
+ * session: SessionLike; bot: { api: BotApi };
19
+ * from?: { id: number }; answer: (p: { text?: string }) => Promise<unknown>;
20
+ * editText: (text: string) => Promise<unknown>;
21
+ * queryData: { cid: string };
22
+ * };
23
+ *
24
+ * Same shape, redefined in 5 files, drifts independently. This module
25
+ * collects every shape we use into ~5 reusable structural types so the
26
+ * cast becomes `narrow<BotCallbackCtx<MySession, { cid: string }>>(ctx)`.
27
+ *
28
+ * ## What goes here vs the plugin
29
+ *
30
+ * - `bot/ctx.ts` (this file): structural ctx types that match
31
+ * gramio's, plus the `narrow` cast helper. Plugin-agnostic.
32
+ * - Each plugin's own types module: the specific *derives* that plugin
33
+ * adds to ctx (`{ payments: PaymentsApi }`, `{ access: AccessInfo }`,
34
+ * `{ adminId: number; isAdmin: boolean }`). Composed with the
35
+ * canonical ctx via TS intersection.
36
+ */
37
+ import type { Storage } from "@gramio/storage";
38
+ /** Minimum ctx shape needed by storage helpers (`bot/storage.ts`) —
39
+ * carries the bot's identity for namespacing. */
40
+ export type BotIdCtx = {
41
+ bot: {
42
+ info: {
43
+ id: number;
44
+ };
45
+ };
46
+ };
47
+ /**
48
+ * Bot API surface — deliberately loose **as a default**. Plugins
49
+ * usually want strict per-method typing (so a typo on
50
+ * `bot.api.refundStarPayment` is a compile error, and the params get
51
+ * type-checked). The canonical ctx types are generic over `Api`, so
52
+ * each plugin specializes:
53
+ *
54
+ * type PaymentBotApi = {
55
+ * answerPreCheckoutQuery: (p: {...}) => Promise<unknown>
56
+ * refundStarPayment: (p: {...}) => Promise<unknown>
57
+ * editUserStarSubscription: (p: {...}) => Promise<unknown>
58
+ * }
59
+ * const c = narrow<BotPaymentCtx<MySession, PaymentBotApi>>(ctx)
60
+ *
61
+ * Default is this loose `BotApi` (any method-name + any params) so
62
+ * places that don't care about strict typing don't have to spell out
63
+ * a full API shape.
64
+ */
65
+ export type BotApi = Record<string, (...args: never[]) => Promise<unknown>>;
66
+ export type BotUser = {
67
+ id: number;
68
+ firstName?: string;
69
+ lastName?: string;
70
+ username?: string;
71
+ languageCode?: string;
72
+ isPremium?: boolean;
73
+ };
74
+ export type BotChat = {
75
+ id: number;
76
+ type: string;
77
+ title?: string;
78
+ username?: string;
79
+ firstName?: string;
80
+ lastName?: string;
81
+ };
82
+ /** Minimum shape we read from a `Message` payload. Includes everything
83
+ * needed for cross-event ctx access (e.g. callback ctx → originating
84
+ * message → chat / thread). */
85
+ export type BotMessage = {
86
+ id?: number;
87
+ chat?: BotChat;
88
+ threadId?: number;
89
+ text?: string;
90
+ delete?: () => Promise<unknown>;
91
+ };
92
+ type SendParams = Record<string, unknown>;
93
+ export type Sender = (text: string | {
94
+ toString(): string;
95
+ }, params?: SendParams) => Promise<{
96
+ message_id: number;
97
+ }>;
98
+ export type Replier = (text: string | {
99
+ toString(): string;
100
+ }, params?: SendParams) => Promise<{
101
+ message_id: number;
102
+ }>;
103
+ export type CallbackAnswerer = (params: {
104
+ text?: string;
105
+ show_alert?: boolean;
106
+ url?: string;
107
+ cache_time?: number;
108
+ }) => Promise<unknown>;
109
+ export type TextEditor = (text: string | {
110
+ toString(): string;
111
+ }, params?: SendParams) => Promise<unknown>;
112
+ /**
113
+ * Generic message-event ctx. `Session` is the shape of the shared
114
+ * session record across all plugins (`{ access?, language?, llm?, pay?,
115
+ * ... }`); pass it as the type parameter at each handler site.
116
+ *
117
+ * Matches gramio's `MessageContext` structurally — a real
118
+ * `MessageContext` is assignable here via duck typing.
119
+ */
120
+ export type BotMessageCtx<Session = Record<string, unknown>, Api extends BotApi = BotApi> = BotIdCtx & {
121
+ bot: {
122
+ info: {
123
+ id: number;
124
+ };
125
+ api: Api;
126
+ };
127
+ from: BotUser;
128
+ chat: BotChat;
129
+ threadId?: number;
130
+ text?: string;
131
+ session: Session;
132
+ send: Sender;
133
+ reply: Replier;
134
+ };
135
+ /**
136
+ * Callback-query ctx. `QueryData` is the unpacked shape of whichever
137
+ * `CallbackData` schema matched (typically `{ cid: string }`,
138
+ * `{ uid: number }`, etc.).
139
+ */
140
+ export type BotCallbackCtx<Session = Record<string, unknown>, QueryData = Record<string, unknown>, Api extends BotApi = BotApi> = BotIdCtx & {
141
+ bot: {
142
+ info: {
143
+ id: number;
144
+ };
145
+ api: Api;
146
+ };
147
+ from: BotUser;
148
+ chat?: BotChat;
149
+ message?: BotMessage;
150
+ threadId?: number;
151
+ session: Session;
152
+ queryData: QueryData;
153
+ answer: CallbackAnswerer;
154
+ editText: TextEditor;
155
+ send: Sender;
156
+ };
157
+ /**
158
+ * `pre_checkout_query` ctx. Different shape from message/callback —
159
+ * the query payload is mixed onto the ctx directly. We expose `bot`
160
+ * for `answerPreCheckoutQuery` calls.
161
+ */
162
+ export type BotPreCheckoutCtx<Api extends BotApi = BotApi> = BotIdCtx & {
163
+ bot: {
164
+ info: {
165
+ id: number;
166
+ };
167
+ api: Api;
168
+ };
169
+ id: string;
170
+ from: BotUser;
171
+ currency: string;
172
+ totalAmount: number;
173
+ invoicePayload: string;
174
+ };
175
+ /**
176
+ * `successful_payment` ctx. Inherits the message-event surface plus
177
+ * gramio's `eventPayment` wrapper. We read `.payload` to get the raw
178
+ * snake_case `TelegramSuccessfulPayment` because every downstream
179
+ * consumer in this package speaks snake_case end-to-end.
180
+ *
181
+ * gramio's `SuccessfulPayment` wrapper is documented in
182
+ * `@gramio/contexts/dist/index.d.ts` around line 2705. The camelCase
183
+ * getters on the wrapper (`telegramPaymentChargeId`, `totalAmount`,
184
+ * `invoicePayload`) are NOT used by this library by convention —
185
+ * stick to one shape (raw snake_case via `.payload`) across all
186
+ * payment handlers to avoid the bug where it's easy to read
187
+ * `payment.telegram_payment_charge_id` on the wrapper and get
188
+ * `undefined`.
189
+ */
190
+ export type BotPaymentCtx<Session = Record<string, unknown>, Api extends BotApi = BotApi> = BotMessageCtx<Session, Api> & {
191
+ eventPayment: {
192
+ payload: {
193
+ currency: string;
194
+ total_amount: number;
195
+ invoice_payload: string;
196
+ telegram_payment_charge_id: string;
197
+ provider_payment_charge_id?: string;
198
+ subscription_expiration_date?: number;
199
+ is_recurring?: true;
200
+ is_first_recurring?: true;
201
+ };
202
+ };
203
+ };
204
+ /**
205
+ * Casts an opaque `unknown` ctx to the structural shape `T` your
206
+ * handler needs. Documents the unavoidable cast that bridges gramio's
207
+ * exact ctx classes to this library's structural shapes.
208
+ *
209
+ * Use over `as unknown as T` so the intent is searchable and reviewers
210
+ * see WHY the cast exists (gramio's MenuCtx / Plugin-derive typing has
211
+ * limits that don't survive cross-plugin composition).
212
+ *
213
+ * const c = narrow<BotCallbackCtx<MySession, { cid: string }>>(ctx)
214
+ *
215
+ * At runtime this is a no-op identity function.
216
+ */
217
+ export declare const narrow: <T>(ctx: unknown) => T;
218
+ export type { Storage };
219
+ //# sourceMappingURL=ctx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx.d.ts","sourceRoot":"","sources":["../../src/bot/ctx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Canonical structural ctx types every plugin in this package imports.
3
+ *
4
+ * gramio's real `MessageContext` / `CallbackQueryContext` /
5
+ * `SuccessfulPaymentContext` / etc. are fully-typed classes, but to
6
+ * keep this library's handler signatures decoupled from gramio's exact
7
+ * import chain (and to let action callbacks in `bot/menu` stay
8
+ * plugin-agnostic), we declare the **minimum structural shape** each
9
+ * plugin handler needs. Real gramio ctxs satisfy these shapes by duck
10
+ * typing; the `narrow<T>(ctx)` helper documents the unavoidable cast.
11
+ *
12
+ * ## Why this exists
13
+ *
14
+ * Before this file, every plugin repeated the same dozen-line cast at
15
+ * the top of every callback / derive / handler:
16
+ *
17
+ * const c = ctx as unknown as {
18
+ * session: SessionLike; bot: { api: BotApi };
19
+ * from?: { id: number }; answer: (p: { text?: string }) => Promise<unknown>;
20
+ * editText: (text: string) => Promise<unknown>;
21
+ * queryData: { cid: string };
22
+ * };
23
+ *
24
+ * Same shape, redefined in 5 files, drifts independently. This module
25
+ * collects every shape we use into ~5 reusable structural types so the
26
+ * cast becomes `narrow<BotCallbackCtx<MySession, { cid: string }>>(ctx)`.
27
+ *
28
+ * ## What goes here vs the plugin
29
+ *
30
+ * - `bot/ctx.ts` (this file): structural ctx types that match
31
+ * gramio's, plus the `narrow` cast helper. Plugin-agnostic.
32
+ * - Each plugin's own types module: the specific *derives* that plugin
33
+ * adds to ctx (`{ payments: PaymentsApi }`, `{ access: AccessInfo }`,
34
+ * `{ adminId: number; isAdmin: boolean }`). Composed with the
35
+ * canonical ctx via TS intersection.
36
+ */
37
+ // ─── narrowing helper ──────────────────────────────────────────────
38
+ /**
39
+ * Casts an opaque `unknown` ctx to the structural shape `T` your
40
+ * handler needs. Documents the unavoidable cast that bridges gramio's
41
+ * exact ctx classes to this library's structural shapes.
42
+ *
43
+ * Use over `as unknown as T` so the intent is searchable and reviewers
44
+ * see WHY the cast exists (gramio's MenuCtx / Plugin-derive typing has
45
+ * limits that don't survive cross-plugin composition).
46
+ *
47
+ * const c = narrow<BotCallbackCtx<MySession, { cid: string }>>(ctx)
48
+ *
49
+ * At runtime this is a no-op identity function.
50
+ */
51
+ export const narrow = (ctx) => ctx;
52
+ //# sourceMappingURL=ctx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ctx.js","sourceRoot":"","sources":["../../src/bot/ctx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AA4LH,sEAAsE;AAEtE;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAI,GAAY,EAAK,EAAE,CAAC,GAAQ,CAAC"}
@@ -12,9 +12,13 @@
12
12
  * import { ... } from '@adriangalilea/utils/bot'
13
13
  */
14
14
  export * from "./access-control.js";
15
+ export * from "./callbacks.js";
15
16
  export * from "./coalesce.js";
17
+ export * from "./ctx.js";
16
18
  export * from "./kit.js";
17
19
  export * from "./language.js";
18
20
  export * from "./llm.js";
19
21
  export * from "./menu.js";
22
+ export * from "./payments/index.js";
23
+ export * from "./storage.js";
20
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC"}
package/dist/bot/index.js CHANGED
@@ -12,9 +12,13 @@
12
12
  * import { ... } from '@adriangalilea/utils/bot'
13
13
  */
14
14
  export * from "./access-control.js";
15
+ export * from "./callbacks.js";
15
16
  export * from "./coalesce.js";
17
+ export * from "./ctx.js";
16
18
  export * from "./kit.js";
17
19
  export * from "./language.js";
18
20
  export * from "./llm.js";
19
21
  export * from "./menu.js";
22
+ export * from "./payments/index.js";
23
+ export * from "./storage.js";
20
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC"}
package/dist/bot/kit.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Foundational helpers every bot wants. Three things:
2
+ * Foundational helpers every bot wants.
3
3
  *
4
4
  * `gracefulStart(bot, opts?)` — wires SIGINT/SIGTERM to bot.stop(),
5
5
  * runs an optional shutdown hook, force-kills if it hangs. DMs the
@@ -12,31 +12,37 @@
12
12
  * every context with `ctx.adminId` (number) and `ctx.isAdmin`
13
13
  * (boolean). Throws at startup if neither source provides an id.
14
14
  *
15
- * `prefixStorage(storage, prefix)` — wraps any `@gramio/storage`
16
- * adapter to namespace every key with a fixed prefix. ESSENTIAL
17
- * when several bots share the same backend (e.g. one Redis): the
18
- * session plugin keys records by `String(senderId)`, so the same
19
- * user's id collides across bots and the last writer wins.
15
+ * `botSession(opts)` — drop-in replacement for `@gramio/session`'s
16
+ * `session()` that AUTOMATICALLY namespaces every key with the
17
+ * calling bot's id (parsed from `ctx.bot.options.token`). When
18
+ * several bots share one Redis instance, each writes to a disjoint
19
+ * keyspace (`bot-<id>:<senderId>`) with no manual wiring. Every
20
+ * plugin in this package (`accessControl`, `botMenu`,
21
+ * `llmHistory`, …) derives the SAME prefix from `ctx.bot` for its
22
+ * own storage access, so the whole package stays isolated by
23
+ * construction. Use this instead of `session()` — full stop.
20
24
  *
21
- * Peer deps: `gramio`, `@gramio/storage`.
25
+ * Peer deps: `gramio`, `@gramio/session`, `@gramio/storage`.
22
26
  *
23
27
  * @example
24
28
  * import { Bot } from 'gramio'
25
29
  * import { redisStorage } from '@gramio/storage-redis'
26
- * import { adminContext, gracefulStart, prefixStorage } from '@adriangalilea/utils/bot/kit'
30
+ * import { adminContext, gracefulStart, botSession } from '@adriangalilea/utils/bot/kit'
27
31
  *
28
- * // ONE prefixed storage instance — pass it to session AND every plugin.
29
- * const storage = prefixStorage(redisStorage(), 'mybot:')
32
+ * const storage = redisStorage() // share across bots, safe
33
+ * const userSession = botSession({ storage, initial: () => ({}) })
30
34
  *
31
35
  * const bot = new Bot(process.env.BOT_TOKEN!)
32
- * .extend(adminContext({ adminId: 190202471 })) // KEV wins, 190… is fallback
36
+ * .extend(adminContext({ adminId: 190202471 })) // KEV wins, 190… is fallback
37
+ * .extend(userSession)
33
38
  * .command('whoami', (ctx) => ctx.send(`admin? ${ctx.isAdmin}`))
34
39
  *
35
40
  * await gracefulStart(bot, { onShutdown: () => db.end() })
36
41
  */
42
+ import { type SessionOptions, session } from "@gramio/session";
37
43
  import type { Storage } from "@gramio/storage";
38
- import type { AnyBot } from "gramio";
39
- import { Plugin } from "gramio";
44
+ import type { Plugin as PluginType } from "gramio";
45
+ import { type AnyBot } from "gramio";
40
46
  export type GracefulStartOptions = {
41
47
  /** Runs after `bot.stop()` resolves, before `process.exit`. Close DBs, flush logs. */
42
48
  onShutdown?: () => Promise<void> | void;
@@ -73,7 +79,7 @@ export type AdminContextOptions = {
73
79
  /** Hardcoded fallback used when `KEV.TELEGRAM_ADMIN_ID` is unset. */
74
80
  adminId?: number;
75
81
  };
76
- export declare const adminContext: (opts?: AdminContextOptions) => Plugin<{}, import("gramio").DeriveDefinitions & {
82
+ export declare const adminContext: (opts?: AdminContextOptions) => PluginType<{}, import("gramio").DeriveDefinitions & {
77
83
  global: {
78
84
  adminId: number;
79
85
  };
@@ -83,42 +89,88 @@ export declare const adminContext: (opts?: AdminContextOptions) => Plugin<{}, im
83
89
  };
84
90
  }, {}>;
85
91
  /**
86
- * Wraps any `@gramio/storage` adapter so every read / write goes
87
- * through `${prefix}${key}`. Pass the wrapped instance to your
88
- * `session({...})` AND to every plugin's `storage` option — they all
89
- * inherit the namespace, no per-plugin wiring needed.
92
+ * Returns the calling bot's numeric id from `ctx.bot.info.id`. Throws
93
+ * if called before `bot.start()` / `bot.init()` populates it — should
94
+ * never happen from inside an event handler, where gramio guarantees
95
+ * `bot.info` is set.
96
+ *
97
+ * Note on the structural cast: gramio's `BotLike` (the interface
98
+ * contexts are typed against) intentionally omits `info` to decouple
99
+ * Context types from the full Bot class. At runtime `ctx.bot` IS the
100
+ * full Bot, so the cast is sound — just papering over a deliberate
101
+ * type-vs-runtime gap.
102
+ */
103
+ export declare const botId: (ctx: {
104
+ bot: unknown;
105
+ }) => number;
106
+ /**
107
+ * Computes the storage key for an arbitrary user under the CALLING
108
+ * bot's namespace. Use whenever a plugin needs to read or write
109
+ * **another user's** session record from inside a handler (typical:
110
+ * admin approves a stranger, /forget wipes a stranger after a takedown
111
+ * request). For the current user, the session plugin handles keying
112
+ * automatically when wired via `botSession`.
113
+ */
114
+ export declare const botStorageKey: (ctx: {
115
+ bot: unknown;
116
+ }, userId: number) => string;
117
+ /**
118
+ * Static-key variant — namespace an arbitrary sub-key (e.g. an admin
119
+ * index, a feature flag, a counter) under the calling bot's prefix.
120
+ * Use this for bot-side state that isn't keyed by a specific user.
90
121
  *
91
- * **Why this exists.** `@gramio/session`'s default `getSessionKey` is
92
- * `String(senderId)`. If two bots share the same Redis (or any
93
- * shared-backend storage), the same Telegram user id collides across
94
- * bots — the last writer wins, `/settings → 📥 Export` returns whatever
95
- * the other bot last wrote, etc. A unique prefix per bot makes the
96
- * keyspace disjoint.
122
+ * botSubKey(ctx, 'ac:index') → 'bot-<id>:ac:index'
123
+ * botSubKey(ctx, 'metrics') → 'bot-<id>:metrics'
124
+ */
125
+ export declare const botSubKey: (ctx: {
126
+ bot: unknown;
127
+ }, subKey: string) => string;
128
+ /**
129
+ * Drop-in replacement for `@gramio/session`'s `session()` that forces
130
+ * the storage key to include the calling bot's id. Equivalent to
131
+ * passing `getSessionKey: (ctx) => bot-${id}:${senderId}` explicitly,
132
+ * but baked in so no consumer can forget.
97
133
  *
98
- * Recommended prefix shapes:
99
- * - `'mybot:'` — explicit, human-readable in Redis GUIs.
100
- * - `'<bot-username>:'` — derive from BotFather handle once at start.
101
- * - `'<bot-id>:'` — Telegram's numeric bot id from `getMe`.
134
+ * Returns a plain `@gramio/session` plugin — same shape, same derives,
135
+ * fully interchangeable in `.extend(userSession)` chains and plugin
136
+ * options like `accessControl({ session: userSession, … })`.
102
137
  *
103
- * **Storage layout** with `prefixStorage(s, 'mybot:')`:
138
+ * `getSessionKey` can still be overridden for advanced cases (e.g. a
139
+ * per-chat session in groups); the override is wrapped so it still
140
+ * receives the `bot-<id>:` prefix. Don't override unless you know what
141
+ * you're doing — every plugin in this package expects the
142
+ * `bot-<id>:<userId>` shape for cross-user storage reads.
104
143
  *
105
- * s['mybot:190202471'] = { access, language, llm } ← user 190…'s record
106
- * s['mybot:ac:index'] = { pending, approved, denied }
144
+ * @example
145
+ * import { redisStorage } from '@gramio/storage-redis'
146
+ * import { botSession } from '@adriangalilea/utils/bot/kit'
107
147
  *
108
- * s['otherbot:190202471'] = { … } ← same user, other bot
148
+ * const storage = redisStorage() // shared across N bots, safe
109
149
  *
110
- * No two bots can read each other's data. Forget / Export operate on
111
- * the prefixed keys via the same wrapper.
150
+ * const userSession = botSession({
151
+ * storage,
152
+ * key: 'session',
153
+ * initial: () => ({}),
154
+ * })
112
155
  *
113
- * @example
114
- * import { prefixStorage } from '@adriangalilea/utils/bot/kit'
115
- * import { redisStorage } from '@gramio/storage-redis'
156
+ * bot.extend(userSession)
157
+ */
158
+ export declare const botSession: <Data = unknown, Key extends string = "session", Lazy extends boolean = false>(opts: SessionOptions<Data, Key, Lazy>) => ReturnType<typeof session<Data, Key, Lazy>>;
159
+ /**
160
+ * Wraps any `@gramio/storage` adapter so every key gets a fixed
161
+ * `${prefix}` prepended.
162
+ *
163
+ * **You almost never need this.** The library's plugins are isolated
164
+ * by bot id automatically when you wire `botSession` (see above) —
165
+ * `prefixStorage` exists for edge cases:
116
166
  *
117
- * const storage = prefixStorage(redisStorage(), 'mybot:')
167
+ * - Sharing a Redis instance with a NON-bot system, and you want a
168
+ * top-level prefix on top of the bot-id namespace.
169
+ * - Migrating from an older deployment that used a custom prefix.
118
170
  *
119
- * const userSession = session({ storage, key: 'session', initial: () => ({}) })
120
- * const menu = botMenu({ adminContact: '@me', personalData: { storage }, ... })
121
- * bot.extend(accessControl({ session: userSession, storage, defaults: [] }))
171
+ * In those cases the wrapper composes cleanly with `botSession`'s
172
+ * internal prefix: final keys look like `${prefix}bot-<id>:<userId>`.
122
173
  */
123
174
  export declare const prefixStorage: (storage: Storage, prefix: string) => Storage;
175
+ export type { PluginType };
124
176
  //# sourceMappingURL=kit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/bot/kit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC,MAAM,MAAM,oBAAoB,GAAG;IAClC,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC;IACtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,aAAa,GACzB,KAAK,MAAM,EACX,OAAM,oBAAyB,KAC7B,OAAO,CAAC,IAAI,CA+Ed,CAAC;AAIF,MAAM,MAAM,mBAAmB,GAAG;IACjC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAM,mBAAwB;;;;;;;;MAqB1D,CAAC;AAIF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,OAAO,EAAE,QAAQ,MAAM,KAAG,OAQhE,CAAC"}
1
+ {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/bot/kit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,KAAK,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,QAAQ,CAAC;AAK7C,MAAM,MAAM,oBAAoB,GAAG;IAClC,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC;IACtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,aAAa,GACzB,KAAK,MAAM,EACX,OAAM,oBAAyB,KAC7B,OAAO,CAAC,IAAI,CAiFd,CAAC;AAIF,MAAM,MAAM,mBAAmB,GAAG;IACjC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,OAAM,mBAAwB;;;;;;;;MAqB1D,CAAC;AAiBF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,GAAI,KAAK;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,KAAG,MAO7C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,GAAI,KAAK;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,EAAE,QAAQ,MAAM,KAAG,MACxC,CAAC;AAE/B;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,GAAI,KAAK;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,EAAE,QAAQ,MAAM,KAAG,MACpC,CAAC;AAI/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,UAAU,GACtB,IAAI,GAAG,OAAO,EACd,GAAG,SAAS,MAAM,GAAG,SAAS,EAC9B,IAAI,SAAS,OAAO,GAAG,KAAK,EAE5B,MAAM,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,KACnC,UAAU,CAAC,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CA0B5C,CAAC;AAIF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,OAAO,EAAE,QAAQ,MAAM,KAAG,OAShE,CAAC;AAIF,YAAY,EAAE,UAAU,EAAE,CAAC"}