@adriangalilea/utils 0.25.0 → 0.27.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 +23 -24
- package/dist/bot/index.d.ts +1 -0
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +1 -0
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/kit.d.ts +9 -59
- package/dist/bot/kit.d.ts.map +1 -1
- package/dist/bot/kit.js +4 -142
- package/dist/bot/kit.js.map +1 -1
- package/dist/bot/notify.d.ts +59 -0
- package/dist/bot/notify.d.ts.map +1 -0
- package/dist/bot/notify.js +62 -0
- package/dist/bot/notify.js.map +1 -0
- package/dist/bot/session.d.ts +63 -0
- package/dist/bot/session.d.ts.map +1 -0
- package/dist/bot/session.js +93 -0
- package/dist/bot/session.js.map +1 -0
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -1
- package/dist/universal/currency/crypto-symbols.d.ts +3 -11
- package/dist/universal/currency/crypto-symbols.d.ts.map +1 -1
- package/dist/universal/currency/crypto-symbols.js +8 -11
- package/dist/universal/currency/crypto-symbols.js.map +1 -1
- package/dist/universal/currency/index.d.ts +15 -0
- package/dist/universal/currency/index.d.ts.map +1 -1
- package/dist/universal/currency/index.js +35 -0
- package/dist/universal/currency/index.js.map +1 -1
- package/dist/universal/format.d.ts +13 -37
- package/dist/universal/format.d.ts.map +1 -1
- package/dist/universal/format.js +29 -77
- package/dist/universal/format.js.map +1 -1
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -77,30 +77,26 @@ currency.formatBasisPoints(50) // "50 bps"
|
|
|
77
77
|
|
|
78
78
|
### Format
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
Pure number formatting — named exports, tree-shakeable, zero currency baggage
|
|
81
|
+
(money formatting lives in the currency module, which owns the symbol/decimals
|
|
82
|
+
knowledge and its crypto-symbol dataset):
|
|
81
83
|
|
|
82
84
|
```typescript
|
|
83
|
-
import {
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
format.auto(100, 'EUR') // "€100.00"
|
|
99
|
-
|
|
100
|
-
// Percentages
|
|
101
|
-
format.percentage(12.3456) // "12.3%"
|
|
102
|
-
format.percentage(0.05) // "0.05%"
|
|
103
|
-
format.percentage(123.456) // "123%"
|
|
85
|
+
import { compact, percentage, withCommas } from '@adriangalilea/utils/format'
|
|
86
|
+
|
|
87
|
+
withCommas(1234567) // "1,234,567"
|
|
88
|
+
withCommas(1234.567, 2) // "1,234.57"
|
|
89
|
+
compact(1234567) // "1.2M"
|
|
90
|
+
compact(1234) // "1.2K"
|
|
91
|
+
percentage(12.3456) // "12.3%"
|
|
92
|
+
percentage(0.05) // "0.05%"
|
|
93
|
+
percentage(123.456) // "123%"
|
|
94
|
+
|
|
95
|
+
// Money — from currency, not format:
|
|
96
|
+
import { usd, btc, money } from '@adriangalilea/utils/currency'
|
|
97
|
+
usd(1234.56) // "$1234.56"
|
|
98
|
+
btc(0.00001234) // "0.00001234 ₿"
|
|
99
|
+
money(100, 'EUR') // "€100.00"
|
|
104
100
|
```
|
|
105
101
|
|
|
106
102
|
### CLI presentation (`cli`)
|
|
@@ -389,7 +385,9 @@ Then `pnpm install`. Every `ctx.send` / `ctx.sendDocument` / `ctx.reply` / etc.
|
|
|
389
385
|
|---|---|
|
|
390
386
|
| `@adriangalilea/utils/bot/ctx` | Structural ctx types (`BotMessageCtx`, `BotCallbackCtx`, …) and the `narrow<T>(ctx)` cast helper. Pure typing — no runtime state. |
|
|
391
387
|
| `@adriangalilea/utils/bot/keys` | The bot-id key namespace, a **persisted contract**: `botId(ctx)`, `botStorageKey(ctx, userId)` → `bot-<id>:<userId>`, `botSubKey(ctx, sub)` → `bot-<id>:<sub>`. Every storage key the library writes derives from here, and those keys live in YOUR Redis/D1 rows — the shape never changes. Pure functions of `ctx.bot.info.id` (no env/fs), which is what keeps the whole bot surface Worker-safe. |
|
|
392
|
-
| `@adriangalilea/utils/bot/kit` | `gracefulStart(bot, opts?)` — SIGINT/SIGTERM → `bot.stop()` → exit; force-kills if shutdown hangs. DMs the admin `@<bot> started.` / `@<bot> shutting down.` by default when `KEV.TELEGRAM_ADMIN_ID` is set (graceful only — crashes don't trigger `onStop`); pass `notifyAdmin: false` to disable or `notifyAdmin: 12345` for an explicit chat id.<br>`adminContext({ adminId? })` — reads `TELEGRAM_ADMIN_ID` from `kev` (with optional hardcoded fallback), decorates `ctx.adminId` + `ctx.isAdmin`.<br
|
|
388
|
+
| `@adriangalilea/utils/bot/kit` | The Node-only corner. `gracefulStart(bot, opts?)` — SIGINT/SIGTERM → `bot.stop()` → exit; force-kills if shutdown hangs. DMs the admin `@<bot> started.` / `@<bot> shutting down.` by default when `KEV.TELEGRAM_ADMIN_ID` is set (graceful only — crashes don't trigger `onStop`); pass `notifyAdmin: false` to disable or `notifyAdmin: 12345` for an explicit chat id.<br>`adminContext({ adminId? })` — reads `TELEGRAM_ADMIN_ID` from `kev` (with optional hardcoded fallback), decorates `ctx.adminId` + `ctx.isAdmin`.<br>Also re-exports `botSession` / `prefixStorage` from `bot/session` so Node consumers keep one import. |
|
|
389
|
+
| `@adriangalilea/utils/bot/session` | `botSession(opts)` — **drop-in replacement for `@gramio/session`'s `session()`** that auto-namespaces every key as `bot-<id>:<senderId>` using `ctx.bot.info.id` (populated by `getMe()` at startup). Use this instead of `session()` — full stop. Multiple bots sharing one Redis/D1 stay isolated by construction; every plugin in this package derives the same prefix internally via `botStorageKey(ctx, userId)` / `botSubKey(ctx, sub)` (from `bot/keys`). No regex, no manual prefix argument, no way to forget.<br>`prefixStorage(storage, prefix)` — escape hatch for adding a top-level prefix on top of the bot-id namespace; almost never needed. Worker-safe (used to live in `bot/kit`, which forced Worker bots to hand-roll the keying). |
|
|
390
|
+
| `@adriangalilea/utils/bot/notify` | Best-effort admin DMs, worker-safe (you pass the ids; no env, no process). `notifyAdmins(bot, adminIds, text, extra?)` — DM each admin, failures logged and swallowed (a notification must never take the bot down). `alertAdminError(bot, adminIds, label, error, throttle?)` — truncated `🚨 label\nName: message`, rate-limited through a caller-owned `alertThrottle(ms?)` so a failure storm sends one alert per window. `gracefulStart`'s start/stop DMs are built on this. |
|
|
393
391
|
| `@adriangalilea/utils/bot/access-control` | Personal-bot ACL — gates non-admin/non-default users; admin gets DM with `[✅ Aprobar][❌ Denegar]` on first attempt; `/access` opens a persistent menu (revoke / reapprove / list pending). Backed by `@gramio/session` per-user + a small index. **Native alternative**: BotFather → Bot Settings → Access → "Restrict bot usage" — flat allow-list at Telegram. Use this plugin when you want in-bot approval flow instead of a BotFather round-trip; both can coexist. |
|
|
394
392
|
| `@adriangalilea/utils/bot/allow-list` | Static allow-list by **id and/or @username** — stateless, no session/storage. `allowList({ ids?, usernames? })` is a plugin that decorates `ctx.allowed` (boolean); gate in your handlers (`if (!ctx.allowed) return`). `makeAllowList(...)` is the pure framework-free predicate. The light counterpart to `access-control` (which adds an approve/deny flow + revocable store, needing session+storage). Username caveat: a `@username` is optional and mutable, and the Bot API can't resolve username→id ahead of time — prefer `ids` when known, `usernames` is the pragmatic fallback. |
|
|
395
393
|
| `@adriangalilea/utils/bot/coalesce` | Joins client-split inbound messages back into one. When a user pastes >4096 chars, Telegram clients fragment it into separate `message` updates with no marker. Middleware detects the burst and emits one combined event. |
|
|
@@ -402,7 +400,8 @@ Standard wiring:
|
|
|
402
400
|
```typescript
|
|
403
401
|
import { Bot } from 'gramio'
|
|
404
402
|
import { redisStorage } from '@gramio/storage-redis'
|
|
405
|
-
import { adminContext,
|
|
403
|
+
import { adminContext, gracefulStart } from '@adriangalilea/utils/bot/kit'
|
|
404
|
+
import { botSession } from '@adriangalilea/utils/bot/session'
|
|
406
405
|
import { accessControl } from '@adriangalilea/utils/bot/access-control'
|
|
407
406
|
import { llmStream, llmHistory } from '@adriangalilea/utils/bot/llm'
|
|
408
407
|
|
package/dist/bot/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./kit.js";
|
|
|
20
20
|
export * from "./language.js";
|
|
21
21
|
export * from "./llm.js";
|
|
22
22
|
export * from "./menu.js";
|
|
23
|
+
export * from "./notify.js";
|
|
23
24
|
export * from "./payments/index.js";
|
|
24
25
|
export * from "./storage.js";
|
|
25
26
|
//# 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,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,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,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC"}
|
package/dist/bot/index.js
CHANGED
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,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,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,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC"}
|
package/dist/bot/kit.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Foundational helpers
|
|
2
|
+
* Foundational helpers for NODE bots — the library's deliberately
|
|
3
|
+
* Node-only corner (process signals, KEV env resolution). Worker bots
|
|
4
|
+
* use the worker-safe subpaths instead: `bot/session` (namespaced
|
|
5
|
+
* sessions) and `bot/notify` (admin DMs) hold the pieces that used to
|
|
6
|
+
* live here but never needed an OS.
|
|
3
7
|
*
|
|
4
8
|
* `gracefulStart(bot, opts?)` — wires SIGINT/SIGTERM to bot.stop(),
|
|
5
9
|
* runs an optional shutdown hook, force-kills if it hangs. DMs the
|
|
@@ -12,15 +16,9 @@
|
|
|
12
16
|
* every context with `ctx.adminId` (number) and `ctx.isAdmin`
|
|
13
17
|
* (boolean). Throws at startup if neither source provides an id.
|
|
14
18
|
*
|
|
15
|
-
* `botSession
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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.
|
|
19
|
+
* `botSession` / `prefixStorage` — re-exported from `bot/session` so
|
|
20
|
+
* Node consumers keep one import; the implementation is worker-safe
|
|
21
|
+
* and lives there.
|
|
24
22
|
*
|
|
25
23
|
* Peer deps: `gramio`, `@gramio/session`, `@gramio/storage`.
|
|
26
24
|
*
|
|
@@ -39,10 +37,9 @@
|
|
|
39
37
|
*
|
|
40
38
|
* await gracefulStart(bot, { onShutdown: () => db.end() })
|
|
41
39
|
*/
|
|
42
|
-
import { type SessionOptions, session } from "@gramio/session";
|
|
43
|
-
import type { Storage } from "@gramio/storage";
|
|
44
40
|
import type { Plugin as PluginType } from "gramio";
|
|
45
41
|
import { type AnyBot } from "gramio";
|
|
42
|
+
export { botSession, prefixStorage } from "./session.js";
|
|
46
43
|
export type GracefulStartOptions = {
|
|
47
44
|
/** Runs after `bot.stop()` resolves, before `process.exit`. Close DBs, flush logs. */
|
|
48
45
|
onShutdown?: () => Promise<void> | void;
|
|
@@ -88,52 +85,5 @@ export declare const adminContext: (opts?: AdminContextOptions) => PluginType<{}
|
|
|
88
85
|
isAdmin: boolean;
|
|
89
86
|
};
|
|
90
87
|
}, {}>;
|
|
91
|
-
/**
|
|
92
|
-
* Drop-in replacement for `@gramio/session`'s `session()` that forces
|
|
93
|
-
* the storage key to include the calling bot's id. Equivalent to
|
|
94
|
-
* passing `getSessionKey: (ctx) => bot-${id}:${senderId}` explicitly,
|
|
95
|
-
* but baked in so no consumer can forget.
|
|
96
|
-
*
|
|
97
|
-
* Returns a plain `@gramio/session` plugin — same shape, same derives,
|
|
98
|
-
* fully interchangeable in `.extend(userSession)` chains and plugin
|
|
99
|
-
* options like `accessControl({ session: userSession, … })`.
|
|
100
|
-
*
|
|
101
|
-
* `getSessionKey` can still be overridden for advanced cases (e.g. a
|
|
102
|
-
* per-chat session in groups); the override is wrapped so it still
|
|
103
|
-
* receives the `bot-<id>:` prefix. Don't override unless you know what
|
|
104
|
-
* you're doing — every plugin in this package expects the
|
|
105
|
-
* `bot-<id>:<userId>` shape for cross-user storage reads.
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* import { redisStorage } from '@gramio/storage-redis'
|
|
109
|
-
* import { botSession } from '@adriangalilea/utils/bot/kit'
|
|
110
|
-
*
|
|
111
|
-
* const storage = redisStorage() // shared across N bots, safe
|
|
112
|
-
*
|
|
113
|
-
* const userSession = botSession({
|
|
114
|
-
* storage,
|
|
115
|
-
* key: 'session',
|
|
116
|
-
* initial: () => ({}),
|
|
117
|
-
* })
|
|
118
|
-
*
|
|
119
|
-
* bot.extend(userSession)
|
|
120
|
-
*/
|
|
121
|
-
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>>;
|
|
122
|
-
/**
|
|
123
|
-
* Wraps any `@gramio/storage` adapter so every key gets a fixed
|
|
124
|
-
* `${prefix}` prepended.
|
|
125
|
-
*
|
|
126
|
-
* **You almost never need this.** The library's plugins are isolated
|
|
127
|
-
* by bot id automatically when you wire `botSession` (see above) —
|
|
128
|
-
* `prefixStorage` exists for edge cases:
|
|
129
|
-
*
|
|
130
|
-
* - Sharing a Redis instance with a NON-bot system, and you want a
|
|
131
|
-
* top-level prefix on top of the bot-id namespace.
|
|
132
|
-
* - Migrating from an older deployment that used a custom prefix.
|
|
133
|
-
*
|
|
134
|
-
* In those cases the wrapper composes cleanly with `botSession`'s
|
|
135
|
-
* internal prefix: final keys look like `${prefix}bot-<id>:<userId>`.
|
|
136
|
-
*/
|
|
137
|
-
export declare const prefixStorage: (storage: Storage, prefix: string) => Storage;
|
|
138
88
|
export type { PluginType };
|
|
139
89
|
//# 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,QAAQ,CAAC;AAI7C,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIzD,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,CAmEd,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,YAAY,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/bot/kit.js
CHANGED
|
@@ -1,48 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Foundational helpers every bot wants.
|
|
3
|
-
*
|
|
4
|
-
* `gracefulStart(bot, opts?)` — wires SIGINT/SIGTERM to bot.stop(),
|
|
5
|
-
* runs an optional shutdown hook, force-kills if it hangs. DMs the
|
|
6
|
-
* admin on start/stop by default (`@<bot> started.` /
|
|
7
|
-
* `@<bot> shutting down.`) when `KEV.TELEGRAM_ADMIN_ID` is set —
|
|
8
|
-
* pass `notifyAdmin: false` to disable.
|
|
9
|
-
*
|
|
10
|
-
* `adminContext({ adminId? })` — reads admin Telegram id from KEV
|
|
11
|
-
* (`TELEGRAM_ADMIN_ID`) with optional hardcoded fallback. Decorates
|
|
12
|
-
* every context with `ctx.adminId` (number) and `ctx.isAdmin`
|
|
13
|
-
* (boolean). Throws at startup if neither source provides an id.
|
|
14
|
-
*
|
|
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.
|
|
24
|
-
*
|
|
25
|
-
* Peer deps: `gramio`, `@gramio/session`, `@gramio/storage`.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* import { Bot } from 'gramio'
|
|
29
|
-
* import { redisStorage } from '@gramio/storage-redis'
|
|
30
|
-
* import { adminContext, gracefulStart, botSession } from '@adriangalilea/utils/bot/kit'
|
|
31
|
-
*
|
|
32
|
-
* const storage = redisStorage() // share across bots, safe
|
|
33
|
-
* const userSession = botSession({ storage, initial: () => ({}) })
|
|
34
|
-
*
|
|
35
|
-
* const bot = new Bot(process.env.BOT_TOKEN!)
|
|
36
|
-
* .extend(adminContext({ adminId: 190202471 })) // KEV wins, 190… is fallback
|
|
37
|
-
* .extend(userSession)
|
|
38
|
-
* .command('whoami', (ctx) => ctx.send(`admin? ${ctx.isAdmin}`))
|
|
39
|
-
*
|
|
40
|
-
* await gracefulStart(bot, { onShutdown: () => db.end() })
|
|
41
|
-
*/
|
|
42
|
-
import { session } from "@gramio/session";
|
|
43
1
|
import { Plugin } from "gramio";
|
|
44
2
|
import { kev } from "../platform/kev.js";
|
|
45
|
-
import {
|
|
3
|
+
import { notifyAdmins } from "./notify.js";
|
|
4
|
+
export { botSession, prefixStorage } from "./session.js";
|
|
46
5
|
export const gracefulStart = async (bot, opts = {}) => {
|
|
47
6
|
const log = opts.log === false ? () => { } : (opts.log ?? ((m) => console.log(m)));
|
|
48
7
|
const forceMs = opts.forceExitAfterMs ?? 10_000;
|
|
@@ -93,28 +52,8 @@ export const gracefulStart = async (bot, opts = {}) => {
|
|
|
93
52
|
"Pass a number explicitly, set the env var, or remove notifyAdmin.");
|
|
94
53
|
}
|
|
95
54
|
if (adminId) {
|
|
96
|
-
bot.onStart(
|
|
97
|
-
|
|
98
|
-
await bot.api.sendMessage({
|
|
99
|
-
chat_id: adminId,
|
|
100
|
-
text: `@${info.username} started.`,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
catch (e) {
|
|
104
|
-
console.error("[bot] notifyAdmin (start) failed", e);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
bot.onStop(async ({ info }) => {
|
|
108
|
-
try {
|
|
109
|
-
await bot.api.sendMessage({
|
|
110
|
-
chat_id: adminId,
|
|
111
|
-
text: `@${info.username} shutting down.`,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
console.error("[bot] notifyAdmin (stop) failed", e);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
55
|
+
bot.onStart(({ info }) => notifyAdmins(bot, [adminId], `@${info.username} started.`));
|
|
56
|
+
bot.onStop(({ info }) => notifyAdmins(bot, [adminId], `@${info.username} shutting down.`));
|
|
118
57
|
}
|
|
119
58
|
await bot.start();
|
|
120
59
|
};
|
|
@@ -136,81 +75,4 @@ export const adminContext = (opts = {}) => {
|
|
|
136
75
|
isAdmin: "senderId" in ctx && ctx.senderId === adminId,
|
|
137
76
|
}));
|
|
138
77
|
};
|
|
139
|
-
// ─── botSession ────────────────────────────────────────────────────
|
|
140
|
-
/**
|
|
141
|
-
* Drop-in replacement for `@gramio/session`'s `session()` that forces
|
|
142
|
-
* the storage key to include the calling bot's id. Equivalent to
|
|
143
|
-
* passing `getSessionKey: (ctx) => bot-${id}:${senderId}` explicitly,
|
|
144
|
-
* but baked in so no consumer can forget.
|
|
145
|
-
*
|
|
146
|
-
* Returns a plain `@gramio/session` plugin — same shape, same derives,
|
|
147
|
-
* fully interchangeable in `.extend(userSession)` chains and plugin
|
|
148
|
-
* options like `accessControl({ session: userSession, … })`.
|
|
149
|
-
*
|
|
150
|
-
* `getSessionKey` can still be overridden for advanced cases (e.g. a
|
|
151
|
-
* per-chat session in groups); the override is wrapped so it still
|
|
152
|
-
* receives the `bot-<id>:` prefix. Don't override unless you know what
|
|
153
|
-
* you're doing — every plugin in this package expects the
|
|
154
|
-
* `bot-<id>:<userId>` shape for cross-user storage reads.
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* import { redisStorage } from '@gramio/storage-redis'
|
|
158
|
-
* import { botSession } from '@adriangalilea/utils/bot/kit'
|
|
159
|
-
*
|
|
160
|
-
* const storage = redisStorage() // shared across N bots, safe
|
|
161
|
-
*
|
|
162
|
-
* const userSession = botSession({
|
|
163
|
-
* storage,
|
|
164
|
-
* key: 'session',
|
|
165
|
-
* initial: () => ({}),
|
|
166
|
-
* })
|
|
167
|
-
*
|
|
168
|
-
* bot.extend(userSession)
|
|
169
|
-
*/
|
|
170
|
-
export const botSession = (opts) => {
|
|
171
|
-
const userKeyer = opts.getSessionKey;
|
|
172
|
-
return session({
|
|
173
|
-
...opts,
|
|
174
|
-
// The session plugin types `getSessionKey` against `ContextType<BotLike, Events>`
|
|
175
|
-
// — too narrow for our generic wrapper. We only need `bot.info.id` +
|
|
176
|
-
// `senderId`, both of which gramio guarantees on every event the session
|
|
177
|
-
// plugin processes (bot.info is populated by bot.start / bot.init before
|
|
178
|
-
// any handler fires). Structural cast at the boundary keeps the public
|
|
179
|
-
// API generic-friendly without forcing consumers to specify Event unions.
|
|
180
|
-
getSessionKey: (async (ctxRaw) => {
|
|
181
|
-
const ctx = ctxRaw;
|
|
182
|
-
const prefix = `bot-${botId(ctx)}:`;
|
|
183
|
-
if (userKeyer) {
|
|
184
|
-
const inner = await userKeyer(ctx);
|
|
185
|
-
return `${prefix}${inner}`;
|
|
186
|
-
}
|
|
187
|
-
return `${prefix}${ctx.senderId ?? ""}`;
|
|
188
|
-
}),
|
|
189
|
-
});
|
|
190
|
-
};
|
|
191
|
-
// ─── prefixStorage (escape hatch) ──────────────────────────────────
|
|
192
|
-
/**
|
|
193
|
-
* Wraps any `@gramio/storage` adapter so every key gets a fixed
|
|
194
|
-
* `${prefix}` prepended.
|
|
195
|
-
*
|
|
196
|
-
* **You almost never need this.** The library's plugins are isolated
|
|
197
|
-
* by bot id automatically when you wire `botSession` (see above) —
|
|
198
|
-
* `prefixStorage` exists for edge cases:
|
|
199
|
-
*
|
|
200
|
-
* - Sharing a Redis instance with a NON-bot system, and you want a
|
|
201
|
-
* top-level prefix on top of the bot-id namespace.
|
|
202
|
-
* - Migrating from an older deployment that used a custom prefix.
|
|
203
|
-
*
|
|
204
|
-
* In those cases the wrapper composes cleanly with `botSession`'s
|
|
205
|
-
* internal prefix: final keys look like `${prefix}bot-<id>:<userId>`.
|
|
206
|
-
*/
|
|
207
|
-
export const prefixStorage = (storage, prefix) => {
|
|
208
|
-
const k = (key) => `${prefix}${String(key)}`;
|
|
209
|
-
return {
|
|
210
|
-
get: (key) => storage.get(k(key)),
|
|
211
|
-
has: (key) => storage.has(k(key)),
|
|
212
|
-
set: (key, value) => storage.set(k(key), value),
|
|
213
|
-
delete: (key) => storage.delete(k(key)),
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
78
|
//# sourceMappingURL=kit.js.map
|
package/dist/bot/kit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kit.js","sourceRoot":"","sources":["../../src/bot/kit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kit.js","sourceRoot":"","sources":["../../src/bot/kit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin notifications — best-effort DMs to the bot's operator(s).
|
|
3
|
+
* Worker-safe: no env, no process; the caller passes the admin ids
|
|
4
|
+
* (from wherever its runtime keeps them: KEV on Node, D1/env on a
|
|
5
|
+
* Worker).
|
|
6
|
+
*
|
|
7
|
+
* Everything here is FIRE-AND-FORGET BY CONTRACT: a notification must
|
|
8
|
+
* never take the bot down, so failures are logged (console.error —
|
|
9
|
+
* visible in a Worker tail and a Node terminal alike) and swallowed.
|
|
10
|
+
*
|
|
11
|
+
* `notifyAdmins(bot, adminIds, text, extra?)` — DM each admin.
|
|
12
|
+
* `alertAdminError(bot, adminIds, label, error, throttle?)` — DM a
|
|
13
|
+
* truncated `🚨 label\nName: message`, rate-limited through a
|
|
14
|
+
* caller-owned throttle so a failure storm can't flood anyone.
|
|
15
|
+
* `alertThrottle(ms?)` — make that throttle (per-process on Node,
|
|
16
|
+
* per-isolate on a Worker; own one per subsystem if you want
|
|
17
|
+
* independent budgets).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { alertAdminError, alertThrottle, notifyAdmins } from '@adriangalilea/utils/bot/notify'
|
|
21
|
+
*
|
|
22
|
+
* const errorAlerts = alertThrottle() // 60s budget, module-level
|
|
23
|
+
* bot.onError(({ kind, error }) => void alertAdminError(bot, adminIds, `error [${kind}]`, error, errorAlerts))
|
|
24
|
+
* await notifyAdmins(bot, adminIds, `@${bot.info.username} deployed.`)
|
|
25
|
+
*/
|
|
26
|
+
/** The one API surface a notification needs — satisfied by any gramio `Bot`. */
|
|
27
|
+
export type NotifyBot = {
|
|
28
|
+
api: {
|
|
29
|
+
sendMessage: (params: {
|
|
30
|
+
chat_id: number;
|
|
31
|
+
text: string;
|
|
32
|
+
}) => Promise<unknown>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* DM `text` to every admin id, best-effort: each failure is logged and
|
|
37
|
+
* swallowed (one unreachable admin must not block the rest, and a
|
|
38
|
+
* notification must never throw into the calling flow). `extra` merges
|
|
39
|
+
* into the sendMessage params (reply_markup, link_preview_options, …).
|
|
40
|
+
*/
|
|
41
|
+
export declare function notifyAdmins(bot: NotifyBot, adminIds: readonly number[], text: string, extra?: Record<string, unknown>): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Rate-limit state for {@link alertAdminError}, owned by the CALLER so
|
|
44
|
+
* scope is explicit (per-process on Node, per-isolate on a Worker) and
|
|
45
|
+
* independent subsystems can hold independent budgets.
|
|
46
|
+
*/
|
|
47
|
+
export type AlertThrottle = {
|
|
48
|
+
ms: number;
|
|
49
|
+
lastAt: number;
|
|
50
|
+
};
|
|
51
|
+
/** A fresh throttle: at most one alert per `ms` (default 60s). */
|
|
52
|
+
export declare const alertThrottle: (ms?: number) => AlertThrottle;
|
|
53
|
+
/**
|
|
54
|
+
* DM the admins a truncated error (`🚨 label\nName: message`), gated by
|
|
55
|
+
* `throttle` so a failure storm sends one alert per window, not one per
|
|
56
|
+
* failure. No throttle = every call sends.
|
|
57
|
+
*/
|
|
58
|
+
export declare function alertAdminError(bot: NotifyBot, adminIds: readonly number[], label: string, error: unknown, throttle?: AlertThrottle): Promise<void>;
|
|
59
|
+
//# sourceMappingURL=notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../../src/bot/notify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG;IACvB,GAAG,EAAE;QACJ,WAAW,EAAE,CAAC,MAAM,EAAE;YACrB,OAAO,EAAE,MAAM,CAAC;YAChB,IAAI,EAAE,MAAM,CAAC;SACb,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACvB,CAAC;CACF,CAAC;AAKF;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,kEAAkE;AAClE,eAAO,MAAM,aAAa,GAAI,WAAW,KAAG,aAG1C,CAAC;AAEH;;;;GAIG;AACH,wBAAsB,eAAe,CACpC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CASf"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin notifications — best-effort DMs to the bot's operator(s).
|
|
3
|
+
* Worker-safe: no env, no process; the caller passes the admin ids
|
|
4
|
+
* (from wherever its runtime keeps them: KEV on Node, D1/env on a
|
|
5
|
+
* Worker).
|
|
6
|
+
*
|
|
7
|
+
* Everything here is FIRE-AND-FORGET BY CONTRACT: a notification must
|
|
8
|
+
* never take the bot down, so failures are logged (console.error —
|
|
9
|
+
* visible in a Worker tail and a Node terminal alike) and swallowed.
|
|
10
|
+
*
|
|
11
|
+
* `notifyAdmins(bot, adminIds, text, extra?)` — DM each admin.
|
|
12
|
+
* `alertAdminError(bot, adminIds, label, error, throttle?)` — DM a
|
|
13
|
+
* truncated `🚨 label\nName: message`, rate-limited through a
|
|
14
|
+
* caller-owned throttle so a failure storm can't flood anyone.
|
|
15
|
+
* `alertThrottle(ms?)` — make that throttle (per-process on Node,
|
|
16
|
+
* per-isolate on a Worker; own one per subsystem if you want
|
|
17
|
+
* independent budgets).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { alertAdminError, alertThrottle, notifyAdmins } from '@adriangalilea/utils/bot/notify'
|
|
21
|
+
*
|
|
22
|
+
* const errorAlerts = alertThrottle() // 60s budget, module-level
|
|
23
|
+
* bot.onError(({ kind, error }) => void alertAdminError(bot, adminIds, `error [${kind}]`, error, errorAlerts))
|
|
24
|
+
* await notifyAdmins(bot, adminIds, `@${bot.info.username} deployed.`)
|
|
25
|
+
*/
|
|
26
|
+
/** Telegram's hard per-message limit; longer texts are truncated, never split. */
|
|
27
|
+
const MAX_CHARS = 4096;
|
|
28
|
+
/**
|
|
29
|
+
* DM `text` to every admin id, best-effort: each failure is logged and
|
|
30
|
+
* swallowed (one unreachable admin must not block the rest, and a
|
|
31
|
+
* notification must never throw into the calling flow). `extra` merges
|
|
32
|
+
* into the sendMessage params (reply_markup, link_preview_options, …).
|
|
33
|
+
*/
|
|
34
|
+
export async function notifyAdmins(bot, adminIds, text, extra) {
|
|
35
|
+
const body = text.slice(0, MAX_CHARS);
|
|
36
|
+
await Promise.all(adminIds
|
|
37
|
+
.filter((id) => id > 0)
|
|
38
|
+
.map((id) => bot.api
|
|
39
|
+
.sendMessage({ ...extra, chat_id: id, text: body })
|
|
40
|
+
.catch((e) => console.error(`[bot/notify] admin ${id} failed:`, e))));
|
|
41
|
+
}
|
|
42
|
+
/** A fresh throttle: at most one alert per `ms` (default 60s). */
|
|
43
|
+
export const alertThrottle = (ms = 60_000) => ({
|
|
44
|
+
ms,
|
|
45
|
+
lastAt: 0,
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* DM the admins a truncated error (`🚨 label\nName: message`), gated by
|
|
49
|
+
* `throttle` so a failure storm sends one alert per window, not one per
|
|
50
|
+
* failure. No throttle = every call sends.
|
|
51
|
+
*/
|
|
52
|
+
export async function alertAdminError(bot, adminIds, label, error, throttle) {
|
|
53
|
+
if (throttle) {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
if (now - throttle.lastAt < throttle.ms)
|
|
56
|
+
return;
|
|
57
|
+
throttle.lastAt = now;
|
|
58
|
+
}
|
|
59
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
60
|
+
await notifyAdmins(bot, adminIds, `🚨 ${label}\n${message}`);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.js","sourceRoot":"","sources":["../../src/bot/notify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAYH,kFAAkF;AAClF,MAAM,SAAS,GAAG,IAAI,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,GAAc,EACd,QAA2B,EAC3B,IAAY,EACZ,KAA+B;IAE/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACtC,MAAM,OAAO,CAAC,GAAG,CAChB,QAAQ;SACN,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;SACtB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CACX,GAAG,CAAC,GAAG;SACL,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;SAClD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,CACpE,CACF,CAAC;AACH,CAAC;AASD,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAAE,GAAG,MAAM,EAAiB,EAAE,CAAC,CAAC;IAC7D,EAAE;IACF,MAAM,EAAE,CAAC;CACT,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACpC,GAAc,EACd,QAA2B,EAC3B,KAAa,EACb,KAAc,EACd,QAAwB;IAExB,IAAI,QAAQ,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,EAAE;YAAE,OAAO;QAChD,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC;IACvB,CAAC;IACD,MAAM,OAAO,GACZ,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5E,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,KAAK,KAAK,OAAO,EAAE,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bot-namespaced session storage — worker-safe (no env, no process, no
|
|
3
|
+
* signals; runs identically on Node and Cloudflare Workers).
|
|
4
|
+
*
|
|
5
|
+
* `botSession(opts)` — drop-in replacement for `@gramio/session`'s
|
|
6
|
+
* `session()` that AUTOMATICALLY namespaces every key with the
|
|
7
|
+
* calling bot's id (parsed from `ctx.bot.options.token`). When
|
|
8
|
+
* several bots share one storage instance, each writes to a
|
|
9
|
+
* disjoint keyspace (`bot-<id>:<senderId>`) with no manual wiring.
|
|
10
|
+
* Every plugin in this package (`accessControl`, `botMenu`,
|
|
11
|
+
* `llmHistory`, …) derives the SAME prefix from `ctx.bot` for its
|
|
12
|
+
* own storage access, so the whole package stays isolated by
|
|
13
|
+
* construction. Use this instead of `session()` — full stop.
|
|
14
|
+
*
|
|
15
|
+
* `prefixStorage(storage, prefix)` — escape hatch that prepends a
|
|
16
|
+
* fixed prefix to every key of any `@gramio/storage` adapter.
|
|
17
|
+
*
|
|
18
|
+
* Peer deps: `gramio`, `@gramio/session`, `@gramio/storage`.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* import { redisStorage } from '@gramio/storage-redis'
|
|
22
|
+
* import { botSession } from '@adriangalilea/utils/bot/session'
|
|
23
|
+
*
|
|
24
|
+
* const storage = redisStorage() // share across bots, safe
|
|
25
|
+
* const userSession = botSession({ storage, initial: () => ({}) })
|
|
26
|
+
* bot.extend(userSession)
|
|
27
|
+
*/
|
|
28
|
+
import { type SessionOptions, session } from "@gramio/session";
|
|
29
|
+
import type { Storage } from "@gramio/storage";
|
|
30
|
+
/**
|
|
31
|
+
* Drop-in replacement for `@gramio/session`'s `session()` that forces
|
|
32
|
+
* the storage key to include the calling bot's id. Equivalent to
|
|
33
|
+
* passing `getSessionKey: (ctx) => bot-${id}:${senderId}` explicitly,
|
|
34
|
+
* but baked in so no consumer can forget.
|
|
35
|
+
*
|
|
36
|
+
* Returns a plain `@gramio/session` plugin — same shape, same derives,
|
|
37
|
+
* fully interchangeable in `.extend(userSession)` chains and plugin
|
|
38
|
+
* options like `accessControl({ session: userSession, … })`.
|
|
39
|
+
*
|
|
40
|
+
* `getSessionKey` can still be overridden for advanced cases (e.g. a
|
|
41
|
+
* per-chat session in groups); the override is wrapped so it still
|
|
42
|
+
* receives the `bot-<id>:` prefix. Don't override unless you know what
|
|
43
|
+
* you're doing — every plugin in this package expects the
|
|
44
|
+
* `bot-<id>:<userId>` shape for cross-user storage reads.
|
|
45
|
+
*/
|
|
46
|
+
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>>;
|
|
47
|
+
/**
|
|
48
|
+
* Wraps any `@gramio/storage` adapter so every key gets a fixed
|
|
49
|
+
* `${prefix}` prepended.
|
|
50
|
+
*
|
|
51
|
+
* **You almost never need this.** The library's plugins are isolated
|
|
52
|
+
* by bot id automatically when you wire `botSession` (see above) —
|
|
53
|
+
* `prefixStorage` exists for edge cases:
|
|
54
|
+
*
|
|
55
|
+
* - Sharing a Redis instance with a NON-bot system, and you want a
|
|
56
|
+
* top-level prefix on top of the bot-id namespace.
|
|
57
|
+
* - Migrating from an older deployment that used a custom prefix.
|
|
58
|
+
*
|
|
59
|
+
* In those cases the wrapper composes cleanly with `botSession`'s
|
|
60
|
+
* internal prefix: final keys look like `${prefix}bot-<id>:<userId>`.
|
|
61
|
+
*/
|
|
62
|
+
export declare const prefixStorage: (storage: Storage, prefix: string) => Storage;
|
|
63
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/bot/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,KAAK,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK/C;;;;;;;;;;;;;;;GAeG;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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bot-namespaced session storage — worker-safe (no env, no process, no
|
|
3
|
+
* signals; runs identically on Node and Cloudflare Workers).
|
|
4
|
+
*
|
|
5
|
+
* `botSession(opts)` — drop-in replacement for `@gramio/session`'s
|
|
6
|
+
* `session()` that AUTOMATICALLY namespaces every key with the
|
|
7
|
+
* calling bot's id (parsed from `ctx.bot.options.token`). When
|
|
8
|
+
* several bots share one storage instance, each writes to a
|
|
9
|
+
* disjoint keyspace (`bot-<id>:<senderId>`) with no manual wiring.
|
|
10
|
+
* Every plugin in this package (`accessControl`, `botMenu`,
|
|
11
|
+
* `llmHistory`, …) derives the SAME prefix from `ctx.bot` for its
|
|
12
|
+
* own storage access, so the whole package stays isolated by
|
|
13
|
+
* construction. Use this instead of `session()` — full stop.
|
|
14
|
+
*
|
|
15
|
+
* `prefixStorage(storage, prefix)` — escape hatch that prepends a
|
|
16
|
+
* fixed prefix to every key of any `@gramio/storage` adapter.
|
|
17
|
+
*
|
|
18
|
+
* Peer deps: `gramio`, `@gramio/session`, `@gramio/storage`.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* import { redisStorage } from '@gramio/storage-redis'
|
|
22
|
+
* import { botSession } from '@adriangalilea/utils/bot/session'
|
|
23
|
+
*
|
|
24
|
+
* const storage = redisStorage() // share across bots, safe
|
|
25
|
+
* const userSession = botSession({ storage, initial: () => ({}) })
|
|
26
|
+
* bot.extend(userSession)
|
|
27
|
+
*/
|
|
28
|
+
import { session } from "@gramio/session";
|
|
29
|
+
import { botId } from "./keys.js";
|
|
30
|
+
// ─── botSession ────────────────────────────────────────────────────
|
|
31
|
+
/**
|
|
32
|
+
* Drop-in replacement for `@gramio/session`'s `session()` that forces
|
|
33
|
+
* the storage key to include the calling bot's id. Equivalent to
|
|
34
|
+
* passing `getSessionKey: (ctx) => bot-${id}:${senderId}` explicitly,
|
|
35
|
+
* but baked in so no consumer can forget.
|
|
36
|
+
*
|
|
37
|
+
* Returns a plain `@gramio/session` plugin — same shape, same derives,
|
|
38
|
+
* fully interchangeable in `.extend(userSession)` chains and plugin
|
|
39
|
+
* options like `accessControl({ session: userSession, … })`.
|
|
40
|
+
*
|
|
41
|
+
* `getSessionKey` can still be overridden for advanced cases (e.g. a
|
|
42
|
+
* per-chat session in groups); the override is wrapped so it still
|
|
43
|
+
* receives the `bot-<id>:` prefix. Don't override unless you know what
|
|
44
|
+
* you're doing — every plugin in this package expects the
|
|
45
|
+
* `bot-<id>:<userId>` shape for cross-user storage reads.
|
|
46
|
+
*/
|
|
47
|
+
export const botSession = (opts) => {
|
|
48
|
+
const userKeyer = opts.getSessionKey;
|
|
49
|
+
return session({
|
|
50
|
+
...opts,
|
|
51
|
+
// The session plugin types `getSessionKey` against `ContextType<BotLike, Events>`
|
|
52
|
+
// — too narrow for our generic wrapper. We only need `bot.info.id` +
|
|
53
|
+
// `senderId`, both of which gramio guarantees on every event the session
|
|
54
|
+
// plugin processes (bot.info is populated by bot.start / bot.init before
|
|
55
|
+
// any handler fires). Structural cast at the boundary keeps the public
|
|
56
|
+
// API generic-friendly without forcing consumers to specify Event unions.
|
|
57
|
+
getSessionKey: (async (ctxRaw) => {
|
|
58
|
+
const ctx = ctxRaw;
|
|
59
|
+
const prefix = `bot-${botId(ctx)}:`;
|
|
60
|
+
if (userKeyer) {
|
|
61
|
+
const inner = await userKeyer(ctx);
|
|
62
|
+
return `${prefix}${inner}`;
|
|
63
|
+
}
|
|
64
|
+
return `${prefix}${ctx.senderId ?? ""}`;
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
// ─── prefixStorage (escape hatch) ──────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Wraps any `@gramio/storage` adapter so every key gets a fixed
|
|
71
|
+
* `${prefix}` prepended.
|
|
72
|
+
*
|
|
73
|
+
* **You almost never need this.** The library's plugins are isolated
|
|
74
|
+
* by bot id automatically when you wire `botSession` (see above) —
|
|
75
|
+
* `prefixStorage` exists for edge cases:
|
|
76
|
+
*
|
|
77
|
+
* - Sharing a Redis instance with a NON-bot system, and you want a
|
|
78
|
+
* top-level prefix on top of the bot-id namespace.
|
|
79
|
+
* - Migrating from an older deployment that used a custom prefix.
|
|
80
|
+
*
|
|
81
|
+
* In those cases the wrapper composes cleanly with `botSession`'s
|
|
82
|
+
* internal prefix: final keys look like `${prefix}bot-<id>:<userId>`.
|
|
83
|
+
*/
|
|
84
|
+
export const prefixStorage = (storage, prefix) => {
|
|
85
|
+
const k = (key) => `${prefix}${String(key)}`;
|
|
86
|
+
return {
|
|
87
|
+
get: (key) => storage.get(k(key)),
|
|
88
|
+
has: (key) => storage.has(k(key)),
|
|
89
|
+
set: (key, value) => storage.set(k(key), value),
|
|
90
|
+
delete: (key) => storage.delete(k(key)),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/bot/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAuB,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,sEAAsE;AAEtE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAKzB,IAAqC,EACS,EAAE;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC;IAKrC,OAAO,OAAO,CAAkB;QAC/B,GAAG,IAAI;QACP,kFAAkF;QAClF,qEAAqE;QACrE,yEAAyE;QACzE,yEAAyE;QACzE,uEAAuE;QACvE,0EAA0E;QAC1E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAChC,MAAM,GAAG,GAAG,MAAgB,CAAC;YAC7B,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YACpC,IAAI,SAAS,EAAE,CAAC;gBACf,MAAM,KAAK,GAAG,MACb,SACA,CAAC,GAAG,CAAC,CAAC;gBACP,OAAO,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC;YAC5B,CAAC;YACD,OAAO,GAAG,MAAM,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACzC,CAAC,CAAqD;KACtD,CAAgD,CAAC;AACnD,CAAC,CAAC;AAEF,sEAAsE;AAEtE;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAAgB,EAAE,MAAc,EAAW,EAAE;IAC1E,MAAM,CAAC,GAAG,CAAC,GAA6B,EAAU,EAAE,CACnD,GAAG,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3B,OAAO;QACN,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;QAC/C,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KACvC,CAAC;AACH,CAAC,CAAC"}
|
package/dist/browser.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* These utilities do not depend on Node.js APIs and can run in the browser.
|
|
4
4
|
*
|
|
5
5
|
* Usage in Next.js client components:
|
|
6
|
-
* import { log,
|
|
6
|
+
* import { log, compact, currency } from '@adriangalilea/utils/browser'
|
|
7
7
|
*/
|
|
8
8
|
export * from "./offensive.js";
|
|
9
9
|
export type { RuntimeCapabilities } from "./runtime.js";
|
package/dist/browser.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* These utilities do not depend on Node.js APIs and can run in the browser.
|
|
4
4
|
*
|
|
5
5
|
* Usage in Next.js client components:
|
|
6
|
-
* import { log,
|
|
6
|
+
* import { log, compact, currency } from '@adriangalilea/utils/browser'
|
|
7
7
|
*/
|
|
8
8
|
// Offensive programming - adapted for browser (throws instead of process.exit)
|
|
9
9
|
export * from "./offensive.js";
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* Run 'npm run update-crypto' to refresh
|
|
6
|
-
*/
|
|
7
|
-
export declare const cryptoSymbols: Set<string>;
|
|
8
|
-
/**
|
|
9
|
-
* Check if a symbol is a known cryptocurrency
|
|
10
|
-
* @param symbol - The symbol to check (case-insensitive)
|
|
11
|
-
* @returns true if the symbol is in the crypto list
|
|
2
|
+
* Check if a symbol is a known cryptocurrency (case-insensitive).
|
|
3
|
+
* Backed by the CoinGecko list in crypto-symbols-data.ts —
|
|
4
|
+
* run 'npm run update-crypto' to refresh.
|
|
12
5
|
*
|
|
13
6
|
* @example
|
|
14
7
|
* isCryptoSymbol("BTC") // true
|
|
15
8
|
* isCryptoSymbol("btc") // true
|
|
16
|
-
* isCryptoSymbol("ETH") // true
|
|
17
9
|
* isCryptoSymbol("DOGE") // true
|
|
18
10
|
*/
|
|
19
11
|
export declare function isCryptoSymbol(symbol: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-symbols.d.ts","sourceRoot":"","sources":["../../../src/universal/currency/crypto-symbols.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"crypto-symbols.d.ts","sourceRoot":"","sources":["../../../src/universal/currency/crypto-symbols.ts"],"names":[],"mappings":"AAOA;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGtD"}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import { cryptoSymbolsData } from "./crypto-symbols-data.js";
|
|
2
|
+
// The Set builds on FIRST LOOKUP, not at import: the dataset is ~133KB and
|
|
3
|
+
// most consumers of the currency module never ask "is this crypto?". Laziness
|
|
4
|
+
// costs one `??=`; eagerness costs every import a startup parse of 8k symbols.
|
|
5
|
+
let cryptoSymbols;
|
|
2
6
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Run 'npm run update-crypto' to refresh
|
|
7
|
-
*/
|
|
8
|
-
export const cryptoSymbols = new Set(cryptoSymbolsData);
|
|
9
|
-
/**
|
|
10
|
-
* Check if a symbol is a known cryptocurrency
|
|
11
|
-
* @param symbol - The symbol to check (case-insensitive)
|
|
12
|
-
* @returns true if the symbol is in the crypto list
|
|
7
|
+
* Check if a symbol is a known cryptocurrency (case-insensitive).
|
|
8
|
+
* Backed by the CoinGecko list in crypto-symbols-data.ts —
|
|
9
|
+
* run 'npm run update-crypto' to refresh.
|
|
13
10
|
*
|
|
14
11
|
* @example
|
|
15
12
|
* isCryptoSymbol("BTC") // true
|
|
16
13
|
* isCryptoSymbol("btc") // true
|
|
17
|
-
* isCryptoSymbol("ETH") // true
|
|
18
14
|
* isCryptoSymbol("DOGE") // true
|
|
19
15
|
*/
|
|
20
16
|
export function isCryptoSymbol(symbol) {
|
|
17
|
+
cryptoSymbols ??= new Set(cryptoSymbolsData);
|
|
21
18
|
return cryptoSymbols.has(symbol.toUpperCase());
|
|
22
19
|
}
|
|
23
20
|
//# sourceMappingURL=crypto-symbols.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-symbols.js","sourceRoot":"","sources":["../../../src/universal/currency/crypto-symbols.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D
|
|
1
|
+
{"version":3,"file":"crypto-symbols.js","sourceRoot":"","sources":["../../../src/universal/currency/crypto-symbols.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,2EAA2E;AAC3E,8EAA8E;AAC9E,+EAA+E;AAC/E,IAAI,aAAsC,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc;IAC5C,aAAa,KAAK,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC7C,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -42,6 +42,17 @@ export declare function percentageDiff(a: number, b: number): number;
|
|
|
42
42
|
export declare function basisPointsToPercent(bps: number): number;
|
|
43
43
|
export declare function percentToBasisPoints(percent: number): number;
|
|
44
44
|
export declare function formatBasisPoints(bps: number): string;
|
|
45
|
+
/** $1234.56 with optimal decimals; sign before the $. */
|
|
46
|
+
export declare function usd(value: number): string;
|
|
47
|
+
/** Bitcoin with optimal decimals: 0.00001234 ₿ */
|
|
48
|
+
export declare function btc(value: number): string;
|
|
49
|
+
/** Ethereum with optimal decimals: 0.123 Ξ */
|
|
50
|
+
export declare function eth(value: number): string;
|
|
51
|
+
/**
|
|
52
|
+
* Format a value in any currency: symbol before for fiat/stablecoins
|
|
53
|
+
* (`$12.34`), after for crypto (`0.5 ₿`), optimal decimals either way.
|
|
54
|
+
*/
|
|
55
|
+
export declare function money(value: number, currencyCode: string): string;
|
|
45
56
|
export declare const currency: {
|
|
46
57
|
getSymbol: typeof getSymbol;
|
|
47
58
|
getOptimalDecimals: typeof getOptimalDecimals;
|
|
@@ -57,6 +68,10 @@ export declare const currency: {
|
|
|
57
68
|
basisPointsToPercent: typeof basisPointsToPercent;
|
|
58
69
|
percentToBasisPoints: typeof percentToBasisPoints;
|
|
59
70
|
formatBasisPoints: typeof formatBasisPoints;
|
|
71
|
+
usd: typeof usd;
|
|
72
|
+
btc: typeof btc;
|
|
73
|
+
eth: typeof eth;
|
|
74
|
+
money: typeof money;
|
|
60
75
|
symbols: {
|
|
61
76
|
readonly BTC: "₿";
|
|
62
77
|
readonly XBT: "₿";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/universal/currency/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BlB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,eAAe,GAAG,MAAM,CAAC;AAEjE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GAClB,MAAM,CAgER;AA4CD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA2BhD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAatD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAmB9C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAclD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkC5C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,eAAO,MAAM,QAAQ
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/universal/currency/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BlB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,eAAe,GAAG,MAAM,CAAC;AAEjE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GAClB,MAAM,CAgER;AA4CD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA2BhD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAatD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAmB9C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAclD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAkC5C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAOD,yDAAyD;AACzD,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzC;AAED,kDAAkD;AAClD,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,8CAA8C;AAC9C,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAQjE;AAED,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoBpB,CAAC"}
|
|
@@ -293,6 +293,37 @@ export function percentToBasisPoints(percent) {
|
|
|
293
293
|
export function formatBasisPoints(bps) {
|
|
294
294
|
return `${bps} bps`;
|
|
295
295
|
}
|
|
296
|
+
// ── money formatting ───────────────────────────────────────────────
|
|
297
|
+
// Lives HERE, not in universal/format: formatting money needs the symbol +
|
|
298
|
+
// optimal-decimals knowledge (and, transitively, the crypto dataset), and the
|
|
299
|
+
// pure format module must stay free of that weight.
|
|
300
|
+
/** $1234.56 with optimal decimals; sign before the $. */
|
|
301
|
+
export function usd(value) {
|
|
302
|
+
const decimals = getOptimalDecimals(value, "USD");
|
|
303
|
+
const formatted = Math.abs(value).toFixed(decimals);
|
|
304
|
+
return value < 0 ? `-$${formatted}` : `$${formatted}`;
|
|
305
|
+
}
|
|
306
|
+
/** Bitcoin with optimal decimals: 0.00001234 ₿ */
|
|
307
|
+
export function btc(value) {
|
|
308
|
+
return `${value.toFixed(getOptimalDecimals(value, "BTC"))} ₿`;
|
|
309
|
+
}
|
|
310
|
+
/** Ethereum with optimal decimals: 0.123 Ξ */
|
|
311
|
+
export function eth(value) {
|
|
312
|
+
return `${value.toFixed(getOptimalDecimals(value, "ETH"))} Ξ`;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Format a value in any currency: symbol before for fiat/stablecoins
|
|
316
|
+
* (`$12.34`), after for crypto (`0.5 ₿`), optimal decimals either way.
|
|
317
|
+
*/
|
|
318
|
+
export function money(value, currencyCode) {
|
|
319
|
+
const decimals = getOptimalDecimals(value, currencyCode);
|
|
320
|
+
const symbol = getSymbol(currencyCode);
|
|
321
|
+
const formatted = Math.abs(value).toFixed(decimals);
|
|
322
|
+
if (isFiat(currencyCode) || isStablecoin(currencyCode)) {
|
|
323
|
+
return value < 0 ? `-${symbol}${formatted}` : `${symbol}${formatted}`;
|
|
324
|
+
}
|
|
325
|
+
return value < 0 ? `-${formatted} ${symbol}` : `${formatted} ${symbol}`;
|
|
326
|
+
}
|
|
296
327
|
export const currency = {
|
|
297
328
|
getSymbol,
|
|
298
329
|
getOptimalDecimals,
|
|
@@ -308,6 +339,10 @@ export const currency = {
|
|
|
308
339
|
basisPointsToPercent,
|
|
309
340
|
percentToBasisPoints,
|
|
310
341
|
formatBasisPoints,
|
|
342
|
+
usd,
|
|
343
|
+
btc,
|
|
344
|
+
eth,
|
|
345
|
+
money,
|
|
311
346
|
symbols: CurrencySymbols,
|
|
312
347
|
};
|
|
313
348
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/universal/currency/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/universal/currency/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,40 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Pure number formatting. No currency coupling — money formatting (usd, btc,
|
|
3
|
+
* money(value, code), …) lives in ./currency, which owns the symbol/decimals
|
|
4
|
+
* knowledge and its 133KB crypto-symbol dataset. Keeping this module pure is
|
|
5
|
+
* what lets a browser bundle import `compact` without shipping that dataset.
|
|
6
|
+
*
|
|
7
|
+
* Named exports only (no namespace object): a namespace keeps every function
|
|
8
|
+
* — and its imports — alive in the bundle; named imports tree-shake.
|
|
3
9
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Format a value as USD with optimal decimals
|
|
11
|
-
*/
|
|
12
|
-
usd(value: number): string;
|
|
13
|
-
/**
|
|
14
|
-
* Format a value as Bitcoin with optimal decimals
|
|
15
|
-
*/
|
|
16
|
-
btc(value: number): string;
|
|
17
|
-
/**
|
|
18
|
-
* Format a value as Ethereum with optimal decimals
|
|
19
|
-
*/
|
|
20
|
-
eth(value: number): string;
|
|
21
|
-
/**
|
|
22
|
-
* Auto format a value with the appropriate currency symbol and decimals
|
|
23
|
-
*/
|
|
24
|
-
auto(value: number, currencyCode: string): string;
|
|
25
|
-
/**
|
|
26
|
-
* Format a percentage with smart decimal places
|
|
27
|
-
*/
|
|
28
|
-
percentage(value: number): string;
|
|
29
|
-
/**
|
|
30
|
-
* Format a value with thousands separators
|
|
31
|
-
*/
|
|
32
|
-
withCommas(value: number, decimals?: number): string;
|
|
33
|
-
/**
|
|
34
|
-
* Format a value in compact notation (1.2K, 3.4M, etc)
|
|
35
|
-
*/
|
|
36
|
-
compact(value: number): string;
|
|
37
|
-
}
|
|
38
|
-
export declare const format: FormatOps;
|
|
39
|
-
export {};
|
|
10
|
+
/** Compact notation: 1.2K, 3.4M, … (Intl, en). */
|
|
11
|
+
export declare function compact(value: number): string;
|
|
12
|
+
/** Percentage with smart decimals: 2 below 0.1, 0 at ≥100, else 1. */
|
|
13
|
+
export declare function percentage(value: number): string;
|
|
14
|
+
/** Thousands separators: 1,234,567.89 (optionally fixed decimals). */
|
|
15
|
+
export declare function withCommas(value: number, decimals?: number): string;
|
|
40
16
|
//# sourceMappingURL=format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/universal/format.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/universal/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kDAAkD;AAClD,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK7C;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAMnE"}
|
package/dist/universal/format.js
CHANGED
|
@@ -1,83 +1,35 @@
|
|
|
1
|
-
import { getOptimalDecimals, getSymbol, isFiat, isStablecoin, } from "./currency/index.js";
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
2
|
+
* Pure number formatting. No currency coupling — money formatting (usd, btc,
|
|
3
|
+
* money(value, code), …) lives in ./currency, which owns the symbol/decimals
|
|
4
|
+
* knowledge and its 133KB crypto-symbol dataset. Keeping this module pure is
|
|
5
|
+
* what lets a browser bundle import `compact` without shipping that dataset.
|
|
6
|
+
*
|
|
7
|
+
* Named exports only (no namespace object): a namespace keeps every function
|
|
8
|
+
* — and its imports — alive in the bundle; named imports tree-shake.
|
|
4
9
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const formatted = Math.abs(value).toFixed(decimals);
|
|
18
|
-
return value < 0 ? `-$${formatted}` : `$${formatted}`;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Format a value as Bitcoin with optimal decimals
|
|
22
|
-
*/
|
|
23
|
-
btc(value) {
|
|
24
|
-
const decimals = getOptimalDecimals(value, "BTC");
|
|
25
|
-
return `${value.toFixed(decimals)} ₿`;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Format a value as Ethereum with optimal decimals
|
|
29
|
-
*/
|
|
30
|
-
eth(value) {
|
|
31
|
-
const decimals = getOptimalDecimals(value, "ETH");
|
|
32
|
-
return `${value.toFixed(decimals)} Ξ`;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Auto format a value with the appropriate currency symbol and decimals
|
|
36
|
-
*/
|
|
37
|
-
auto(value, currencyCode) {
|
|
38
|
-
const decimals = getOptimalDecimals(value, currencyCode);
|
|
39
|
-
const symbol = getSymbol(currencyCode);
|
|
40
|
-
const formatted = Math.abs(value).toFixed(decimals);
|
|
41
|
-
// Put symbol before for fiat/stablecoins, after for crypto
|
|
42
|
-
if (isFiat(currencyCode) || isStablecoin(currencyCode)) {
|
|
43
|
-
return value < 0 ? `-${symbol}${formatted}` : `${symbol}${formatted}`;
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
return value < 0 ? `-${formatted} ${symbol}` : `${formatted} ${symbol}`;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Format a percentage with smart decimal places
|
|
51
|
-
*/
|
|
52
|
-
percentage(value) {
|
|
53
|
-
let decimals = 1;
|
|
54
|
-
if (Math.abs(value) < 0.1) {
|
|
55
|
-
decimals = 2;
|
|
56
|
-
}
|
|
57
|
-
else if (Math.abs(value) >= 100) {
|
|
58
|
-
decimals = 0;
|
|
59
|
-
}
|
|
60
|
-
return `${value.toFixed(decimals)}%`;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Format a value with thousands separators
|
|
64
|
-
*/
|
|
65
|
-
withCommas(value, decimals) {
|
|
66
|
-
const fixed = decimals !== undefined ? value.toFixed(decimals) : value.toString();
|
|
67
|
-
const parts = fixed.split(".");
|
|
68
|
-
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
69
|
-
return parts.join(".");
|
|
10
|
+
/** Compact notation: 1.2K, 3.4M, … (Intl, en). */
|
|
11
|
+
export function compact(value) {
|
|
12
|
+
return new Intl.NumberFormat("en", {
|
|
13
|
+
notation: "compact",
|
|
14
|
+
maximumFractionDigits: 1,
|
|
15
|
+
}).format(value);
|
|
16
|
+
}
|
|
17
|
+
/** Percentage with smart decimals: 2 below 0.1, 0 at ≥100, else 1. */
|
|
18
|
+
export function percentage(value) {
|
|
19
|
+
let decimals = 1;
|
|
20
|
+
if (Math.abs(value) < 0.1) {
|
|
21
|
+
decimals = 2;
|
|
70
22
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*/
|
|
74
|
-
compact(value) {
|
|
75
|
-
const formatter = new Intl.NumberFormat("en", {
|
|
76
|
-
notation: "compact",
|
|
77
|
-
maximumFractionDigits: 1,
|
|
78
|
-
});
|
|
79
|
-
return formatter.format(value);
|
|
23
|
+
else if (Math.abs(value) >= 100) {
|
|
24
|
+
decimals = 0;
|
|
80
25
|
}
|
|
26
|
+
return `${value.toFixed(decimals)}%`;
|
|
27
|
+
}
|
|
28
|
+
/** Thousands separators: 1,234,567.89 (optionally fixed decimals). */
|
|
29
|
+
export function withCommas(value, decimals) {
|
|
30
|
+
const fixed = decimals !== undefined ? value.toFixed(decimals) : value.toString();
|
|
31
|
+
const parts = fixed.split(".");
|
|
32
|
+
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
33
|
+
return parts.join(".");
|
|
81
34
|
}
|
|
82
|
-
export const format = new FormatOps();
|
|
83
35
|
//# sourceMappingURL=format.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/universal/format.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/universal/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kDAAkD;AAClD,MAAM,UAAU,OAAO,CAAC,KAAa;IACpC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;QAClC,QAAQ,EAAE,SAAS;QACnB,qBAAqB,EAAE,CAAC;KACxB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClB,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,UAAU,CAAC,KAAa;IACvC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,CAAC;QAC3B,QAAQ,GAAG,CAAC,CAAC;IACd,CAAC;SAAM,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;QACnC,QAAQ,GAAG,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;AACtC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,QAAiB;IAC1D,MAAM,KAAK,GACV,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACrE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;IAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adriangalilea/utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "TypeScript utilities - logger, currency, formatter, GramIO bot plugins, and more",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -87,6 +87,14 @@
|
|
|
87
87
|
"./bot/callbacks": {
|
|
88
88
|
"types": "./dist/bot/callbacks.d.ts",
|
|
89
89
|
"default": "./dist/bot/callbacks.js"
|
|
90
|
+
},
|
|
91
|
+
"./bot/session": {
|
|
92
|
+
"types": "./dist/bot/session.d.ts",
|
|
93
|
+
"default": "./dist/bot/session.js"
|
|
94
|
+
},
|
|
95
|
+
"./bot/notify": {
|
|
96
|
+
"types": "./dist/bot/notify.d.ts",
|
|
97
|
+
"default": "./dist/bot/notify.js"
|
|
90
98
|
}
|
|
91
99
|
},
|
|
92
100
|
"files": [
|
|
@@ -170,5 +178,6 @@
|
|
|
170
178
|
"bugs": {
|
|
171
179
|
"url": "https://github.com/adriangalilea/ts-utils/issues"
|
|
172
180
|
},
|
|
173
|
-
"homepage": "https://github.com/adriangalilea/ts-utils#readme"
|
|
181
|
+
"homepage": "https://github.com/adriangalilea/ts-utils#readme",
|
|
182
|
+
"sideEffects": false
|
|
174
183
|
}
|