@owlmeans/bot 0.1.18-rc.2 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +23 -21
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/bot/SKILL.md +68 -46
  4. package/build/consts.d.ts +6 -31
  5. package/build/consts.d.ts.map +1 -1
  6. package/build/consts.js +10 -36
  7. package/build/consts.js.map +1 -1
  8. package/build/consts.local.d.ts +3 -1
  9. package/build/consts.local.d.ts.map +1 -1
  10. package/build/consts.local.js +3 -1
  11. package/build/consts.local.js.map +1 -1
  12. package/build/helpers/index.d.ts +2 -2
  13. package/build/helpers/index.js +1 -1
  14. package/build/helpers/text/types.d.ts +35 -0
  15. package/build/helpers/text/types.d.ts.map +1 -0
  16. package/build/helpers/{rule → text}/types.js.map +1 -1
  17. package/build/helpers/text.d.ts +4 -0
  18. package/build/helpers/text.d.ts.map +1 -0
  19. package/build/helpers/text.js +77 -0
  20. package/build/helpers/text.js.map +1 -0
  21. package/build/protocols/types.d.ts +2 -17
  22. package/build/protocols/types.d.ts.map +1 -1
  23. package/build/protocols.d.ts +1 -1
  24. package/build/protocols.d.ts.map +1 -1
  25. package/build/protocols.js +2 -7
  26. package/build/protocols.js.map +1 -1
  27. package/build/schemas.d.ts +2 -4
  28. package/build/schemas.d.ts.map +1 -1
  29. package/build/schemas.js +3 -31
  30. package/build/schemas.js.map +1 -1
  31. package/build/types.d.ts +7 -41
  32. package/build/types.d.ts.map +1 -1
  33. package/build/utils/aliases/types.d.ts +0 -5
  34. package/build/utils/aliases/types.d.ts.map +1 -1
  35. package/build/utils/aliases.d.ts.map +1 -1
  36. package/build/utils/aliases.js +0 -5
  37. package/build/utils/aliases.js.map +1 -1
  38. package/package.json +7 -7
  39. package/src/consts.local.ts +4 -1
  40. package/src/consts.ts +6 -37
  41. package/src/helpers/index.ts +2 -2
  42. package/src/helpers/text/types.ts +35 -0
  43. package/src/helpers/text.ts +91 -0
  44. package/src/protocols/types.ts +2 -12
  45. package/src/protocols.ts +4 -21
  46. package/src/schemas.ts +5 -39
  47. package/src/types.ts +7 -45
  48. package/src/utils/aliases/types.ts +0 -1
  49. package/src/utils/aliases.ts +0 -5
  50. package/tests/protocols.spec.ts +3 -7
  51. package/tests/schemas.spec.ts +2 -30
  52. package/tests/text.spec.ts +101 -0
  53. package/tests/update.spec.ts +4 -10
  54. package/build/helpers/rule/types.d.ts +0 -26
  55. package/build/helpers/rule/types.d.ts.map +0 -1
  56. package/build/helpers/rule.d.ts +0 -4
  57. package/build/helpers/rule.d.ts.map +0 -1
  58. package/build/helpers/rule.js +0 -71
  59. package/build/helpers/rule.js.map +0 -1
  60. package/src/helpers/rule/types.ts +0 -26
  61. package/src/helpers/rule.ts +0 -89
  62. package/tests/rule.spec.ts +0 -129
  63. /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, keyword rules (groups) and the one
5
- Unicode-aware matcher, the `/command` parser, normalized updates and activity, the managing and hook
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.2
13
+ bun add @owlmeans/bot@^0.1.18
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
- - **Rule** — a keyword group: keywords, a match mode (`word` / `contains`) and what to do
21
- (`BotRuleAction`). `connection: null` applies to every connection of the scope.
22
- - **Update** — an inbound message normalized across platforms (`BotUpdate`), with the rules it
23
- matched already in `matches`.
24
- - **Activity** — one thing the bot did or tried (`BotActivity`), recorded with `ok` / `error`.
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, botRuleHelper, makeBotHookProtocols, makeBotProtocols } from '@owlmeans/bot'
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 matches = botRuleHelper.match('Free money at the CASINO!', rules) // enabled rules, by order
39
- const command = botCommandHelper.parse('/report@MyBot spam', 'MyBot') // { name: 'report', args: 'spam' }
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
- `BotRuleAction`, `BotMatchMode`, `BotUpdateKind`, `BotChatKind`
46
- - Constants: `BOT_PLATFORMS`, `BOT_*` limits (`BOT_KEYWORDS_MAX`, `BOT_KEYWORD_MAX`,
47
- `BOT_ACTIVITY_LIMIT_MAX`, `BOT_ID_PATTERN`, …)
48
- - Helpers: `botRuleHelper` (`match`, `normalizeKeywords`, `appliesTo`), `botCommandHelper`
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`, `BotRuleInputSchema`, `BotSimulateInputSchema`,
53
- `BotIdParamsSchema`, `BotRuleListQuerySchema`, `BotActivityQuerySchema`, `BotHookParamsSchema`,
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
 
@@ -77,7 +79,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
77
79
  your project's skill store (`.agents/skills/`):
78
80
 
79
81
  ```sh
80
- npx @owlmeans/agent-skills@^0.1.18-rc.59
82
+ npx @owlmeans/agent-skills@^0.1.18
81
83
  ```
82
84
 
83
85
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 3,
3
3
  "package": "@owlmeans/bot",
4
- "version": "0.1.18-rc.2",
5
- "generatedAt": "2026-10-26T22:23:53.842Z",
4
+ "version": "0.1.18",
5
+ "generatedAt": "2026-10-28T00:31:34.726Z",
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, keyword rules (groups) and the Unicode-aware matcher, the /command parser, normalized updates and activity, 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 keyword groups, or deciding what a platform can do.
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.2"` in `dependencies`
11
+ **Install:** `"@owlmeans/bot": "^0.1.18"` in `dependencies`
12
12
  **Runtime-free:** no network, no storage, no logging — enums, descriptors, interfaces, AJV schemas
13
- (plain objects), two pure helpers, protocol factories and registered errors. Safe in a browser.
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). Its **rules** are keyword groups: keywords + what to do with a
17
- matching message. The server half (`@owlmeans/server-bot`) stores, verifies, receives, matches and
18
- acts; `@owlmeans/bot-postgres` persists; `@owlmeans/web-bot` draws the panels; `@owlmeans/bot-agent`
19
- gives an agent the actions as tools. Every one of them speaks the vocabulary declared here.
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
- | `BotRuleAction` | what a group tells the bot: `delete` `warn` `mute` `ban` `reply` `record` `agent` |
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); the simulator's input and answer `{ update, duplicate? }` |
35
- | `botRuleHelper` | `match(text, rules)`, `normalizeKeywords(list)`, `appliesTo(rule, connection)` |
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, rules, activity) |
38
+ | `makeBotProtocols(opts)` → `BotProtocols` | the managing tree (connections, activity) |
39
39
  | `makeBotHookProtocols(opts)` → `BotHookProtocols` | the platforms' inbound tree (`receive`, `challenge`) |
40
- | `Bot*Schema` | `BotConnectionInputSchema`, `BotRuleInputSchema`, `BotSimulateInputSchema`, `BotIdParamsSchema`, `BotRuleListQuerySchema`, `BotActivityQuerySchema`, `BotHookParamsSchema`, `BotChallengeQuerySchema` |
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 | `BOT_KEYWORDS_MAX` 200, `BOT_KEYWORD_MAX` 100, `BOT_ACTIVITY_LIMIT_MAX` 200 / `_DEFAULT` 50, `BOT_ID_PATTERN` … |
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 rules
62
-
63
- `botRuleHelper.match(text, rules)` is the ONE matcher — the server's dispatch, the panels and the
64
- tests call it, so a group means the same thing everywhere.
65
-
66
- - Both sides fold: NFKC, then a case fold (`ß` ≡ `ss`, `Ё` ≡ `ё`, full-width ≡ ASCII). Accents are
67
- kept: `cafe` does not match `café`.
68
- - `word`: tokens are runs of letters, combining marks, digits and `_`; punctuation splits. A
69
- multi-word keyword is a PHRASE — consecutive tokens (`free money` matches `FREE, money!`, not
70
- `money for free`). A keyword with no letters or digits never matches a word.
71
- - `contains`: a substring of the folded text, whitespace runs collapsed — also the mode for scripts
72
- written without spaces (Chinese, Japanese, Thai), where a word is the whole run.
73
- - Disabled rules never match; results are sorted by `order` (ties keep the given order); each
74
- `BotMatch.keywords` lists the rule's keywords, as stored, that matched.
75
- - Which rules apply to a connection is `appliesTo`: its own, or a scope-wide one (`connection`
76
- `null`/absent). The runtime filters with it before matching.
77
- - `normalizeKeywords(list)` is what a store keeps: trimmed, inner whitespace collapsed, ≤
78
- `BOT_KEYWORD_MAX` code points, empties and folded duplicates dropped (first spelling kept), ≤
79
- `BOT_KEYWORDS_MAX` items.
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>:rule:save`, `<alias>:receive` …
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: `rule.list.call({ query: {} })`.
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 reacts to `update.matches` (already filtered and ordered) — it never re-matches text
120
- and never calls a platform API by hand.
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
- The server hands the platform's native payload straight to normalization and the inbox — no hook.
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` / `BotRulesPanel` / `BotActivityPanel` with
173
- `surface = appProtocols.api.bot.operator` (or `.member`); handlers live in
174
- `sources/backend/src/bot/handlers/` and run in the worker (`bot.runtime(handlers)`).
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
- * What a keyword group (a rule) tells the bot to do with a message it matches.
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, rule, activity, update) the wire accepts. */
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, edit its keyword groups and
119
- * read its bot activity. In a product whose users work in organizations, an organization's owners hold
120
- * it by default; otherwise it is only ever granted explicitly.
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
  /**
@@ -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;;;;;GAKG;AACH,oBAAY,aAAa;IACvB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,GAAG,QAAQ;IACX,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,KAAK,UAAU;CAChB;AAED,yDAAyD;AACzD,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,oFAAoF;AACpF,eAAO,MAAM,UAAU,MAAM,CAAA;AAE7B,gGAAgG;AAChG,eAAO,MAAM,cAAc,kCAAkC,CAAA;AAE7D,oCAAoC;AACpC,eAAO,MAAM,aAAa,MAAM,CAAA;AAEhC,6CAA6C;AAC7C,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC,wCAAwC;AACxC,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC,qDAAqD;AACrD,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC,8CAA8C;AAC9C,eAAO,MAAM,aAAa,OAAO,CAAA;AAEjC,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,OAAO,CAAA;AAEvC,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"}
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
- * What a keyword group (a rule) tells the bot to do with a message it matches.
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
- BotMatchMode["Word"] = "word";
61
+ BotTextMatch["Word"] = "word";
78
62
  /** A case-insensitive substring — also the mode for scripts written without spaces. */
79
- BotMatchMode["Contains"] = "contains";
80
- })(BotMatchMode || (BotMatchMode = {}));
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, rule, activity, update) the wire accepts. */
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, edit its keyword groups and
127
- * read its bot activity. In a product whose users work in organizations, an organization's owners hold
128
- * it by default; otherwise it is only ever granted explicitly.
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
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"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"}
@@ -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 stored keyword. */
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,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,QAAU,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,QAA6E,CAAA"}
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"}
@@ -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 stored keyword. */
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,0GAA0G;AAC1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAA;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,0EAA0E,CAAA"}
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"}
@@ -1,7 +1,7 @@
1
- export type * from './rule/types.js';
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 './rule.js';
4
+ export * from './text.js';
5
5
  export * from './command.js';
6
6
  export * from './platform.js';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- export * from './rule.js';
1
+ export * from './text.js';
2
2
  export * from './command.js';
3
3
  export * from './platform.js';
4
4
  //# sourceMappingURL=index.js.map
@@ -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/rule/types.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/helpers/text/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { BotTextHelper } from './text/types.js';
2
+ export declare const createBotTextHelper: () => BotTextHelper;
3
+ export declare const botTextHelper: BotTextHelper;
4
+ //# sourceMappingURL=text.d.ts.map
@@ -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"}