@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.
- package/README.md +9 -9
- package/dist/bot/access-control.d.ts.map +1 -1
- package/dist/bot/access-control.js +62 -45
- package/dist/bot/access-control.js.map +1 -1
- package/dist/bot/callbacks.d.ts +89 -0
- package/dist/bot/callbacks.d.ts.map +1 -0
- package/dist/bot/callbacks.js +128 -0
- package/dist/bot/callbacks.js.map +1 -0
- package/dist/bot/ctx.d.ts +219 -0
- package/dist/bot/ctx.d.ts.map +1 -0
- package/dist/bot/ctx.js +52 -0
- package/dist/bot/ctx.js.map +1 -0
- package/dist/bot/index.d.ts +4 -0
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +4 -0
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/kit.d.ts +93 -41
- package/dist/bot/kit.d.ts.map +1 -1
- package/dist/bot/kit.js +153 -30
- package/dist/bot/kit.js.map +1 -1
- package/dist/bot/menu.d.ts +31 -11
- package/dist/bot/menu.d.ts.map +1 -1
- package/dist/bot/menu.js +34 -9
- package/dist/bot/menu.js.map +1 -1
- package/dist/bot/payments/callbacks.d.ts +28 -0
- package/dist/bot/payments/callbacks.d.ts.map +1 -0
- package/dist/bot/payments/callbacks.js +102 -0
- package/dist/bot/payments/callbacks.js.map +1 -0
- package/dist/bot/payments/commands.d.ts +26 -0
- package/dist/bot/payments/commands.d.ts.map +1 -0
- package/dist/bot/payments/commands.js +41 -0
- package/dist/bot/payments/commands.js.map +1 -0
- package/dist/bot/payments/config.d.ts +30 -0
- package/dist/bot/payments/config.d.ts.map +1 -0
- package/dist/bot/payments/config.js +166 -0
- package/dist/bot/payments/config.js.map +1 -0
- package/dist/bot/payments/derive.d.ts +75 -0
- package/dist/bot/payments/derive.d.ts.map +1 -0
- package/dist/bot/payments/derive.js +151 -0
- package/dist/bot/payments/derive.js.map +1 -0
- package/dist/bot/payments/handlers.d.ts +113 -0
- package/dist/bot/payments/handlers.d.ts.map +1 -0
- package/dist/bot/payments/handlers.js +284 -0
- package/dist/bot/payments/handlers.js.map +1 -0
- package/dist/bot/payments/index.d.ts +17 -0
- package/dist/bot/payments/index.d.ts.map +1 -0
- package/dist/bot/payments/index.js +14 -0
- package/dist/bot/payments/index.js.map +1 -0
- package/dist/bot/payments/invoice.d.ts +101 -0
- package/dist/bot/payments/invoice.d.ts.map +1 -0
- package/dist/bot/payments/invoice.js +213 -0
- package/dist/bot/payments/invoice.js.map +1 -0
- package/dist/bot/payments/menu-item.d.ts +41 -0
- package/dist/bot/payments/menu-item.d.ts.map +1 -0
- package/dist/bot/payments/menu-item.js +259 -0
- package/dist/bot/payments/menu-item.js.map +1 -0
- package/dist/bot/payments/payload.d.ts +42 -0
- package/dist/bot/payments/payload.d.ts.map +1 -0
- package/dist/bot/payments/payload.js +69 -0
- package/dist/bot/payments/payload.js.map +1 -0
- package/dist/bot/payments/payouts.d.ts +88 -0
- package/dist/bot/payments/payouts.d.ts.map +1 -0
- package/dist/bot/payments/payouts.js +133 -0
- package/dist/bot/payments/payouts.js.map +1 -0
- package/dist/bot/payments/plugin.d.ts +271 -0
- package/dist/bot/payments/plugin.d.ts.map +1 -0
- package/dist/bot/payments/plugin.js +141 -0
- package/dist/bot/payments/plugin.js.map +1 -0
- package/dist/bot/payments/refund.d.ts +124 -0
- package/dist/bot/payments/refund.d.ts.map +1 -0
- package/dist/bot/payments/refund.js +308 -0
- package/dist/bot/payments/refund.js.map +1 -0
- package/dist/bot/payments/schemas.d.ts +58 -0
- package/dist/bot/payments/schemas.d.ts.map +1 -0
- package/dist/bot/payments/schemas.js +55 -0
- package/dist/bot/payments/schemas.js.map +1 -0
- package/dist/bot/payments/state.d.ts +90 -0
- package/dist/bot/payments/state.d.ts.map +1 -0
- package/dist/bot/payments/state.js +149 -0
- package/dist/bot/payments/state.js.map +1 -0
- package/dist/bot/payments/stores.d.ts +44 -0
- package/dist/bot/payments/stores.d.ts.map +1 -0
- package/dist/bot/payments/stores.js +39 -0
- package/dist/bot/payments/stores.js.map +1 -0
- package/dist/bot/payments/types.d.ts +299 -0
- package/dist/bot/payments/types.d.ts.map +1 -0
- package/dist/bot/payments/types.js +39 -0
- package/dist/bot/payments/types.js.map +1 -0
- package/dist/bot/payments/waiver.d.ts +81 -0
- package/dist/bot/payments/waiver.d.ts.map +1 -0
- package/dist/bot/payments/waiver.js +145 -0
- package/dist/bot/payments/waiver.js.map +1 -0
- package/dist/bot/storage.d.ts +154 -0
- package/dist/bot/storage.d.ts.map +1 -0
- package/dist/bot/storage.js +222 -0
- package/dist/bot/storage.js.map +1 -0
- 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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"}
|
package/dist/bot/ctx.js
ADDED
|
@@ -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"}
|
package/dist/bot/index.d.ts
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.d.ts.map
|
package/dist/bot/index.d.ts.map
CHANGED
|
@@ -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
|
package/dist/bot/index.js.map
CHANGED
|
@@ -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.
|
|
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
|
-
* `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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,
|
|
30
|
+
* import { adminContext, gracefulStart, botSession } from '@adriangalilea/utils/bot/kit'
|
|
27
31
|
*
|
|
28
|
-
*
|
|
29
|
-
* const
|
|
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 }))
|
|
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 {
|
|
39
|
-
import {
|
|
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) =>
|
|
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
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
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
|
-
*
|
|
92
|
-
*
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
106
|
-
*
|
|
144
|
+
* @example
|
|
145
|
+
* import { redisStorage } from '@gramio/storage-redis'
|
|
146
|
+
* import { botSession } from '@adriangalilea/utils/bot/kit'
|
|
107
147
|
*
|
|
108
|
-
*
|
|
148
|
+
* const storage = redisStorage() // shared across N bots, safe
|
|
109
149
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
150
|
+
* const userSession = botSession({
|
|
151
|
+
* storage,
|
|
152
|
+
* key: 'session',
|
|
153
|
+
* initial: () => ({}),
|
|
154
|
+
* })
|
|
112
155
|
*
|
|
113
|
-
*
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
120
|
-
*
|
|
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
|
package/dist/bot/kit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/bot/kit.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|