@openclaw/slack 2026.7.1 → 2026.7.2-beta.1
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/dist/accounts.runtime-KvftRRek.js +2 -0
- package/dist/{action-runtime-DoQGk_8D.js → action-runtime-p6M2ULpv.js} +205 -29
- package/dist/action-runtime.runtime-DQstDkHG.js +2 -0
- package/dist/{actions-DMpDmKEA.js → actions-DkTcWmpT.js} +87 -138
- package/dist/{actions.runtime-C103_BPW.js → actions.runtime-BSxpwgUc.js} +1 -1
- package/dist/api.js +14 -13
- package/dist/{approval-handler.runtime-CIUbOt5T.js → approval-handler.runtime-UGbnz9OC.js} +3 -3
- package/dist/{channel-BjlsaGHn.js → channel-B0_j6C6z.js} +116 -140
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel-type-BpeTezY4.js +109 -0
- package/dist/{channel.setup-Dq6syTNU.js → channel.setup-BQFut21T.js} +2 -2
- package/dist/{client-DGxwSL7f.js → client-D2F6m8CP.js} +38 -2
- package/dist/config-api-Df9a1B8C.js +3 -0
- package/dist/{config-schema-BzqzFW__.js → config-schema-DYI01PV2.js} +20 -37
- package/dist/cursor-pages-DSmTg0su.js +13 -0
- package/dist/{directory-config-BZuS8141.js → directory-config-DRkFujwG.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-BNsxCgqP.js → directory-live-DX7yFsM-.js} +2 -2
- package/dist/{doctor-contract-XL6HeNCb.js → doctor-contract-DddfkMlF.js} +25 -38
- package/dist/doctor-contract-api.js +1 -1
- package/dist/group-policy-C-b2ZnSl.js +2332 -0
- package/dist/{interactive-replies-CXpT-vA_.js → interactive-replies-BilWUdcI.js} +5 -1
- package/dist/interactive-replies-api.js +1 -1
- package/dist/{message-tool-api-BgWKyu2r.js → message-tool-api-CA9jZrCY.js} +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/{monitor-Ux-wzUWI.js → monitor-BN_uuvrQ.js} +3 -3
- package/dist/outbound-adapter-ECl0go7d.js +228 -0
- package/dist/{pipeline.runtime-rpVpay59.js → pipeline.runtime-f0eJJoJL.js} +492 -178
- package/dist/{policy-Dj-puVPb.js → policy-f8b0edSi.js} +1 -1
- package/dist/preflight-audio.runtime-D5Bgags0.js +3 -0
- package/dist/{probe-CuwRDE5j.js → probe-CfALk0l4.js} +2 -2
- package/dist/{provider-C1-DFSpw.js → provider-Ds-y-imP.js} +658 -192
- package/dist/{relay-source-D2jv1iGg.js → relay-source-B-6LFUdz.js} +6 -17
- package/dist/replies-BMvf3ihj.js +420 -0
- package/dist/{resolve-channels-CstkChBE.js → resolve-channels-DOMgNCWb.js} +17 -6
- package/dist/{resolve-users-C3NP2c-Q.js → resolve-users-aL6-Ssee.js} +11 -6
- package/dist/{runtime-BOk7xkOl.js → runtime-CauEvswP.js} +1 -1
- package/dist/{runtime-api-CEmqYxR-.js → runtime-api-CVb6CQjX.js} +3 -3
- package/dist/runtime-api.js +11 -11
- package/dist/runtime-setter-api.js +1 -1
- package/dist/{scopes-DCWVD5-8.js → scopes-Dw8wbU0j.js} +2 -2
- package/dist/{secret-contract-C3ChHo5A.js → secret-contract-CMohXFWS.js} +18 -113
- package/dist/secret-contract-api.js +1 -1
- package/dist/{send-DKDXoeoV.js → send-NEfJ0GvM.js} +662 -325
- package/dist/{send.runtime-GPRa63l1.js → send.runtime-BkKpitPu.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-Dv2fIJNB.js → setup-surface-BN2WeG5c.js} +3 -3
- package/dist/{shared-CosfcFri.js → shared-BLnB9R1T.js} +7 -5
- package/dist/{slash-dispatch.runtime-CcMbbT3_.js → slash-dispatch.runtime-C0Otuf_T.js} +1 -1
- package/dist/{streaming-compat-DjlgH-Be.js → streaming-compat-3_X-21wW.js} +1 -0
- package/dist/{target-parsing-3jYH8LfB.js → target-parsing-N6lHogYZ.js} +16 -3
- package/dist/{targets-Dll4NJgs.js → targets-KmjP2E8s.js} +1 -1
- package/node_modules/p-map/index.d.ts +155 -0
- package/node_modules/p-map/index.js +284 -0
- package/node_modules/p-map/license +9 -0
- package/node_modules/p-map/package.json +57 -0
- package/node_modules/p-map/readme.md +190 -0
- package/npm-shrinkwrap.json +16 -3
- package/openclaw.plugin.json +16 -0
- package/package.json +6 -4
- package/dist/accounts.runtime-DWvaCb-X.js +0 -2
- package/dist/action-runtime.runtime-BABj3aM-.js +0 -2
- package/dist/config-api-DnT9ohtE.js +0 -2
- package/dist/format-YCNoNkM2.js +0 -107
- package/dist/outbound-adapter-DVoBfBW5.js +0 -272
- package/dist/replies-DpF38e1y.js +0 -287
- package/dist/reply-blocks-BGQ6zSqM.js +0 -877
- package/dist/resolve-allowlist-common-CP8SH0Zf.js +0 -43
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# p-map
|
|
2
|
+
|
|
3
|
+
> Map over promises concurrently
|
|
4
|
+
|
|
5
|
+
Useful when you need to run promise-returning & async functions multiple times with different inputs concurrently.
|
|
6
|
+
|
|
7
|
+
This is different from `Promise.all()` in that you can control the concurrency and also decide whether or not to stop iterating when there's an error.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install p-map
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import pMap from 'p-map';
|
|
19
|
+
import got from 'got';
|
|
20
|
+
|
|
21
|
+
const sites = [
|
|
22
|
+
getWebsiteFromUsername('sindresorhus'), //=> Promise
|
|
23
|
+
'https://avajs.dev',
|
|
24
|
+
'https://github.com'
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const mapper = async site => {
|
|
28
|
+
const {requestUrl} = await got.head(site);
|
|
29
|
+
return requestUrl;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const result = await pMap(sites, mapper, {concurrency: 2});
|
|
33
|
+
|
|
34
|
+
console.log(result);
|
|
35
|
+
//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/']
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
|
|
40
|
+
### pMap(input, mapper, options?)
|
|
41
|
+
|
|
42
|
+
Returns a `Promise` that is fulfilled when all promises in `input` and the ones returned from `mapper` are fulfilled, or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned from `mapper` in `input` order.
|
|
43
|
+
|
|
44
|
+
### pMapIterable(input, mapper, options?)
|
|
45
|
+
|
|
46
|
+
Returns an async iterable that streams each return value from `mapper` in order.
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import {pMapIterable} from 'p-map';
|
|
50
|
+
|
|
51
|
+
// Multiple posts are fetched concurrently, with limited concurrency and backpressure
|
|
52
|
+
for await (const post of pMapIterable(postIds, getPostMetadata, {concurrency: 8})) {
|
|
53
|
+
console.log(post);
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### input
|
|
58
|
+
|
|
59
|
+
Type: `AsyncIterable<Promise<unknown> | unknown> | Iterable<Promise<unknown> | unknown>`
|
|
60
|
+
|
|
61
|
+
Synchronous or asynchronous iterable that is iterated over concurrently, calling the `mapper` function for each element. Each iterated item is `await`'d before the `mapper` is invoked so the iterable may return a `Promise` that resolves to an item.
|
|
62
|
+
|
|
63
|
+
Asynchronous iterables (different from synchronous iterables that return `Promise` that resolves to an item) can be used when the next item may not be ready without waiting for an asynchronous process to complete and/or the end of the iterable may be reached after the asynchronous process completes. For example, reading from a remote queue when the queue has reached empty, or reading lines from a stream.
|
|
64
|
+
|
|
65
|
+
#### mapper(element, index)
|
|
66
|
+
|
|
67
|
+
Type: `Function`
|
|
68
|
+
|
|
69
|
+
Expected to return a `Promise` or value.
|
|
70
|
+
|
|
71
|
+
#### options
|
|
72
|
+
|
|
73
|
+
Type: `object`
|
|
74
|
+
|
|
75
|
+
##### concurrency
|
|
76
|
+
|
|
77
|
+
Type: `number` *(Integer)*\
|
|
78
|
+
Default: `Infinity`\
|
|
79
|
+
Minimum: `1`
|
|
80
|
+
|
|
81
|
+
Number of concurrently pending promises returned by `mapper`.
|
|
82
|
+
|
|
83
|
+
##### backpressure
|
|
84
|
+
|
|
85
|
+
**Only for `pMapIterable`**
|
|
86
|
+
|
|
87
|
+
Type: `number` *(Integer)*\
|
|
88
|
+
Default: `options.concurrency`\
|
|
89
|
+
Minimum: `options.concurrency`
|
|
90
|
+
|
|
91
|
+
Maximum number of promises returned by `mapper` that have resolved but not yet collected by the consumer of the async iterable. Calls to `mapper` will be limited so that there is never too much backpressure.
|
|
92
|
+
|
|
93
|
+
Useful whenever you are consuming the iterable slower than what the mapper function can produce concurrently. For example, to avoid making an overwhelming number of HTTP requests if you are saving each of the results to a database.
|
|
94
|
+
|
|
95
|
+
##### stopOnError
|
|
96
|
+
|
|
97
|
+
**Only for `pMap`**
|
|
98
|
+
|
|
99
|
+
Type: `boolean`\
|
|
100
|
+
Default: `true`
|
|
101
|
+
|
|
102
|
+
When `true`, the first mapper rejection will be rejected back to the consumer.
|
|
103
|
+
|
|
104
|
+
When `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [`AggregateError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) containing all the errors from the rejected promises.
|
|
105
|
+
|
|
106
|
+
Caveat: When `true`, any already-started async mappers will continue to run until they resolve or reject. In the case of infinite concurrency with sync iterables, *all* mappers are invoked on startup and will continue after the first rejection. Use the `signal` option for abort control.
|
|
107
|
+
|
|
108
|
+
##### signal
|
|
109
|
+
|
|
110
|
+
**Only for `pMap`**
|
|
111
|
+
|
|
112
|
+
Type: [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal)
|
|
113
|
+
|
|
114
|
+
You can abort the promises using [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import pMap from 'p-map';
|
|
118
|
+
import delay from 'delay';
|
|
119
|
+
|
|
120
|
+
const abortController = new AbortController();
|
|
121
|
+
|
|
122
|
+
setTimeout(() => {
|
|
123
|
+
abortController.abort();
|
|
124
|
+
}, 500);
|
|
125
|
+
|
|
126
|
+
const mapper = async value => value;
|
|
127
|
+
|
|
128
|
+
await pMap([delay(1000), delay(1000)], mapper, {signal: abortController.signal});
|
|
129
|
+
// Throws AbortError (DOMException) after 500 ms.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### pMapSkip
|
|
133
|
+
|
|
134
|
+
Return this value from a `mapper` function to skip including the value in the returned array.
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
import pMap, {pMapSkip} from 'p-map';
|
|
138
|
+
import got from 'got';
|
|
139
|
+
|
|
140
|
+
const sites = [
|
|
141
|
+
getWebsiteFromUsername('sindresorhus'), //=> Promise
|
|
142
|
+
'https://avajs.dev',
|
|
143
|
+
'https://example.invalid',
|
|
144
|
+
'https://github.com'
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
const mapper = async site => {
|
|
148
|
+
try {
|
|
149
|
+
const {requestUrl} = await got.head(site);
|
|
150
|
+
return requestUrl;
|
|
151
|
+
} catch {
|
|
152
|
+
return pMapSkip;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const result = await pMap(sites, mapper, {concurrency: 2});
|
|
157
|
+
|
|
158
|
+
console.log(result);
|
|
159
|
+
//=> ['https://sindresorhus.com/', 'https://avajs.dev/', 'https://github.com/']
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Recipes
|
|
163
|
+
|
|
164
|
+
### Rate limiting
|
|
165
|
+
|
|
166
|
+
This package controls how many mapper promises run concurrently. To limit how often the mapper starts, compose it with a rate limiter like [`p-throttle`](https://github.com/sindresorhus/p-throttle):
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
import pThrottle from 'p-throttle';
|
|
170
|
+
import pMap from 'p-map';
|
|
171
|
+
|
|
172
|
+
const throttle = pThrottle({
|
|
173
|
+
limit: 1,
|
|
174
|
+
interval: 1000,
|
|
175
|
+
strict: true,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const result = await pMap(input, throttle(mapper), {concurrency: 2});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
For more advanced scheduling, use [`p-queue`](https://github.com/sindresorhus/p-queue).
|
|
182
|
+
|
|
183
|
+
## Related
|
|
184
|
+
|
|
185
|
+
- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
|
|
186
|
+
- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently
|
|
187
|
+
- [p-times](https://github.com/sindresorhus/p-times) - Run promise-returning & async functions a specific number of times concurrently
|
|
188
|
+
- [p-props](https://github.com/sindresorhus/p-props) - Like `Promise.all()` but for `Map` and `Object`
|
|
189
|
+
- [p-map-series](https://github.com/sindresorhus/p-map-series) - Map over promises serially
|
|
190
|
+
- [More…](https://github.com/sindresorhus/promise-fun)
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/slack",
|
|
3
|
-
"version": "2026.7.1",
|
|
3
|
+
"version": "2026.7.2-beta.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@openclaw/slack",
|
|
9
|
-
"version": "2026.7.1",
|
|
9
|
+
"version": "2026.7.2-beta.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@slack/bolt": "4.7.3",
|
|
12
12
|
"@slack/types": "2.21.1",
|
|
13
13
|
"@slack/web-api": "7.18.0",
|
|
14
|
+
"p-map": "7.0.5",
|
|
14
15
|
"typebox": "1.3.3",
|
|
15
16
|
"ws": "8.21.0",
|
|
16
17
|
"zod": "4.4.3"
|
|
17
18
|
},
|
|
18
19
|
"peerDependencies": {
|
|
19
|
-
"openclaw": ">=2026.7.1"
|
|
20
|
+
"openclaw": ">=2026.7.2-beta.1"
|
|
20
21
|
},
|
|
21
22
|
"peerDependenciesMeta": {
|
|
22
23
|
"openclaw": {
|
|
@@ -982,6 +983,18 @@
|
|
|
982
983
|
"node": ">=4"
|
|
983
984
|
}
|
|
984
985
|
},
|
|
986
|
+
"node_modules/p-map": {
|
|
987
|
+
"version": "7.0.5",
|
|
988
|
+
"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.5.tgz",
|
|
989
|
+
"integrity": "sha512-e8vJF4XdVkzqqSHguEMz41mQO1wKwxKm5ENrUJQUu9kLDCtn83cxbyHZcszr4QC5zEA7WffRRC4gsTecC7J9oA==",
|
|
990
|
+
"license": "MIT",
|
|
991
|
+
"engines": {
|
|
992
|
+
"node": ">=18"
|
|
993
|
+
},
|
|
994
|
+
"funding": {
|
|
995
|
+
"url": "https://github.com/sponsors/sindresorhus"
|
|
996
|
+
}
|
|
997
|
+
},
|
|
985
998
|
"node_modules/p-queue": {
|
|
986
999
|
"version": "6.6.2",
|
|
987
1000
|
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
|
package/openclaw.plugin.json
CHANGED
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
"relay"
|
|
30
30
|
]
|
|
31
31
|
},
|
|
32
|
+
"enterpriseOrgInstall": {
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
32
35
|
"socketMode": {
|
|
33
36
|
"type": "object",
|
|
34
37
|
"properties": {
|
|
@@ -819,6 +822,9 @@
|
|
|
819
822
|
"commentary": {
|
|
820
823
|
"type": "boolean"
|
|
821
824
|
},
|
|
825
|
+
"narration": {
|
|
826
|
+
"type": "boolean"
|
|
827
|
+
},
|
|
822
828
|
"nativeTaskCards": {
|
|
823
829
|
"type": "boolean"
|
|
824
830
|
}
|
|
@@ -1341,6 +1347,9 @@
|
|
|
1341
1347
|
"relay"
|
|
1342
1348
|
]
|
|
1343
1349
|
},
|
|
1350
|
+
"enterpriseOrgInstall": {
|
|
1351
|
+
"type": "boolean"
|
|
1352
|
+
},
|
|
1344
1353
|
"socketMode": {
|
|
1345
1354
|
"type": "object",
|
|
1346
1355
|
"properties": {
|
|
@@ -2129,6 +2138,9 @@
|
|
|
2129
2138
|
"commentary": {
|
|
2130
2139
|
"type": "boolean"
|
|
2131
2140
|
},
|
|
2141
|
+
"narration": {
|
|
2142
|
+
"type": "boolean"
|
|
2143
|
+
},
|
|
2132
2144
|
"nativeTaskCards": {
|
|
2133
2145
|
"type": "boolean"
|
|
2134
2146
|
}
|
|
@@ -2658,6 +2670,10 @@
|
|
|
2658
2670
|
"label": "Slack",
|
|
2659
2671
|
"help": "Slack channel provider configuration for bot/app tokens, streaming behavior, and DM policy controls. Keep token handling and thread behavior explicit to avoid noisy workspace interactions."
|
|
2660
2672
|
},
|
|
2673
|
+
"enterpriseOrgInstall": {
|
|
2674
|
+
"label": "Slack Enterprise Grid Org Install",
|
|
2675
|
+
"help": "Enable only for an Enterprise Grid org-wide bot installation. OpenClaw verifies the token with Slack auth.test at startup; DMs must be disabled or use dmPolicy=\"open\" with allowFrom=[\"*\"]."
|
|
2676
|
+
},
|
|
2661
2677
|
"dm.policy": {
|
|
2662
2678
|
"label": "Slack DM Policy",
|
|
2663
2679
|
"help": "Direct message access control (\"pairing\" recommended). \"open\" requires channels.slack.allowFrom=[\"*\"] (legacy: channels.slack.dm.allowFrom)."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/slack",
|
|
3
|
-
"version": "2026.7.1",
|
|
3
|
+
"version": "2026.7.2-beta.1",
|
|
4
4
|
"description": "OpenClaw Slack channel plugin for channels, DMs, commands, and app events.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
"@slack/bolt": "4.7.3",
|
|
12
12
|
"@slack/types": "2.21.1",
|
|
13
13
|
"@slack/web-api": "7.18.0",
|
|
14
|
+
"p-map": "7.0.5",
|
|
14
15
|
"typebox": "1.3.3",
|
|
15
16
|
"ws": "8.21.0",
|
|
16
17
|
"zod": "4.4.3"
|
|
17
18
|
},
|
|
18
19
|
"peerDependencies": {
|
|
19
|
-
"openclaw": ">=2026.7.1"
|
|
20
|
+
"openclaw": ">=2026.7.2-beta.1"
|
|
20
21
|
},
|
|
21
22
|
"peerDependenciesMeta": {
|
|
22
23
|
"openclaw": {
|
|
@@ -61,13 +62,13 @@
|
|
|
61
62
|
"allowInvalidConfigRecovery": true
|
|
62
63
|
},
|
|
63
64
|
"compat": {
|
|
64
|
-
"pluginApi": ">=2026.7.1"
|
|
65
|
+
"pluginApi": ">=2026.7.2-beta.1"
|
|
65
66
|
},
|
|
66
67
|
"startup": {
|
|
67
68
|
"deferConfiguredChannelFullLoadUntilAfterListen": true
|
|
68
69
|
},
|
|
69
70
|
"build": {
|
|
70
|
-
"openclawVersion": "2026.7.1",
|
|
71
|
+
"openclawVersion": "2026.7.2-beta.1",
|
|
71
72
|
"bundledDist": false
|
|
72
73
|
},
|
|
73
74
|
"release": {
|
|
@@ -90,6 +91,7 @@
|
|
|
90
91
|
"@slack/bolt",
|
|
91
92
|
"@slack/types",
|
|
92
93
|
"@slack/web-api",
|
|
94
|
+
"p-map",
|
|
93
95
|
"typebox",
|
|
94
96
|
"ws",
|
|
95
97
|
"zod"
|
package/dist/format-YCNoNkM2.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { markdownToIR, renderMarkdownIRChunksWithinLimit, renderMarkdownWithMarkers } from "openclaw/plugin-sdk/text-chunking";
|
|
2
|
-
//#region extensions/slack/src/format.ts
|
|
3
|
-
function escapeSlackMrkdwnSegment(text) {
|
|
4
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
5
|
-
}
|
|
6
|
-
const SLACK_ANGLE_TOKEN_RE = /<[^>\n]+>/g;
|
|
7
|
-
function isAllowedSlackAngleToken(token) {
|
|
8
|
-
if (!token.startsWith("<") || !token.endsWith(">")) return false;
|
|
9
|
-
const inner = token.slice(1, -1);
|
|
10
|
-
return inner.startsWith("@") || inner.startsWith("#") || inner.startsWith("!") || inner.startsWith("mailto:") || inner.startsWith("tel:") || inner.startsWith("http://") || inner.startsWith("https://") || inner.startsWith("slack://");
|
|
11
|
-
}
|
|
12
|
-
function escapeSlackMrkdwnContent(text) {
|
|
13
|
-
if (!text) return "";
|
|
14
|
-
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
15
|
-
SLACK_ANGLE_TOKEN_RE.lastIndex = 0;
|
|
16
|
-
const out = [];
|
|
17
|
-
let lastIndex = 0;
|
|
18
|
-
for (let match = SLACK_ANGLE_TOKEN_RE.exec(text); match; match = SLACK_ANGLE_TOKEN_RE.exec(text)) {
|
|
19
|
-
const matchIndex = match.index ?? 0;
|
|
20
|
-
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex, matchIndex)));
|
|
21
|
-
const token = match[0] ?? "";
|
|
22
|
-
out.push(isAllowedSlackAngleToken(token) ? token : escapeSlackMrkdwnSegment(token));
|
|
23
|
-
lastIndex = matchIndex + token.length;
|
|
24
|
-
}
|
|
25
|
-
out.push(escapeSlackMrkdwnSegment(text.slice(lastIndex)));
|
|
26
|
-
return out.join("");
|
|
27
|
-
}
|
|
28
|
-
function escapeSlackMrkdwnText(text) {
|
|
29
|
-
if (!text) return "";
|
|
30
|
-
if (!text.includes("&") && !text.includes("<") && !text.includes(">")) return text;
|
|
31
|
-
return text.split("\n").map((line) => {
|
|
32
|
-
if (line.startsWith("> ")) return `> ${escapeSlackMrkdwnContent(line.slice(2))}`;
|
|
33
|
-
return escapeSlackMrkdwnContent(line);
|
|
34
|
-
}).join("\n");
|
|
35
|
-
}
|
|
36
|
-
function buildSlackLink(link, text) {
|
|
37
|
-
const href = link.href.trim();
|
|
38
|
-
if (!href) return null;
|
|
39
|
-
const trimmedLabel = text.slice(link.start, link.end).trim();
|
|
40
|
-
const comparableHref = href.startsWith("mailto:") ? href.slice(7) : href;
|
|
41
|
-
if (!(trimmedLabel.length > 0 && trimmedLabel !== href && trimmedLabel !== comparableHref)) return null;
|
|
42
|
-
const safeHref = escapeSlackMrkdwnSegment(href);
|
|
43
|
-
return {
|
|
44
|
-
start: link.start,
|
|
45
|
-
end: link.end,
|
|
46
|
-
open: `<${safeHref}|`,
|
|
47
|
-
close: ">"
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function buildSlackRenderOptions() {
|
|
51
|
-
return {
|
|
52
|
-
styleMarkers: {
|
|
53
|
-
bold: {
|
|
54
|
-
open: "*",
|
|
55
|
-
close: "*"
|
|
56
|
-
},
|
|
57
|
-
italic: {
|
|
58
|
-
open: "_",
|
|
59
|
-
close: "_"
|
|
60
|
-
},
|
|
61
|
-
strikethrough: {
|
|
62
|
-
open: "~",
|
|
63
|
-
close: "~"
|
|
64
|
-
},
|
|
65
|
-
code: {
|
|
66
|
-
open: "`",
|
|
67
|
-
close: "`"
|
|
68
|
-
},
|
|
69
|
-
code_block: {
|
|
70
|
-
open: "```\n",
|
|
71
|
-
close: "```"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
escapeText: escapeSlackMrkdwnText,
|
|
75
|
-
buildLink: buildSlackLink
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function markdownToSlackMrkdwn(markdown, options = {}) {
|
|
79
|
-
return renderMarkdownWithMarkers(markdownToIR(markdown ?? "", {
|
|
80
|
-
linkify: false,
|
|
81
|
-
autolink: false,
|
|
82
|
-
headingStyle: "bold",
|
|
83
|
-
blockquotePrefix: "> ",
|
|
84
|
-
tableMode: options.tableMode
|
|
85
|
-
}), buildSlackRenderOptions());
|
|
86
|
-
}
|
|
87
|
-
function normalizeSlackOutboundText(markdown) {
|
|
88
|
-
return markdownToSlackMrkdwn(markdown ?? "");
|
|
89
|
-
}
|
|
90
|
-
function markdownToSlackMrkdwnChunks(markdown, limit, options = {}) {
|
|
91
|
-
const ir = markdownToIR(markdown ?? "", {
|
|
92
|
-
linkify: false,
|
|
93
|
-
autolink: false,
|
|
94
|
-
headingStyle: "bold",
|
|
95
|
-
blockquotePrefix: "> ",
|
|
96
|
-
tableMode: options.tableMode
|
|
97
|
-
});
|
|
98
|
-
const renderOptions = buildSlackRenderOptions();
|
|
99
|
-
return renderMarkdownIRChunksWithinLimit({
|
|
100
|
-
ir,
|
|
101
|
-
limit,
|
|
102
|
-
renderChunk: (chunk) => renderMarkdownWithMarkers(chunk, renderOptions),
|
|
103
|
-
measureRendered: (rendered) => rendered.length
|
|
104
|
-
}).map(({ rendered }) => rendered);
|
|
105
|
-
}
|
|
106
|
-
//#endregion
|
|
107
|
-
export { normalizeSlackOutboundText as n, markdownToSlackMrkdwnChunks as t };
|