@adriangalilea/utils 0.7.0 → 0.9.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 +29 -5
- package/dist/bot/access-control.d.ts +106 -62
- package/dist/bot/access-control.d.ts.map +1 -1
- package/dist/bot/access-control.js +255 -146
- package/dist/bot/access-control.js.map +1 -1
- package/dist/bot/index.d.ts +3 -0
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +3 -0
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/kit.d.ts.map +1 -1
- package/dist/bot/kit.js +6 -0
- package/dist/bot/kit.js.map +1 -1
- package/dist/bot/language.d.ts +305 -0
- package/dist/bot/language.d.ts.map +1 -0
- package/dist/bot/language.js +250 -0
- package/dist/bot/language.js.map +1 -0
- package/dist/bot/menu.d.ts +189 -0
- package/dist/bot/menu.d.ts.map +1 -0
- package/dist/bot/menu.js +331 -0
- package/dist/bot/menu.js.map +1 -0
- package/dist/bot/message-history.d.ts +259 -0
- package/dist/bot/message-history.d.ts.map +1 -0
- package/dist/bot/message-history.js +111 -0
- package/dist/bot/message-history.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/say/index.d.ts +62 -0
- package/dist/say/index.d.ts.map +1 -0
- package/dist/say/index.js +59 -0
- package/dist/say/index.js.map +1 -0
- package/package.json +17 -1
- package/dist/currency/crypto-symbols-data.d.ts +0 -10
- package/dist/currency/crypto-symbols-data.d.ts.map +0 -1
- package/dist/currency/crypto-symbols-data.js +0 -13765
- package/dist/currency/crypto-symbols-data.js.map +0 -1
- package/dist/currency/crypto-symbols.d.ts +0 -20
- package/dist/currency/crypto-symbols.d.ts.map +0 -1
- package/dist/currency/crypto-symbols.js +0 -23
- package/dist/currency/crypto-symbols.js.map +0 -1
- package/dist/currency/download-crypto-list.d.ts +0 -10
- package/dist/currency/download-crypto-list.d.ts.map +0 -1
- package/dist/currency/download-crypto-list.js +0 -69
- package/dist/currency/download-crypto-list.js.map +0 -1
- package/dist/currency/index.d.ts +0 -84
- package/dist/currency/index.d.ts.map +0 -1
- package/dist/currency/index.js +0 -230
- package/dist/currency/index.js.map +0 -1
- package/dist/dir.d.ts +0 -40
- package/dist/dir.d.ts.map +0 -1
- package/dist/dir.js +0 -108
- package/dist/dir.js.map +0 -1
- package/dist/file.d.ts +0 -53
- package/dist/file.d.ts.map +0 -1
- package/dist/file.js +0 -211
- package/dist/file.js.map +0 -1
- package/dist/format.d.ts +0 -40
- package/dist/format.d.ts.map +0 -1
- package/dist/format.js +0 -83
- package/dist/format.js.map +0 -1
- package/dist/kev.d.ts +0 -149
- package/dist/kev.d.ts.map +0 -1
- package/dist/kev.js +0 -761
- package/dist/kev.js.map +0 -1
- package/dist/log.d.ts +0 -91
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js +0 -300
- package/dist/log.js.map +0 -1
- package/dist/logger.d.ts +0 -91
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -269
- package/dist/logger.js.map +0 -1
- package/dist/path.d.ts +0 -67
- package/dist/path.d.ts.map +0 -1
- package/dist/path.js +0 -107
- package/dist/path.js.map +0 -1
- package/dist/project.d.ts +0 -35
- package/dist/project.d.ts.map +0 -1
- package/dist/project.js +0 -154
- package/dist/project.js.map +0 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-user rolling message history for GramIO bots — opt-in, with
|
|
3
|
+
* retention.
|
|
4
|
+
*
|
|
5
|
+
* Follows the same shared-session pattern as `bot/language`: the
|
|
6
|
+
* user creates a `session()` once at bot level, and each feature
|
|
7
|
+
* plugin (including this one) declares it as a dependency. gramio
|
|
8
|
+
* dedupes the runtime extension; the types flow.
|
|
9
|
+
*
|
|
10
|
+
* ## What this plugin owns
|
|
11
|
+
*
|
|
12
|
+
* - Appends each incoming user message to `ctx.session.history.items`
|
|
13
|
+
* - Prunes entries older than `retentionDays` or beyond `maxMessages`
|
|
14
|
+
* - Exposes a read-only pruned snapshot at `ctx.history` for handlers
|
|
15
|
+
*
|
|
16
|
+
* ## GDPR caveat — retention IS personal data
|
|
17
|
+
*
|
|
18
|
+
* Unlike `bot/language` (preference data, covered by Telegram's standard
|
|
19
|
+
* privacy policy), retaining user **message content** is the one thing
|
|
20
|
+
* the [standard policy](https://telegram.org/privacy-tpa) does NOT cover
|
|
21
|
+
* by default. If you extend `messageHistory`, you should:
|
|
22
|
+
*
|
|
23
|
+
* 1. Set a custom `privacy` URL on your `botMenu` describing what you
|
|
24
|
+
* retain and for how long.
|
|
25
|
+
* 2. Pass `personalData: { storage }` to your `botMenu` so 🗑 Forget
|
|
26
|
+
* and 📥 Export buttons appear — letting users see and delete
|
|
27
|
+
* the data you keep about them.
|
|
28
|
+
*
|
|
29
|
+
* These are not enforced by this plugin (would couple it to menu); they
|
|
30
|
+
* are documented as the bot author's legal responsibility.
|
|
31
|
+
*
|
|
32
|
+
* ## Storage layout
|
|
33
|
+
*
|
|
34
|
+
* Lives entirely inside the shared session record:
|
|
35
|
+
*
|
|
36
|
+
* storage[String(senderId)] = {
|
|
37
|
+
* ...other plugins' fields,
|
|
38
|
+
* history: { items: [HistoryEntry, ...] }
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* Peer deps: `gramio`, `@gramio/session`.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* import { Bot } from 'gramio'
|
|
45
|
+
* import { session } from '@gramio/session'
|
|
46
|
+
* import { redisStorage } from '@gramio/storage-redis'
|
|
47
|
+
* import { messageHistory } from '@adriangalilea/utils/bot/message-history'
|
|
48
|
+
*
|
|
49
|
+
* const userSession = session({ storage: redisStorage(), key: 'session', initial: () => ({}) })
|
|
50
|
+
*
|
|
51
|
+
* const history = messageHistory({
|
|
52
|
+
* session: userSession,
|
|
53
|
+
* maxMessages: 100,
|
|
54
|
+
* retentionDays: 7,
|
|
55
|
+
* })
|
|
56
|
+
*
|
|
57
|
+
* const bot = new Bot(process.env.BOT_TOKEN!)
|
|
58
|
+
* .extend(userSession)
|
|
59
|
+
* .extend(history.plugin)
|
|
60
|
+
* .command('replay', (ctx) => {
|
|
61
|
+
* const last = ctx.history.slice(-3).map((e) => e.text).join('\n---\n')
|
|
62
|
+
* return ctx.send(last || '(no history)')
|
|
63
|
+
* })
|
|
64
|
+
*/
|
|
65
|
+
import { Plugin } from 'gramio';
|
|
66
|
+
// ─── helpers ───────────────────────────────────────────────────────
|
|
67
|
+
const prune = (items, maxMessages, retentionDays) => {
|
|
68
|
+
const cutoffSec = Math.floor(Date.now() / 1000) - retentionDays * 86400;
|
|
69
|
+
const fresh = items.filter((e) => e.date >= cutoffSec);
|
|
70
|
+
return fresh.slice(-maxMessages);
|
|
71
|
+
};
|
|
72
|
+
// ─── feature factory ───────────────────────────────────────────────
|
|
73
|
+
export const messageHistory = (opts) => {
|
|
74
|
+
if (opts.maxMessages <= 0)
|
|
75
|
+
throw new Error('messageHistory: maxMessages must be > 0');
|
|
76
|
+
if (opts.retentionDays <= 0)
|
|
77
|
+
throw new Error('messageHistory: retentionDays must be > 0');
|
|
78
|
+
const plugin = buildHistoryPlugin({
|
|
79
|
+
sessionPlugin: opts.session,
|
|
80
|
+
maxMessages: opts.maxMessages,
|
|
81
|
+
retentionDays: opts.retentionDays,
|
|
82
|
+
});
|
|
83
|
+
return { plugin };
|
|
84
|
+
};
|
|
85
|
+
// ─── plugin builder ────────────────────────────────────────────────
|
|
86
|
+
const buildHistoryPlugin = (args) => {
|
|
87
|
+
const { sessionPlugin, maxMessages, retentionDays } = args;
|
|
88
|
+
return new Plugin('@adriangalilea/utils/bot/message-history')
|
|
89
|
+
.extend(sessionPlugin)
|
|
90
|
+
// Record incoming messages with text. Service messages, edits,
|
|
91
|
+
// and callback queries don't append — only direct user input.
|
|
92
|
+
.on('message', async (ctx, next) => {
|
|
93
|
+
if (ctx.text !== undefined) {
|
|
94
|
+
const entry = {
|
|
95
|
+
messageId: ctx.id,
|
|
96
|
+
date: ctx.payload.date,
|
|
97
|
+
text: ctx.text,
|
|
98
|
+
};
|
|
99
|
+
const cur = ctx.session.history?.items ?? [];
|
|
100
|
+
ctx.session.history = {
|
|
101
|
+
items: [...prune(cur, maxMessages, retentionDays), entry].slice(-maxMessages),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return next();
|
|
105
|
+
})
|
|
106
|
+
// Pruned read-only view for handlers downstream.
|
|
107
|
+
.derive(['message', 'callback_query'], (ctx) => ({
|
|
108
|
+
history: prune(ctx.session.history?.items ?? [], maxMessages, retentionDays),
|
|
109
|
+
}));
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=message-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-history.js","sourceRoot":"","sources":["../../src/bot/message-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,OAAO,EAA0B,MAAM,EAAE,MAAM,QAAQ,CAAA;AA8CvD,sEAAsE;AAEtE,MAAM,KAAK,GAAG,CACZ,KAAqB,EACrB,WAAmB,EACnB,aAAqB,EACL,EAAE;IAClB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,aAAa,GAAG,KAAK,CAAA;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,CAAA;IACtD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAA;AAClC,CAAC,CAAA;AAED,sEAAsE;AAEtE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAA2B,EAAyB,EAAE;IACnF,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;IACrF,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAEzF,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,aAAa,EAAE,IAAI,CAAC,OAAO;QAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;KAClC,CAAC,CAAA;IAEF,OAAO,EAAE,MAAM,EAAE,CAAA;AACnB,CAAC,CAAA;AAED,sEAAsE;AAEtE,MAAM,kBAAkB,GAAG,CAAC,IAI3B,EAAE,EAAE;IACH,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,IAAI,CAAA;IAE1D,OAAO,IAAI,MAAM,CACf,0CAA0C,CAC3C;SACE,MAAM,CAAC,aAAa,CAAC;QACtB,+DAA+D;QAC/D,8DAA8D;SAC7D,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACjC,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAiB;gBAC1B,SAAS,EAAE,GAAG,CAAC,EAAE;gBACjB,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI;aACf,CAAA;YACD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAA;YAC5C,GAAG,CAAC,OAAO,CAAC,OAAO,GAAG;gBACpB,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,CAC7D,CAAC,WAAW,CACb;aACF,CAAA;QACH,CAAC;QACD,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAC;QACF,iDAAiD;SAChD,MAAM,CAAC,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAkB,EAAE,CAAC,CAAC;QAC/D,OAAO,EAAE,KAAK,CACZ,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,EAChC,WAAW,EACX,aAAa,CACiB;KACjC,CAAC,CAAC,CAAA;AACP,CAAC,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from './universal/log.js';
|
|
|
8
8
|
export * from './universal/format.js';
|
|
9
9
|
export * from './universal/currency/index.js';
|
|
10
10
|
export * from './offensive.js';
|
|
11
|
+
export * from './say/index.js';
|
|
11
12
|
export * from './platform/file.js';
|
|
12
13
|
export * from './platform/dir.js';
|
|
13
14
|
export * from './platform/path.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAGvD,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAG7C,cAAc,gBAAgB,CAAA;AAI9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAGvD,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAG7C,cAAc,gBAAgB,CAAA;AAG9B,cAAc,gBAAgB,CAAA;AAI9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export * from './universal/format.js';
|
|
|
10
10
|
export * from './universal/currency/index.js';
|
|
11
11
|
// Offensive programming - pure throws, zero dependencies
|
|
12
12
|
export * from './offensive.js';
|
|
13
|
+
// Polyglot strings — TS-enforced multi-language values
|
|
14
|
+
export * from './say/index.js';
|
|
13
15
|
// Platform-specific utilities
|
|
14
16
|
// These will throw helpful errors in browser environment when used
|
|
15
17
|
export * from './platform/file.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8CAA8C;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC,wCAAwC;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAE7C,yDAAyD;AACzD,cAAc,gBAAgB,CAAA;AAE9B,8BAA8B;AAC9B,mEAAmE;AACnE,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8CAA8C;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC,wCAAwC;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAE7C,yDAAyD;AACzD,cAAc,gBAAgB,CAAA;AAE9B,uDAAuD;AACvD,cAAc,gBAAgB,CAAA;AAE9B,8BAA8B;AAC9B,mEAAmE;AACnE,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,sBAAsB,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `say` — TypeScript-enforced polyglot strings, framework-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* A "polyglot value" is a plain object literal with one string per
|
|
5
|
+
* supported language:
|
|
6
|
+
*
|
|
7
|
+
* { en: 'Hello', es: 'Hola' }
|
|
8
|
+
*
|
|
9
|
+
* The keys are the source of truth. There is no JSON file, no key
|
|
10
|
+
* registry, no extraction tool, no namespaces. The TS compiler
|
|
11
|
+
* enforces completeness: add a language to the plugin's `supported`
|
|
12
|
+
* list and every call site without that key becomes a compile error.
|
|
13
|
+
*
|
|
14
|
+
* Two entry points:
|
|
15
|
+
*
|
|
16
|
+
* `say(value, lang)` — pure resolver, no context, returns string.
|
|
17
|
+
* Use it for 3rd-party SDKs / cron / email
|
|
18
|
+
* / anything outside a bot ctx.
|
|
19
|
+
*
|
|
20
|
+
* `ctx.say(value)` — bot-bound; uses `ctx.lang`. Provided by
|
|
21
|
+
* `bot/language` (see that plugin for the
|
|
22
|
+
* `ctx.say.send / .edit / .answer` methods).
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* import { say, type Polyglot } from '@adriangalilea/utils/say'
|
|
26
|
+
*
|
|
27
|
+
* await pushover.send({
|
|
28
|
+
* message: say({ en: 'Drop!', es: '¡Drop!' }, user.lang),
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* // typing your own adapter:
|
|
32
|
+
* const notify = (msg: string | Polyglot<'en' | 'es'>, lang: 'en' | 'es') =>
|
|
33
|
+
* transport.send(typeof msg === 'string' ? msg : say(msg, lang))
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* A value that exists in N languages. `L` is the union of supported
|
|
37
|
+
* language tags (typically inferred from the object literal's keys).
|
|
38
|
+
*
|
|
39
|
+
* Authoring: `{ en: 'Hi', es: 'Hola' }` — TS infers `L = 'en' | 'es'`.
|
|
40
|
+
*
|
|
41
|
+
* Typing your own API: `function notify(msg: Polyglot<'en' | 'es'>)`
|
|
42
|
+
* — callers must provide both keys.
|
|
43
|
+
*/
|
|
44
|
+
export type Polyglot<L extends string> = Readonly<Record<L, string>>;
|
|
45
|
+
/**
|
|
46
|
+
* Resolve a polyglot value to a string at `lang`.
|
|
47
|
+
*
|
|
48
|
+
* If `lang` is missing from `value`, returns the first available key
|
|
49
|
+
* (lexicographic). This is a structural fallback — it should never
|
|
50
|
+
* happen when `lang` is constrained by the same `L` as `value`'s
|
|
51
|
+
* keys; it exists only for the dynamic-string escape hatch.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* say({ en: 'Hi', es: 'Hola' }, 'es') // → 'Hola'
|
|
55
|
+
* say({ en: 'Hi', es: 'Hola' }, 'fr') // TS error: '"fr"' not in '"en" | "es"'
|
|
56
|
+
*
|
|
57
|
+
* @example // typing-loose escape hatch with `as Polyglot<string>`
|
|
58
|
+
* const raw: Polyglot<string> = JSON.parse(blob)
|
|
59
|
+
* say(raw, userLang) // dynamic, falls back if missing
|
|
60
|
+
*/
|
|
61
|
+
export declare const say: <L extends string>(value: Polyglot<L>, lang: L) => string;
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/say/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,MAAM,EAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,KAAG,MAKnE,CAAA"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `say` — TypeScript-enforced polyglot strings, framework-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* A "polyglot value" is a plain object literal with one string per
|
|
5
|
+
* supported language:
|
|
6
|
+
*
|
|
7
|
+
* { en: 'Hello', es: 'Hola' }
|
|
8
|
+
*
|
|
9
|
+
* The keys are the source of truth. There is no JSON file, no key
|
|
10
|
+
* registry, no extraction tool, no namespaces. The TS compiler
|
|
11
|
+
* enforces completeness: add a language to the plugin's `supported`
|
|
12
|
+
* list and every call site without that key becomes a compile error.
|
|
13
|
+
*
|
|
14
|
+
* Two entry points:
|
|
15
|
+
*
|
|
16
|
+
* `say(value, lang)` — pure resolver, no context, returns string.
|
|
17
|
+
* Use it for 3rd-party SDKs / cron / email
|
|
18
|
+
* / anything outside a bot ctx.
|
|
19
|
+
*
|
|
20
|
+
* `ctx.say(value)` — bot-bound; uses `ctx.lang`. Provided by
|
|
21
|
+
* `bot/language` (see that plugin for the
|
|
22
|
+
* `ctx.say.send / .edit / .answer` methods).
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* import { say, type Polyglot } from '@adriangalilea/utils/say'
|
|
26
|
+
*
|
|
27
|
+
* await pushover.send({
|
|
28
|
+
* message: say({ en: 'Drop!', es: '¡Drop!' }, user.lang),
|
|
29
|
+
* })
|
|
30
|
+
*
|
|
31
|
+
* // typing your own adapter:
|
|
32
|
+
* const notify = (msg: string | Polyglot<'en' | 'es'>, lang: 'en' | 'es') =>
|
|
33
|
+
* transport.send(typeof msg === 'string' ? msg : say(msg, lang))
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a polyglot value to a string at `lang`.
|
|
37
|
+
*
|
|
38
|
+
* If `lang` is missing from `value`, returns the first available key
|
|
39
|
+
* (lexicographic). This is a structural fallback — it should never
|
|
40
|
+
* happen when `lang` is constrained by the same `L` as `value`'s
|
|
41
|
+
* keys; it exists only for the dynamic-string escape hatch.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* say({ en: 'Hi', es: 'Hola' }, 'es') // → 'Hola'
|
|
45
|
+
* say({ en: 'Hi', es: 'Hola' }, 'fr') // TS error: '"fr"' not in '"en" | "es"'
|
|
46
|
+
*
|
|
47
|
+
* @example // typing-loose escape hatch with `as Polyglot<string>`
|
|
48
|
+
* const raw: Polyglot<string> = JSON.parse(blob)
|
|
49
|
+
* say(raw, userLang) // dynamic, falls back if missing
|
|
50
|
+
*/
|
|
51
|
+
export const say = (value, lang) => {
|
|
52
|
+
const direct = value[lang];
|
|
53
|
+
if (typeof direct === 'string')
|
|
54
|
+
return direct;
|
|
55
|
+
for (const k in value)
|
|
56
|
+
return value[k];
|
|
57
|
+
return '';
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/say/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAaH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAmB,KAAkB,EAAE,IAAO,EAAU,EAAE;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAA;IAC7C,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,CAAM,CAAC,CAAA;IAC3C,OAAO,EAAE,CAAA;AACX,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adriangalilea/utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"types": "./dist/universal/currency/index.d.ts",
|
|
29
29
|
"default": "./dist/universal/currency/index.js"
|
|
30
30
|
},
|
|
31
|
+
"./say": {
|
|
32
|
+
"types": "./dist/say/index.d.ts",
|
|
33
|
+
"default": "./dist/say/index.js"
|
|
34
|
+
},
|
|
31
35
|
"./bot": {
|
|
32
36
|
"types": "./dist/bot/index.d.ts",
|
|
33
37
|
"default": "./dist/bot/index.js"
|
|
@@ -40,6 +44,18 @@
|
|
|
40
44
|
"types": "./dist/bot/coalesce.d.ts",
|
|
41
45
|
"default": "./dist/bot/coalesce.js"
|
|
42
46
|
},
|
|
47
|
+
"./bot/language": {
|
|
48
|
+
"types": "./dist/bot/language.d.ts",
|
|
49
|
+
"default": "./dist/bot/language.js"
|
|
50
|
+
},
|
|
51
|
+
"./bot/menu": {
|
|
52
|
+
"types": "./dist/bot/menu.d.ts",
|
|
53
|
+
"default": "./dist/bot/menu.js"
|
|
54
|
+
},
|
|
55
|
+
"./bot/message-history": {
|
|
56
|
+
"types": "./dist/bot/message-history.d.ts",
|
|
57
|
+
"default": "./dist/bot/message-history.js"
|
|
58
|
+
},
|
|
43
59
|
"./bot/kit": {
|
|
44
60
|
"types": "./dist/bot/kit.d.ts",
|
|
45
61
|
"default": "./dist/bot/kit.js"
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generated on 2025-08-17T10:11:21.771Z
|
|
3
|
-
* 13,754 cryptocurrency symbols from CoinGecko API
|
|
4
|
-
*
|
|
5
|
-
* Run 'npm run update-crypto' to refresh this list
|
|
6
|
-
*/
|
|
7
|
-
export declare const cryptoSymbolsData: readonly string[];
|
|
8
|
-
export declare const lastUpdated = "2025-08-17T10:11:21.771Z";
|
|
9
|
-
export declare const symbolCount = 13754;
|
|
10
|
-
//# sourceMappingURL=crypto-symbols-data.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-symbols-data.d.ts","sourceRoot":"","sources":["../../src/currency/crypto-symbols-data.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EA27a9C,CAAA;AAED,eAAO,MAAM,WAAW,6BAA6B,CAAA;AACrD,eAAO,MAAM,WAAW,QAAQ,CAAA"}
|