@owlmeans/bot 0.1.18-rc.2 → 0.1.18-rc.3
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 +22 -20
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/bot/SKILL.md +68 -46
- package/build/consts.d.ts +6 -31
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +10 -36
- package/build/consts.js.map +1 -1
- package/build/consts.local.d.ts +3 -1
- package/build/consts.local.d.ts.map +1 -1
- package/build/consts.local.js +3 -1
- package/build/consts.local.js.map +1 -1
- package/build/helpers/index.d.ts +2 -2
- package/build/helpers/index.js +1 -1
- package/build/helpers/text/types.d.ts +35 -0
- package/build/helpers/text/types.d.ts.map +1 -0
- package/build/helpers/{rule → text}/types.js.map +1 -1
- package/build/helpers/text.d.ts +4 -0
- package/build/helpers/text.d.ts.map +1 -0
- package/build/helpers/text.js +77 -0
- package/build/helpers/text.js.map +1 -0
- package/build/protocols/types.d.ts +2 -17
- package/build/protocols/types.d.ts.map +1 -1
- package/build/protocols.d.ts +1 -1
- package/build/protocols.d.ts.map +1 -1
- package/build/protocols.js +2 -7
- package/build/protocols.js.map +1 -1
- package/build/schemas.d.ts +2 -4
- package/build/schemas.d.ts.map +1 -1
- package/build/schemas.js +3 -31
- package/build/schemas.js.map +1 -1
- package/build/types.d.ts +7 -41
- package/build/types.d.ts.map +1 -1
- package/build/utils/aliases/types.d.ts +0 -5
- package/build/utils/aliases/types.d.ts.map +1 -1
- package/build/utils/aliases.d.ts.map +1 -1
- package/build/utils/aliases.js +0 -5
- package/build/utils/aliases.js.map +1 -1
- package/package.json +2 -2
- package/src/consts.local.ts +4 -1
- package/src/consts.ts +6 -37
- package/src/helpers/index.ts +2 -2
- package/src/helpers/text/types.ts +35 -0
- package/src/helpers/text.ts +91 -0
- package/src/protocols/types.ts +2 -12
- package/src/protocols.ts +4 -21
- package/src/schemas.ts +5 -39
- package/src/types.ts +7 -45
- package/src/utils/aliases/types.ts +0 -1
- package/src/utils/aliases.ts +0 -5
- package/tests/protocols.spec.ts +3 -7
- package/tests/schemas.spec.ts +2 -30
- package/tests/text.spec.ts +101 -0
- package/tests/update.spec.ts +4 -10
- package/build/helpers/rule/types.d.ts +0 -26
- package/build/helpers/rule/types.d.ts.map +0 -1
- package/build/helpers/rule.d.ts +0 -4
- package/build/helpers/rule.d.ts.map +0 -1
- package/build/helpers/rule.js +0 -71
- package/build/helpers/rule.js.map +0 -1
- package/src/helpers/rule/types.ts +0 -26
- package/src/helpers/rule.ts +0 -89
- package/tests/rule.spec.ts +0 -129
- /package/build/helpers/{rule → text}/types.js +0 -0
package/README.md
CHANGED
|
@@ -1,57 +1,58 @@
|
|
|
1
1
|
# @owlmeans/bot
|
|
2
2
|
|
|
3
3
|
The runtime-free, browser-safe contract of OwlMeans chat bots on Telegram, WhatsApp, Discord and
|
|
4
|
-
Slack: what each platform needs and can do, connections,
|
|
5
|
-
|
|
6
|
-
protocol trees with their AJV schemas, and the bot error family. A shared package imports it to
|
|
4
|
+
Slack: what each platform needs and can do, connections, the one Unicode-aware text helper a
|
|
5
|
+
handler matches message text with, the `/command` parser, normalized updates and activity, the
|
|
6
|
+
managing and hook protocol trees with their AJV schemas, and the bot error family. A shared package imports it to
|
|
7
7
|
declare the bot routes; a server, a store, the panels and an agent's tools build on it. It stores,
|
|
8
8
|
receives and sends nothing — that is `@owlmeans/server-bot`.
|
|
9
9
|
|
|
10
10
|
## Installation
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
bun add @owlmeans/bot@^0.1.18-rc.
|
|
13
|
+
bun add @owlmeans/bot@^0.1.18-rc.3
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## Concepts
|
|
17
17
|
|
|
18
18
|
- **Connection** — one bot account on one platform, owned by a scope (an organization or the
|
|
19
19
|
application). Clients see `BotConnection`, never a credential; `credentialsSet` names the keys set.
|
|
20
|
-
- **
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
- **Update** — an inbound message normalized across platforms (`BotUpdate`). What to do with it is
|
|
21
|
+
the application's handler's decision — it reads the application's own records (keyword groups)
|
|
22
|
+
and compares the text with `botTextHelper.matched`.
|
|
23
|
+
- **Activity** — one thing the bot did or tried (`BotActivity`), recorded with `ok` / `error` and
|
|
24
|
+
the handler's opaque `ref` (e.g. the id of the keyword group it followed).
|
|
25
25
|
- **Descriptor** — `BOT_PLATFORMS[platform]`: credentials, receive modes, platform actions, setup.
|
|
26
26
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
30
|
import { DEFAULT_GUARD } from '@owlmeans/auth-common'
|
|
31
|
-
import { botCommandHelper,
|
|
31
|
+
import { BotTextMatch, botCommandHelper, botTextHelper, makeBotHookProtocols, makeBotProtocols } from '@owlmeans/bot'
|
|
32
32
|
|
|
33
33
|
export const botProtocols = Object.freeze({
|
|
34
34
|
operator: makeBotProtocols({ base: { alias: 'api:bot:operator', path: '/bot/operator' }, guards: DEFAULT_GUARD }),
|
|
35
35
|
hook: makeBotHookProtocols({ base: { alias: 'api:bot:hook', path: '/bot/hook' } }),
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
const
|
|
39
|
-
|
|
38
|
+
const keywords = botTextHelper.phrasesOf('casino, free money') // ['casino', 'free money']
|
|
39
|
+
botTextHelper.matched('Free money at the CASINO!', keywords) // ['casino', 'free money']
|
|
40
|
+
botTextHelper.matched('megacasino.com', ['casino'], BotTextMatch.Contains) // ['casino']
|
|
41
|
+
const command = botCommandHelper.parse('/report@MyBot spam', 'MyBot') // { name: 'report', args: 'spam' }
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
## API
|
|
43
45
|
|
|
44
46
|
- Enums: `BotPlatform`, `BotReceiveMode`, `BotTransport`, `BotConnectionStatus`, `BotActionKind`,
|
|
45
|
-
`
|
|
46
|
-
- Constants: `BOT_PLATFORMS`, `BOT_*` limits (`
|
|
47
|
-
`BOT_ACTIVITY_LIMIT_MAX`, `BOT_ID_PATTERN`, …)
|
|
48
|
-
- Helpers: `
|
|
47
|
+
`BotTextMatch`, `BotUpdateKind`, `BotChatKind`
|
|
48
|
+
- Constants: `BOT_PLATFORMS`, `BOT_*` limits (`BOT_TEXT_MAX`, `BOT_LABEL_MAX`,
|
|
49
|
+
`BOT_ACTIVITY_LIMIT_MAX`, `BOT_ID_PATTERN`, …), `BOT_MANAGE_PERMISSION`
|
|
50
|
+
- Helpers: `botTextHelper` (`fold`, `tokensOf`, `matched`, `phrasesOf`), `botCommandHelper`
|
|
49
51
|
(`parse`), `botPlatformHelper` (`actionsOf`, `supports`)
|
|
50
52
|
- Protocols: `makeBotProtocols`, `makeBotHookProtocols` and their types (`BotProtocols`,
|
|
51
53
|
`BotHookProtocols`, `BotProtocolOptions`, `BotHookProtocolOptions`, …)
|
|
52
|
-
- Schemas: `BotConnectionInputSchema`, `
|
|
53
|
-
`
|
|
54
|
-
`BotChallengeQuerySchema`
|
|
54
|
+
- Schemas: `BotConnectionInputSchema`, `BotSimulateInputSchema`, `BotIdParamsSchema`,
|
|
55
|
+
`BotActivityQuerySchema`, `BotHookParamsSchema`, `BotChallengeQuerySchema`
|
|
55
56
|
- Errors: `BotError`, `BotConnectionNotFound` (404), `BotCredentialsRejected` (422),
|
|
56
57
|
`BotSignatureRejected` (401), `BotTransportMismatch` (409), `BotUnsupportedAction` (422)
|
|
57
58
|
|
|
@@ -61,8 +62,9 @@ const command = botCommandHelper.parse('/report@MyBot spam', 'MyBot') // { nam
|
|
|
61
62
|
- Ask `botPlatformHelper.supports(...)` before an action — WhatsApp cannot delete, mute or ban;
|
|
62
63
|
Slack deletes only with the admin `userToken`.
|
|
63
64
|
- Use `contains` for scripts written without spaces; `word` matches whole words and phrases.
|
|
65
|
+
- `simulate` (mock connections only) is an API route for tests and smoke runs — no UI offers it.
|
|
64
66
|
|
|
65
|
-
The `bot` skill covers matching, the protocols and how a generated target mounts them.
|
|
67
|
+
The `bot` skill covers text matching, the protocols and how a generated target mounts them.
|
|
66
68
|
|
|
67
69
|
## Related packages
|
|
68
70
|
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 3,
|
|
3
3
|
"package": "@owlmeans/bot",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.3",
|
|
5
|
+
"generatedAt": "2026-10-27T13:25:25.418Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bot
|
|
3
|
-
description: How to use @owlmeans/bot — the runtime-free, browser-safe contract of OwlMeans chat bots on Telegram, WhatsApp, Discord and Slack. Covers the platform descriptors (credentials, receive modes, supported actions), connections,
|
|
3
|
+
description: How to use @owlmeans/bot — the runtime-free, browser-safe contract of OwlMeans chat bots on Telegram, WhatsApp, Discord and Slack. Covers the platform descriptors (credentials, receive modes, supported actions), connections, the Unicode-aware text helper a handler matches message text with, the /command parser, normalized updates and activity (with the handler's opaque `ref`), the managing and hook protocol trees with their AJV schemas, the bot error family, and how a generated target mounts the operator, member and hook trees. Auto-invoked when importing from @owlmeans/bot, declaring bot routes, matching a message against phrases (an application's own keyword groups), or deciding what a platform can do.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,15 +8,17 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/bot
|
|
9
9
|
|
|
10
10
|
**Layer:** Cross-cutting domain (contracts only)
|
|
11
|
-
**Install:** `"@owlmeans/bot": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/bot": "^0.1.18-rc.3"` in `dependencies`
|
|
12
12
|
**Runtime-free:** no network, no storage, no logging — enums, descriptors, interfaces, AJV schemas
|
|
13
|
-
(plain objects),
|
|
13
|
+
(plain objects), three pure helpers, protocol factories and registered errors. Safe in a browser.
|
|
14
14
|
|
|
15
15
|
A bot connection is ONE bot account on one platform, owned by a **scope** (the organization — or the
|
|
16
|
-
application itself — that runs it).
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
application itself — that runs it). What the bot does with a message is the APPLICATION's code: a
|
|
17
|
+
handler reads the application's own records (its keyword groups, its requests) and calls the
|
|
18
|
+
actions. No package here stores a keyword group or decides on a message. The server half
|
|
19
|
+
(`@owlmeans/server-bot`) stores connections, verifies, receives and acts; `@owlmeans/bot-postgres`
|
|
20
|
+
persists; `@owlmeans/web-bot` draws the connection and activity panels; `@owlmeans/bot-agent` gives
|
|
21
|
+
an agent the actions as tools. Every one of them speaks the vocabulary declared here.
|
|
20
22
|
|
|
21
23
|
## Key Exports
|
|
22
24
|
|
|
@@ -25,21 +27,19 @@ gives an agent the actions as tools. Every one of them speaks the vocabulary dec
|
|
|
25
27
|
| `BotPlatform` | `telegram` · `whatsapp` · `discord` · `slack` |
|
|
26
28
|
| `BotReceiveMode` / `BotTransport` / `BotConnectionStatus` | `webhook`·`poll`·`gateway` / `live`·`mock` / `pending`·`connected`·`failed`·`disabled` |
|
|
27
29
|
| `BotActionKind` | platform calls: `reply` `send` `delete` `mute` `ban` `react`, plus `note` (activity only) |
|
|
28
|
-
| `
|
|
29
|
-
| `BotMatchMode` / `BotUpdateKind` / `BotChatKind` | `word`·`contains` / `message`·`edited`·`command`·`member` / `private`·`group`·`channel` |
|
|
30
|
+
| `BotTextMatch` / `BotUpdateKind` / `BotChatKind` | `word`·`contains` / `message`·`edited`·`command`·`member` / `private`·`group`·`channel` |
|
|
30
31
|
| `BOT_PLATFORMS` | `Record<BotPlatform, BotPlatformDescriptor>` — credentials, receive modes, actions, setup, docs |
|
|
31
32
|
| `BotConnection` / `BotConnectionInput` | the client view (never a credential) / the write (credentials write-only) |
|
|
32
|
-
| `BotRule` / `BotRuleInput` / `BotMatch` | a keyword group / its write / a matched group with its matched keywords |
|
|
33
33
|
| `BotUpdate`, `BotMessage`, `BotMessageRef`, `BotChatRef`, `BotSenderRef`, `BotCommand` | the normalized inbound update a handler receives |
|
|
34
|
-
| `BotActivity`, `BotSimulateInput`, `BotSimulateResult` | one recorded action (a failure carries `error`, a sentence, and `code`, its `bot:<marker>:` marker
|
|
35
|
-
| `
|
|
34
|
+
| `BotActivity`, `BotSimulateInput`, `BotSimulateResult` | one recorded action (a failure carries `error`, a sentence, and `code`, its `bot:<marker>:` marker; `ref` is the handler's opaque reference); the API-only simulate input and answer `{ update, duplicate? }` |
|
|
35
|
+
| `botTextHelper` | `fold(text)`, `tokensOf(text)`, `matched(text, phrases, mode?)`, `phrasesOf(input)` |
|
|
36
36
|
| `botCommandHelper` | `parse(text, botUsername?) → BotCommand \| null` |
|
|
37
37
|
| `botPlatformHelper` | `actionsOf(platform, credentialsSet?)`, `supports(platform, kind, credentialsSet?)` |
|
|
38
|
-
| `makeBotProtocols(opts)` → `BotProtocols` | the managing tree (connections,
|
|
38
|
+
| `makeBotProtocols(opts)` → `BotProtocols` | the managing tree (connections, activity) |
|
|
39
39
|
| `makeBotHookProtocols(opts)` → `BotHookProtocols` | the platforms' inbound tree (`receive`, `challenge`) |
|
|
40
|
-
| `Bot*Schema` | `BotConnectionInputSchema`, `
|
|
40
|
+
| `Bot*Schema` | `BotConnectionInputSchema`, `BotSimulateInputSchema`, `BotIdParamsSchema`, `BotActivityQuerySchema`, `BotHookParamsSchema`, `BotChallengeQuerySchema` |
|
|
41
41
|
| `BotError` family | `BotConnectionNotFound` 404, `BotCredentialsRejected` 422, `BotSignatureRejected` 401, `BotTransportMismatch` 409, `BotUnsupportedAction` 422 |
|
|
42
|
-
| `BOT_*` limits | `
|
|
42
|
+
| `BOT_*` limits | `BOT_TEXT_MAX` 4096, `BOT_LABEL_MAX` 120, `BOT_ACTIVITY_LIMIT_MAX` 200 / `_DEFAULT` 50, `BOT_ID_PATTERN` … |
|
|
43
43
|
| `BOT_MANAGE_PERMISSION` | `'bot--manage'` — the permission the member mount's gate requires (organization owners hold it by default where users work in organizations; otherwise granted explicitly) |
|
|
44
44
|
|
|
45
45
|
## Platforms
|
|
@@ -58,25 +58,27 @@ gives an agent the actions as tools. Every one of them speaks the vocabulary dec
|
|
|
58
58
|
- A `generated` credential (WhatsApp `verifyToken`) is created by the server and shown in the
|
|
59
59
|
connection's `setup` steps; nobody types it.
|
|
60
60
|
|
|
61
|
-
## Matching
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
tests call it, so a
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- `
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
61
|
+
## Matching text
|
|
62
|
+
|
|
63
|
+
`botTextHelper` is the ONE way message text is compared with phrases — a generated handler matching
|
|
64
|
+
the application's own keyword groups, the runtime smoke and the tests call it, so a phrase means the
|
|
65
|
+
same thing everywhere. The packages hold no keyword group: the application's records carry the
|
|
66
|
+
phrases, its handler loads them and asks `matched`.
|
|
67
|
+
|
|
68
|
+
- Both sides fold (`fold`): NFKC, then a case fold, then NFKC (`ß` ≡ `ss`, `Ё` ≡ `ё`, full-width ≡
|
|
69
|
+
ASCII, ligatures ≡ letters). Accents are kept: `cafe` does not match `café`.
|
|
70
|
+
- `matched(text, phrases, BotTextMatch.Word)` (the default): tokens are runs of letters, combining
|
|
71
|
+
marks, digits and `_`; punctuation splits. A multi-word phrase must appear as CONSECUTIVE tokens
|
|
72
|
+
(`free money` matches `FREE, money!`, not `money for free`). A phrase with no letters or digits
|
|
73
|
+
never matches a word.
|
|
74
|
+
- `BotTextMatch.Contains`: a substring of the folded text, whitespace runs collapsed — also the mode
|
|
75
|
+
for scripts written without spaces (Chinese, Japanese, Thai), where a word is the whole run.
|
|
76
|
+
- The answer lists the phrases found, in the order given, each once (a folded repeat is skipped, the
|
|
77
|
+
first spelling answers). Blank phrases and an empty text match nothing.
|
|
78
|
+
- `phrasesOf(input)` turns what a person typed (a string, or a list whose items may hold several)
|
|
79
|
+
into phrases: split on commas and line breaks, trimmed, inner whitespace collapsed, empties and
|
|
80
|
+
folded duplicates dropped (first spelling kept). A form or a model normalizes keywords with it
|
|
81
|
+
before saving them.
|
|
80
82
|
|
|
81
83
|
`botCommandHelper.parse('/report@MyBot some args', 'MyBot')` → `{ name: 'report', args: 'some args' }`.
|
|
82
84
|
The name is lower-cased and must end at whitespace or the end (`/usr/bin` is no command); a command
|
|
@@ -91,24 +93,21 @@ makeBotProtocols({ base: { alias, path, parent?, service? }, guards?, gates? }):
|
|
|
91
93
|
// connection.save POST /connections BotConnectionInput → BotConnection
|
|
92
94
|
// connection.verify POST /connections/:id/verify → BotConnection
|
|
93
95
|
// connection.remove DELETE /connections/:id → { id }
|
|
94
|
-
// connection.simulate POST /connections/:id/simulate BotSimulateInput → BotSimulateResult (mock only)
|
|
95
|
-
// rule.list GET /rules?connection= → BotRule[]
|
|
96
|
-
// rule.save POST /rules BotRuleInput → BotRule
|
|
97
|
-
// rule.remove DELETE /rules/:id → { id }
|
|
96
|
+
// connection.simulate POST /connections/:id/simulate BotSimulateInput → BotSimulateResult (mock only, API only)
|
|
98
97
|
// activity.list GET /activity?connection=&limit= → BotActivity[] (newest first, limit ≤ 200)
|
|
99
98
|
makeBotHookProtocols({ base: { alias, path, parent?, service? } }): BotHookProtocols
|
|
100
99
|
// receive POST /:platform/:connection (native payload, no body schema)
|
|
101
100
|
// challenge GET /:platform/:connection (WhatsApp hub.* handshake → the challenge string)
|
|
102
101
|
```
|
|
103
102
|
|
|
104
|
-
- Aliases derive from the base: `<alias>:connection:list`, `<alias>:
|
|
103
|
+
- Aliases derive from the base: `<alias>:connection:list`, `<alias>:activity:list`, `<alias>:receive` …
|
|
105
104
|
Two mounts are two base aliases.
|
|
106
105
|
- `gates` is the gate the base carries (`{ alias, params? }` — a protocol has exactly one gate).
|
|
107
106
|
- **The hook tree carries no guard and no gate, on purpose: the platform signs.** Telegram's secret
|
|
108
107
|
token, WhatsApp's app-secret HMAC and Slack's signing secret are verified by the server against the
|
|
109
108
|
connection's credentials over the RAW body — never put an auth guard in front of it, never add a
|
|
110
109
|
body schema.
|
|
111
|
-
- List queries are required on the client: `
|
|
110
|
+
- List queries are required on the client: `activity.list.call({ query: {} })`.
|
|
112
111
|
|
|
113
112
|
## Rules for consumers
|
|
114
113
|
|
|
@@ -116,12 +115,16 @@ makeBotHookProtocols({ base: { alias, path, parent?, service? } }): BotHookProto
|
|
|
116
115
|
`{ ok, error?, code? }` and records a `BotActivity` with both; a handler checks `ok`, never wraps in
|
|
117
116
|
try/catch to "handle" a platform refusal, and asks `supports(kind)` before an action its platform
|
|
118
117
|
may lack. `error` is one sentence for a person or a model; `code` is the marker code compares.
|
|
119
|
-
- A handler
|
|
120
|
-
and
|
|
118
|
+
- A handler decides on the update itself: it reads the application's own records (keyword groups
|
|
119
|
+
for `update.scope`, and its connection where the records are bound to one), compares the text
|
|
120
|
+
with `botTextHelper.matched`, and acts through `BotActions` with `{ ref }` — the id of the record
|
|
121
|
+
it followed, recorded on the activity. It never calls a platform API by hand.
|
|
121
122
|
- `BotConnection` never carries a credential; `credentialsSet` says which keys hold a value. In a
|
|
122
123
|
`BotConnectionInput`, an omitted credential key keeps its stored value; `''` is spellable (clear).
|
|
123
124
|
- `simulate` exists only for `transport: 'mock'`; on a live connection it is `BotTransportMismatch`.
|
|
124
|
-
|
|
125
|
+
It is reachable through the API alone — the runtime smoke and end-to-end tests call it; no UI
|
|
126
|
+
offers a mock transport or a simulator. The server hands the platform's native payload straight to
|
|
127
|
+
normalization and the inbox — no hook.
|
|
125
128
|
`BotSimulateResult.duplicate: true` means the payload was already in the inbox: `update` is the
|
|
126
129
|
existing row and nothing new is dispatched — a caller waiting for a reaction stops there.
|
|
127
130
|
- Chat members are not application users: nothing of theirs is a guest endpoint; their messages
|
|
@@ -169,9 +172,28 @@ export const botProtocols = Object.freeze({
|
|
|
169
172
|
tenancy, the acting organization otherwise — and the hook tree with `serveBotHookEntrypoints`.
|
|
170
173
|
- Hook URL: `https://<host>/api/bot/hook/<platform>/<connection>` — the host of the request that
|
|
171
174
|
saved or verified the connection, so preview, production and custom domains all work.
|
|
172
|
-
- The web screens host `BotConnectionsPanel`
|
|
173
|
-
`surface = appProtocols.api.bot.operator` (or `.member`)
|
|
174
|
-
|
|
175
|
+
- The web screens host `BotConnectionsPanel` (the connection dialog) and `BotActivityPanel` with
|
|
176
|
+
`surface = appProtocols.api.bot.operator` (or `.member`). Keyword groups are the target's OWN
|
|
177
|
+
generated records — type, API, collection and form screens like any product record.
|
|
178
|
+
- Handlers live in `sources/backend/src/bot/handlers/`, listed by the generated barrel
|
|
179
|
+
`handlers/index.ts`, and run in the worker (`bot.runtime(handlers)`). A keyword handler loads the
|
|
180
|
+
groups for `update.scope` through the backend model, matches with `botTextHelper.matched` and
|
|
181
|
+
acts with `{ ref: group.id }`:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
// sources/backend/src/bot/handlers/moderate.ts — the keyword group is the app's own record
|
|
185
|
+
import { botTextHelper } from '@owlmeans/bot'
|
|
186
|
+
import { botHandler } from '@owlmeans/server-bot'
|
|
187
|
+
|
|
188
|
+
export const moderate = botHandler('moderate', async (update, bot, ctx) => {
|
|
189
|
+
const text = update.message?.text ?? ''
|
|
190
|
+
for (const group of await makeKeywordGroupModel(ctx).enabledOf(update.scope)) {
|
|
191
|
+
if (botTextHelper.matched(text, group.keywords).length > 0) {
|
|
192
|
+
await bot.delete(update, { ref: group.id })
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
```
|
|
175
197
|
|
|
176
198
|
## Depends On
|
|
177
199
|
|
package/build/consts.d.ts
CHANGED
|
@@ -50,23 +50,8 @@ export declare enum BotActionKind {
|
|
|
50
50
|
React = "react",
|
|
51
51
|
Note = "note"
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
*
|
|
56
|
-
* A product vocabulary, not a platform one: `warn` is a reply, `record` is a request record of the
|
|
57
|
-
* product, `agent` hands the message to the product's own agent.
|
|
58
|
-
*/
|
|
59
|
-
export declare enum BotRuleAction {
|
|
60
|
-
Delete = "delete",
|
|
61
|
-
Warn = "warn",
|
|
62
|
-
Mute = "mute",
|
|
63
|
-
Ban = "ban",
|
|
64
|
-
Reply = "reply",
|
|
65
|
-
Record = "record",
|
|
66
|
-
Agent = "agent"
|
|
67
|
-
}
|
|
68
|
-
/** How a rule's keywords are compared with a message. */
|
|
69
|
-
export declare enum BotMatchMode {
|
|
53
|
+
/** How `botTextHelper.matched` compares a phrase with a message. */
|
|
54
|
+
export declare enum BotTextMatch {
|
|
70
55
|
/** Whole words and whole phrases (consecutive words), Unicode-aware and case-insensitive. */
|
|
71
56
|
Word = "word",
|
|
72
57
|
/** A case-insensitive substring — also the mode for scripts written without spaces. */
|
|
@@ -83,22 +68,12 @@ export declare enum BotChatKind {
|
|
|
83
68
|
Group = "group",
|
|
84
69
|
Channel = "channel"
|
|
85
70
|
}
|
|
86
|
-
/** The longest identifier (connection,
|
|
71
|
+
/** The longest identifier (connection, activity, update) the wire accepts. */
|
|
87
72
|
export declare const BOT_ID_MAX = 128;
|
|
88
73
|
/** What an identifier on the wire may look like — it is also a path segment of the hook URL. */
|
|
89
74
|
export declare const BOT_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9_.:-]*$";
|
|
90
75
|
/** The longest connection label. */
|
|
91
76
|
export declare const BOT_LABEL_MAX = 120;
|
|
92
|
-
/** The longest rule (keyword group) name. */
|
|
93
|
-
export declare const BOT_RULE_NAME_MAX = 120;
|
|
94
|
-
/** How many keywords one rule keeps. */
|
|
95
|
-
export declare const BOT_KEYWORDS_MAX = 200;
|
|
96
|
-
/** The longest keyword or phrase, in code points. */
|
|
97
|
-
export declare const BOT_KEYWORD_MAX = 100;
|
|
98
|
-
/** The longest fixed reply text of a rule. */
|
|
99
|
-
export declare const BOT_REPLY_MAX = 4096;
|
|
100
|
-
/** The longest instruction a rule hands to the product's agent. */
|
|
101
|
-
export declare const BOT_INSTRUCTION_MAX = 4000;
|
|
102
77
|
/** The longest message text the simulator accepts. */
|
|
103
78
|
export declare const BOT_TEXT_MAX = 4096;
|
|
104
79
|
/** The longest single credential value. */
|
|
@@ -115,9 +90,9 @@ export declare const BOT_ACTIVITY_LIMIT_MAX = 200;
|
|
|
115
90
|
export declare const BOT_ACTIVITY_LIMIT_DEFAULT = 50;
|
|
116
91
|
/**
|
|
117
92
|
* The permission the MEMBER mount's gate requires (`gates: { alias: OIDC_GATE, params:
|
|
118
|
-
* [BOT_MANAGE_PERMISSION] }`) — who may connect an organization's bots
|
|
119
|
-
*
|
|
120
|
-
*
|
|
93
|
+
* [BOT_MANAGE_PERMISSION] }`) — who may connect an organization's bots and read its bot activity.
|
|
94
|
+
* In a product whose users work in organizations, an organization's owners hold it by default;
|
|
95
|
+
* otherwise it is only ever granted explicitly.
|
|
121
96
|
*/
|
|
122
97
|
export declare const BOT_MANAGE_PERMISSION = "bot--manage";
|
|
123
98
|
/**
|
package/build/consts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,4DAA4D;AAC5D,oBAAY,WAAW;IACrB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,KAAK,UAAU;CAChB;AAED,wDAAwD;AACxD,oBAAY,cAAc;IACxB,oEAAoE;IACpE,OAAO,YAAY;IACnB,wEAAwE;IACxE,IAAI,SAAS;IACb,gFAAgF;IAChF,OAAO,YAAY;CACpB;AAED;;;;;GAKG;AACH,oBAAY,YAAY;IACtB,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,oBAAY,mBAAmB;IAC7B,+BAA+B;IAC/B,OAAO,YAAY;IACnB,qFAAqF;IACrF,SAAS,cAAc;IACvB,sEAAsE;IACtE,MAAM,WAAW;IACjB,8DAA8D;IAC9D,QAAQ,aAAa;CACtB;AAED;;;;;GAKG;AACH,oBAAY,aAAa;IACvB,KAAK,UAAU;IACf,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,IAAI,SAAS;CACd;AAED
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEvD,4DAA4D;AAC5D,oBAAY,WAAW;IACrB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,KAAK,UAAU;CAChB;AAED,wDAAwD;AACxD,oBAAY,cAAc;IACxB,oEAAoE;IACpE,OAAO,YAAY;IACnB,wEAAwE;IACxE,IAAI,SAAS;IACb,gFAAgF;IAChF,OAAO,YAAY;CACpB;AAED;;;;;GAKG;AACH,oBAAY,YAAY;IACtB,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,oBAAY,mBAAmB;IAC7B,+BAA+B;IAC/B,OAAO,YAAY;IACnB,qFAAqF;IACrF,SAAS,cAAc;IACvB,sEAAsE;IACtE,MAAM,WAAW;IACjB,8DAA8D;IAC9D,QAAQ,aAAa;CACtB;AAED;;;;;GAKG;AACH,oBAAY,aAAa;IACvB,KAAK,UAAU;IACf,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,IAAI,SAAS;CACd;AAED,oEAAoE;AACpE,oBAAY,YAAY;IACtB,6FAA6F;IAC7F,IAAI,SAAS;IACb,uFAAuF;IACvF,QAAQ,aAAa;CACtB;AAED,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB;AAED,oBAAY,WAAW;IACrB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,OAAO,YAAY;CACpB;AAED,8EAA8E;AAC9E,eAAO,MAAM,UAAU,MAAM,CAAA;AAE7B,gGAAgG;AAChG,eAAO,MAAM,cAAc,kCAAkC,CAAA;AAE7D,oCAAoC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAA;AAEhC,sDAAsD;AACtD,eAAO,MAAM,YAAY,OAAO,CAAA;AAEhC,2CAA2C;AAC3C,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC,2CAA2C;AAC3C,eAAO,MAAM,0BAA0B,gCAAgC,CAAA;AAEvE,yFAAyF;AACzF,eAAO,MAAM,YAAY,MAAM,CAAA;AAE/B,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB,MAAM,CAAA;AAEzC,+DAA+D;AAC/D,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,gBAAgB,CAAA;AAElD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,WAAW,EAAE,qBAAqB,CAyDrB,CAAA"}
|
package/build/consts.js
CHANGED
|
@@ -54,30 +54,14 @@ export var BotActionKind;
|
|
|
54
54
|
BotActionKind["React"] = "react";
|
|
55
55
|
BotActionKind["Note"] = "note";
|
|
56
56
|
})(BotActionKind || (BotActionKind = {}));
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
* A product vocabulary, not a platform one: `warn` is a reply, `record` is a request record of the
|
|
61
|
-
* product, `agent` hands the message to the product's own agent.
|
|
62
|
-
*/
|
|
63
|
-
export var BotRuleAction;
|
|
64
|
-
(function (BotRuleAction) {
|
|
65
|
-
BotRuleAction["Delete"] = "delete";
|
|
66
|
-
BotRuleAction["Warn"] = "warn";
|
|
67
|
-
BotRuleAction["Mute"] = "mute";
|
|
68
|
-
BotRuleAction["Ban"] = "ban";
|
|
69
|
-
BotRuleAction["Reply"] = "reply";
|
|
70
|
-
BotRuleAction["Record"] = "record";
|
|
71
|
-
BotRuleAction["Agent"] = "agent";
|
|
72
|
-
})(BotRuleAction || (BotRuleAction = {}));
|
|
73
|
-
/** How a rule's keywords are compared with a message. */
|
|
74
|
-
export var BotMatchMode;
|
|
75
|
-
(function (BotMatchMode) {
|
|
57
|
+
/** How `botTextHelper.matched` compares a phrase with a message. */
|
|
58
|
+
export var BotTextMatch;
|
|
59
|
+
(function (BotTextMatch) {
|
|
76
60
|
/** Whole words and whole phrases (consecutive words), Unicode-aware and case-insensitive. */
|
|
77
|
-
|
|
61
|
+
BotTextMatch["Word"] = "word";
|
|
78
62
|
/** A case-insensitive substring — also the mode for scripts written without spaces. */
|
|
79
|
-
|
|
80
|
-
})(
|
|
63
|
+
BotTextMatch["Contains"] = "contains";
|
|
64
|
+
})(BotTextMatch || (BotTextMatch = {}));
|
|
81
65
|
export var BotUpdateKind;
|
|
82
66
|
(function (BotUpdateKind) {
|
|
83
67
|
BotUpdateKind["Message"] = "message";
|
|
@@ -91,22 +75,12 @@ export var BotChatKind;
|
|
|
91
75
|
BotChatKind["Group"] = "group";
|
|
92
76
|
BotChatKind["Channel"] = "channel";
|
|
93
77
|
})(BotChatKind || (BotChatKind = {}));
|
|
94
|
-
/** The longest identifier (connection,
|
|
78
|
+
/** The longest identifier (connection, activity, update) the wire accepts. */
|
|
95
79
|
export const BOT_ID_MAX = 128;
|
|
96
80
|
/** What an identifier on the wire may look like — it is also a path segment of the hook URL. */
|
|
97
81
|
export const BOT_ID_PATTERN = '^[A-Za-z0-9][A-Za-z0-9_.:-]*$';
|
|
98
82
|
/** The longest connection label. */
|
|
99
83
|
export const BOT_LABEL_MAX = 120;
|
|
100
|
-
/** The longest rule (keyword group) name. */
|
|
101
|
-
export const BOT_RULE_NAME_MAX = 120;
|
|
102
|
-
/** How many keywords one rule keeps. */
|
|
103
|
-
export const BOT_KEYWORDS_MAX = 200;
|
|
104
|
-
/** The longest keyword or phrase, in code points. */
|
|
105
|
-
export const BOT_KEYWORD_MAX = 100;
|
|
106
|
-
/** The longest fixed reply text of a rule. */
|
|
107
|
-
export const BOT_REPLY_MAX = 4096;
|
|
108
|
-
/** The longest instruction a rule hands to the product's agent. */
|
|
109
|
-
export const BOT_INSTRUCTION_MAX = 4000;
|
|
110
84
|
/** The longest message text the simulator accepts. */
|
|
111
85
|
export const BOT_TEXT_MAX = 4096;
|
|
112
86
|
/** The longest single credential value. */
|
|
@@ -123,9 +97,9 @@ export const BOT_ACTIVITY_LIMIT_MAX = 200;
|
|
|
123
97
|
export const BOT_ACTIVITY_LIMIT_DEFAULT = 50;
|
|
124
98
|
/**
|
|
125
99
|
* The permission the MEMBER mount's gate requires (`gates: { alias: OIDC_GATE, params:
|
|
126
|
-
* [BOT_MANAGE_PERMISSION] }`) — who may connect an organization's bots
|
|
127
|
-
*
|
|
128
|
-
*
|
|
100
|
+
* [BOT_MANAGE_PERMISSION] }`) — who may connect an organization's bots and read its bot activity.
|
|
101
|
+
* In a product whose users work in organizations, an organization's owners hold it by default;
|
|
102
|
+
* otherwise it is only ever granted explicitly.
|
|
129
103
|
*/
|
|
130
104
|
export const BOT_MANAGE_PERMISSION = 'bot--manage';
|
|
131
105
|
/**
|
package/build/consts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAEA,4DAA4D;AAC5D,MAAM,CAAN,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,oCAAqB,CAAA;IACrB,oCAAqB,CAAA;IACrB,kCAAmB,CAAA;IACnB,8BAAe,CAAA;AACjB,CAAC,EALW,WAAW,KAAX,WAAW,QAKtB;AAED,wDAAwD;AACxD,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACxB,oEAAoE;IACpE,qCAAmB,CAAA;IACnB,wEAAwE;IACxE,+BAAa,CAAA;IACb,gFAAgF;IAChF,qCAAmB,CAAA;AACrB,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB;AAED;;;;;GAKG;AACH,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,6BAAa,CAAA;IACb,6BAAa,CAAA;AACf,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AAED,MAAM,CAAN,IAAY,mBASX;AATD,WAAY,mBAAmB;IAC7B,+BAA+B;IAC/B,0CAAmB,CAAA;IACnB,qFAAqF;IACrF,8CAAuB,CAAA;IACvB,sEAAsE;IACtE,wCAAiB,CAAA;IACjB,8DAA8D;IAC9D,4CAAqB,CAAA;AACvB,CAAC,EATW,mBAAmB,KAAnB,mBAAmB,QAS9B;AAED;;;;;GAKG;AACH,MAAM,CAAN,IAAY,aAQX;AARD,WAAY,aAAa;IACvB,gCAAe,CAAA;IACf,8BAAa,CAAA;IACb,kCAAiB,CAAA;IACjB,8BAAa,CAAA;IACb,4BAAW,CAAA;IACX,gCAAe,CAAA;IACf,8BAAa,CAAA;AACf,CAAC,EARW,aAAa,KAAb,aAAa,QAQxB;AAED
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"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"}
|
package/build/consts.local.d.ts
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
* (Devanagari vowel signs, a decomposed accent left after folding), so a word never splits on one.
|
|
4
4
|
*/
|
|
5
5
|
export declare const BOT_TOKEN_PATTERN: RegExp;
|
|
6
|
-
/** Any whitespace run — collapsed to one space before a `contains` comparison and in a
|
|
6
|
+
/** Any whitespace run — collapsed to one space before a `contains` comparison and in a typed phrase. */
|
|
7
7
|
export declare const BOT_SPACE_PATTERN: RegExp;
|
|
8
|
+
/** What separates the phrases of a typed list: commas (ASCII, full-width, ideographic) and line breaks. */
|
|
9
|
+
export declare const BOT_PHRASE_SEPARATOR_PATTERN: RegExp;
|
|
8
10
|
/**
|
|
9
11
|
* A `/command`, optionally addressed `@ToBot`, ending at whitespace or at the end of the text, then
|
|
10
12
|
* its arguments.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAA0B,CAAA;AAExD,
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAA0B,CAAA;AAExD,wGAAwG;AACxG,eAAO,MAAM,iBAAiB,QAAU,CAAA;AAExC,2GAA2G;AAC3G,eAAO,MAAM,4BAA4B,QAAgB,CAAA;AAEzD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAA6E,CAAA"}
|
package/build/consts.local.js
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
* (Devanagari vowel signs, a decomposed accent left after folding), so a word never splits on one.
|
|
4
4
|
*/
|
|
5
5
|
export const BOT_TOKEN_PATTERN = /[\p{L}\p{M}\p{N}_]+/gu;
|
|
6
|
-
/** Any whitespace run — collapsed to one space before a `contains` comparison and in a
|
|
6
|
+
/** Any whitespace run — collapsed to one space before a `contains` comparison and in a typed phrase. */
|
|
7
7
|
export const BOT_SPACE_PATTERN = /\s+/gu;
|
|
8
|
+
/** What separates the phrases of a typed list: commas (ASCII, full-width, ideographic) and line breaks. */
|
|
9
|
+
export const BOT_PHRASE_SEPARATOR_PATTERN = /[,,、\r\n]+/u;
|
|
8
10
|
/**
|
|
9
11
|
* A `/command`, optionally addressed `@ToBot`, ending at whitespace or at the end of the text, then
|
|
10
12
|
* its arguments.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAA;AAExD,
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAA;AAExD,wGAAwG;AACxG,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAA;AAExC,2GAA2G;AAC3G,MAAM,CAAC,MAAM,4BAA4B,GAAG,aAAa,CAAA;AAEzD;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,0EAA0E,CAAA"}
|
package/build/helpers/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export type * from './
|
|
1
|
+
export type * from './text/types.js';
|
|
2
2
|
export type * from './command/types.js';
|
|
3
3
|
export type * from './platform/types.js';
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './text.js';
|
|
5
5
|
export * from './command.js';
|
|
6
6
|
export * from './platform.js';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/build/helpers/index.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { BotTextMatch } from '../../consts.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unicode-aware comparison of a message with phrases — the pure primitive a bot handler matches
|
|
4
|
+
* message text with (the application's own keyword groups, a command's argument, a reply's text).
|
|
5
|
+
*
|
|
6
|
+
* Both sides fold the same way: NFKC, then a case fold, then NFKC again (`ß` ≡ `ss`, `Ё` ≡ `ё`,
|
|
7
|
+
* full-width ≡ ASCII, ligatures ≡ their letters); accents are kept (`cafe` is not `café`).
|
|
8
|
+
*/
|
|
9
|
+
export interface BotTextHelper {
|
|
10
|
+
/** The folded form of a text: NFKC, upper- then lower-cased, NFKC again. */
|
|
11
|
+
fold: (text: string) => string;
|
|
12
|
+
/**
|
|
13
|
+
* The folded tokens of a text: runs of letters, combining marks, digits and `_`; everything else
|
|
14
|
+
* (punctuation, spaces, symbols) splits. `[]` for a text with none.
|
|
15
|
+
*/
|
|
16
|
+
tokensOf: (text: string) => string[];
|
|
17
|
+
/**
|
|
18
|
+
* The phrases found in `text`, in the order they were given, each once — a phrase whose folded
|
|
19
|
+
* form repeats an earlier one is skipped, so the first spelling answers.
|
|
20
|
+
*
|
|
21
|
+
* `word` (the default): the phrase's tokens appear in the text as CONSECUTIVE tokens (`free money`
|
|
22
|
+
* matches `FREE, money!`, not `money for free`), and a phrase with no letters or digits never
|
|
23
|
+
* matches. `contains`: the folded phrase is a substring of the folded text, whitespace runs of both
|
|
24
|
+
* collapsed to one space — also the mode for scripts written without spaces (Chinese, Japanese,
|
|
25
|
+
* Thai). An empty or blank phrase never matches; an empty text matches nothing.
|
|
26
|
+
*/
|
|
27
|
+
matched: (text: string, phrases: readonly string[], mode?: BotTextMatch) => string[];
|
|
28
|
+
/**
|
|
29
|
+
* A phrase list as a person typed it: every item split on commas and line breaks, each phrase
|
|
30
|
+
* trimmed with inner whitespace runs collapsed to one space, empties dropped, and a phrase whose
|
|
31
|
+
* folded form repeats an earlier one dropped (the first spelling kept).
|
|
32
|
+
*/
|
|
33
|
+
phrasesOf: (input: string | readonly string[]) => string[];
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/text/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEnD;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IAC9B;;;OAGG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAA;IACpC;;;;;;;;;OASG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,YAAY,KAAK,MAAM,EAAE,CAAA;IACpF;;;;OAIG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,KAAK,MAAM,EAAE,CAAA;CAC3D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/helpers/
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/helpers/text/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/helpers/text.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,eAAO,MAAM,mBAAmB,QAAO,aAoFtC,CAAA;AAED,eAAO,MAAM,aAAa,eAAwB,CAAA"}
|