@objectstack/connector-slack 17.0.0-rc.0 → 17.0.0-rc.2
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/CHANGELOG.md +325 -0
- package/package.json +12 -6
- package/.turbo/turbo-build.log +0 -22
- package/src/connector-slack-plugin.test.ts +0 -78
- package/src/connector-slack-plugin.ts +0 -79
- package/src/index.ts +0 -28
- package/src/slack-connector.test.ts +0 -132
- package/src/slack-connector.ts +0 -210
- package/tsconfig.json +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,330 @@
|
|
|
1
1
|
# @objectstack/connector-slack
|
|
2
2
|
|
|
3
|
+
## 17.0.0-rc.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [430dcc2]
|
|
8
|
+
- Updated dependencies [e6ac4bd]
|
|
9
|
+
- Updated dependencies [80334c7]
|
|
10
|
+
- Updated dependencies [ce5242c]
|
|
11
|
+
- Updated dependencies [a7163ea]
|
|
12
|
+
- Updated dependencies [e6e9379]
|
|
13
|
+
- Updated dependencies [98877c9]
|
|
14
|
+
- Updated dependencies [98877c9]
|
|
15
|
+
- Updated dependencies [e6b1b69]
|
|
16
|
+
- Updated dependencies [ad047d2]
|
|
17
|
+
- Updated dependencies [2826d1e]
|
|
18
|
+
- Updated dependencies [5a84d41]
|
|
19
|
+
- Updated dependencies [20b1a9e]
|
|
20
|
+
- Updated dependencies [203a449]
|
|
21
|
+
- Updated dependencies [ac37fc6]
|
|
22
|
+
- Updated dependencies [4820f55]
|
|
23
|
+
- Updated dependencies [462d9c4]
|
|
24
|
+
- Updated dependencies [7d21581]
|
|
25
|
+
- Updated dependencies [f2445c9]
|
|
26
|
+
- Updated dependencies [23338c3]
|
|
27
|
+
- Updated dependencies [5b843fb]
|
|
28
|
+
- Updated dependencies [b4487aa]
|
|
29
|
+
- Updated dependencies [65ca83a]
|
|
30
|
+
- Updated dependencies [67bf2e2]
|
|
31
|
+
- Updated dependencies [c6d1cb4]
|
|
32
|
+
- Updated dependencies [36030ff]
|
|
33
|
+
- Updated dependencies [6117f7b]
|
|
34
|
+
- Updated dependencies [e533b0b]
|
|
35
|
+
- Updated dependencies [cdf4d9a]
|
|
36
|
+
- Updated dependencies [aee1806]
|
|
37
|
+
- Updated dependencies [c13350b]
|
|
38
|
+
- Updated dependencies [c13350b]
|
|
39
|
+
- Updated dependencies [9ca2d85]
|
|
40
|
+
- Updated dependencies [c13350b]
|
|
41
|
+
- Updated dependencies [891d345]
|
|
42
|
+
- Updated dependencies [a52e2ef]
|
|
43
|
+
- Updated dependencies [5293114]
|
|
44
|
+
- Updated dependencies [20bc357]
|
|
45
|
+
- Updated dependencies [5966c2a]
|
|
46
|
+
- Updated dependencies [2382580]
|
|
47
|
+
- Updated dependencies [d9fa683]
|
|
48
|
+
- Updated dependencies [3c7bcc0]
|
|
49
|
+
- Updated dependencies [4b6cac7]
|
|
50
|
+
- Updated dependencies [7631964]
|
|
51
|
+
- Updated dependencies [ac471a0]
|
|
52
|
+
- Updated dependencies [60ae58e]
|
|
53
|
+
- Updated dependencies [ce92674]
|
|
54
|
+
- Updated dependencies [9f601e8]
|
|
55
|
+
- Updated dependencies [51c5227]
|
|
56
|
+
- Updated dependencies [a4a85c8]
|
|
57
|
+
- Updated dependencies [07a4e26]
|
|
58
|
+
- Updated dependencies [ec975f1]
|
|
59
|
+
- Updated dependencies [eb4204b]
|
|
60
|
+
- Updated dependencies [4f13be2]
|
|
61
|
+
- Updated dependencies [61cc079]
|
|
62
|
+
- Updated dependencies [0e96e46]
|
|
63
|
+
- Updated dependencies [d52d4fe]
|
|
64
|
+
- Updated dependencies [742cebb]
|
|
65
|
+
- Updated dependencies [ce92674]
|
|
66
|
+
- Updated dependencies [cf2c9b7]
|
|
67
|
+
- Updated dependencies [833b512]
|
|
68
|
+
- Updated dependencies [0f9faa2]
|
|
69
|
+
- Updated dependencies [7cf42fe]
|
|
70
|
+
- Updated dependencies [5966c2a]
|
|
71
|
+
- Updated dependencies [f78dd83]
|
|
72
|
+
- Updated dependencies [a2cd18a]
|
|
73
|
+
- Updated dependencies [4638aaa]
|
|
74
|
+
- Updated dependencies [0222d3c]
|
|
75
|
+
- Updated dependencies [071d0dc]
|
|
76
|
+
- Updated dependencies [0a936ea]
|
|
77
|
+
- Updated dependencies [023c00b]
|
|
78
|
+
- Updated dependencies [155507e]
|
|
79
|
+
- Updated dependencies [7bba90b]
|
|
80
|
+
- Updated dependencies [7e05d8e]
|
|
81
|
+
- Updated dependencies [061406d]
|
|
82
|
+
- Updated dependencies [c1f344b]
|
|
83
|
+
- Updated dependencies [9c93465]
|
|
84
|
+
- Updated dependencies [ebb209c]
|
|
85
|
+
- Updated dependencies [63b33e6]
|
|
86
|
+
- Updated dependencies [2a44c1d]
|
|
87
|
+
- Updated dependencies [695cfbd]
|
|
88
|
+
- Updated dependencies [7445149]
|
|
89
|
+
- Updated dependencies [071d0dc]
|
|
90
|
+
- Updated dependencies [0848bea]
|
|
91
|
+
- Updated dependencies [d51bed2]
|
|
92
|
+
- Updated dependencies [b8b3c64]
|
|
93
|
+
- Updated dependencies [0c0fbd9]
|
|
94
|
+
- Updated dependencies [f3141d8]
|
|
95
|
+
- Updated dependencies [5a84d41]
|
|
96
|
+
- Updated dependencies [fd3013a]
|
|
97
|
+
- Updated dependencies [21676eb]
|
|
98
|
+
- Updated dependencies [e336549]
|
|
99
|
+
- Updated dependencies [d40f43a]
|
|
100
|
+
- Updated dependencies [e5e7ee0]
|
|
101
|
+
- Updated dependencies [a2ebea2]
|
|
102
|
+
- Updated dependencies [800bdb0]
|
|
103
|
+
- Updated dependencies [04f1182]
|
|
104
|
+
- Updated dependencies [5647006]
|
|
105
|
+
- Updated dependencies [38f7e4f]
|
|
106
|
+
- Updated dependencies [c57f3cf]
|
|
107
|
+
- Updated dependencies [97faca3]
|
|
108
|
+
- Updated dependencies [ad5fe25]
|
|
109
|
+
- Updated dependencies [ea90179]
|
|
110
|
+
- Updated dependencies [ce92674]
|
|
111
|
+
- Updated dependencies [5ef0b5b]
|
|
112
|
+
- Updated dependencies [48fbacb]
|
|
113
|
+
- Updated dependencies [355e951]
|
|
114
|
+
- Updated dependencies [dadb43f]
|
|
115
|
+
- @objectstack/spec@17.0.0-rc.2
|
|
116
|
+
- @objectstack/core@17.0.0-rc.2
|
|
117
|
+
|
|
118
|
+
## 17.0.0-rc.1
|
|
119
|
+
|
|
120
|
+
### Patch Changes
|
|
121
|
+
|
|
122
|
+
- 2e836de: chore(packaging): CHANGELOG.md ships in every npm tarball (#4261)
|
|
123
|
+
|
|
124
|
+
The AGENTS.md post-task checklist requires breaking changesets to carry their
|
|
125
|
+
FROM → TO migration because "this text ships to consumers as `CHANGELOG.md`
|
|
126
|
+
inside the npm package and is what an upgrading agent greps after the tombstone
|
|
127
|
+
error." That delivery path was severed for 68 of the 69 publishable packages:
|
|
128
|
+
npm packs `package.json` / `README*` / `LICENSE*` unconditionally but — unlike
|
|
129
|
+
older npm versions — not `CHANGELOG.md`, and the canonical
|
|
130
|
+
`"files": ["dist", "README.md"]` whitelist never named it. Measured on npm
|
|
131
|
+
10.9.7: `npm pack --dry-run` on `@objectstack/types` shipped 3 files while its
|
|
132
|
+
70KB `CHANGELOG.md` stayed behind. Only `@objectstack/spec` listed it
|
|
133
|
+
explicitly.
|
|
134
|
+
|
|
135
|
+
The tombstone-error scenario is precisely the one where the repo is out of
|
|
136
|
+
reach — the upgrading agent has `node_modules` and nothing else — so the
|
|
137
|
+
migration text has to ride in the tarball. Every publishable package now
|
|
138
|
+
declares `CHANGELOG.md` in `files`, and the canonical whitelist is
|
|
139
|
+
`["dist", "README.md", "CHANGELOG.md"]`.
|
|
140
|
+
|
|
141
|
+
The other half is the gate: `check:published-files` gains a fifth invariant,
|
|
142
|
+
COMPLETE — a whitelist that fails to cover `CHANGELOG.md` fails the
|
|
143
|
+
always-required lint job, so the next package cannot silently sever the path
|
|
144
|
+
again. `@objectstack/spec`'s per-package EXTRA_ENTRIES exemption dissolves
|
|
145
|
+
into the canonical set.
|
|
146
|
+
|
|
147
|
+
Consumer-visible change: one more file per install (the package's changelog,
|
|
148
|
+
e.g. 70.8KB for `@objectstack/types`), and `grep -r "removed key"
|
|
149
|
+
node_modules/@objectstack/*/CHANGELOG.md` now finds the migration it was
|
|
150
|
+
promised.
|
|
151
|
+
|
|
152
|
+
- cc2de0e: chore(packaging): 20 packages stop publishing their sources, tests and build tooling (#4248)
|
|
153
|
+
|
|
154
|
+
These 20 packages declared no `files` field, so npm fell back to packing the
|
|
155
|
+
whole package directory. `npm pack --dry-run` on `@objectstack/plugin-webhooks`
|
|
156
|
+
listed **21 files** — 15 under `src/`, three of them unit tests
|
|
157
|
+
(`auto-enqueuer.test.ts`, `bootstrap-declared-webhooks.test.ts`, …), plus the
|
|
158
|
+
build-time `scripts/i18n-extract.config.ts`. `dist/` lands on top of that at
|
|
159
|
+
publish time rather than instead of it, so consumers were installing the
|
|
160
|
+
TypeScript sources and the test suite alongside the artifact they asked for.
|
|
161
|
+
|
|
162
|
+
Each now declares `"files": ["dist", "README.md"]`, matching the 29 packages
|
|
163
|
+
that already did. Nothing a consumer imports moves: every `main` / `types` /
|
|
164
|
+
`exports` target in all 20 already resolved inside `dist/`, which the new
|
|
165
|
+
`check:published-files` guard verifies rather than assumes. The visible change
|
|
166
|
+
is a smaller install and a smaller dependency-scanning surface — `npm pack` on
|
|
167
|
+
`@objectstack/plugin-webhooks` now yields 2 files plus `dist/`.
|
|
168
|
+
|
|
169
|
+
The other half of the fix is the gate. Half the packages declaring `files` and
|
|
170
|
+
half not was the #3786 shape — a hand-copied convention with nothing enforcing
|
|
171
|
+
it, where whoever forgets the line gets no signal at all. `check:published-files`
|
|
172
|
+
(new, wired into the always-required `lint` job) holds every non-private
|
|
173
|
+
workspace package to four invariants: `files` is **declared**; it is
|
|
174
|
+
**sufficient** (covers every entry point, so tightening a whitelist cannot ship
|
|
175
|
+
a package that fails to resolve); it is **minimal** (admits no test, test-harness
|
|
176
|
+
config or build script); and anything beyond `dist` + `README.md` is
|
|
177
|
+
**registered** with a reason, reconciled in both directions so a stale exemption
|
|
178
|
+
is an error rather than dead text. `@objectstack/spec` is the one package with
|
|
179
|
+
registered extras — its `.zod.ts` sources, JSON Schemas, liveness ledgers and
|
|
180
|
+
`CHANGELOG.md` are product, not build input.
|
|
181
|
+
|
|
182
|
+
This also closes an assumption #4206 was resting on. Excluding `<pkg>/scripts/**`
|
|
183
|
+
from the docs-drift implementation test is sound only while no package publishes
|
|
184
|
+
`scripts/` as runtime code; that held, but it held because someone read all three
|
|
185
|
+
offenders by hand. It is now checked on every PR.
|
|
186
|
+
|
|
187
|
+
- Updated dependencies [6a67d7a]
|
|
188
|
+
- Updated dependencies [0ecc656]
|
|
189
|
+
- Updated dependencies [06772eb]
|
|
190
|
+
- Updated dependencies [270650f]
|
|
191
|
+
- Updated dependencies [3aef718]
|
|
192
|
+
- Updated dependencies [1ea6bce]
|
|
193
|
+
- Updated dependencies [c1dcacd]
|
|
194
|
+
- Updated dependencies [ad303ed]
|
|
195
|
+
- Updated dependencies [32ccb23]
|
|
196
|
+
- Updated dependencies [f5a4ef0]
|
|
197
|
+
- Updated dependencies [2d3e255]
|
|
198
|
+
- Updated dependencies [7d7521f]
|
|
199
|
+
- Updated dependencies [5dc4d02]
|
|
200
|
+
- Updated dependencies [05154a1]
|
|
201
|
+
- Updated dependencies [9b6fe7c]
|
|
202
|
+
- Updated dependencies [8c711fb]
|
|
203
|
+
- Updated dependencies [09e4547]
|
|
204
|
+
- Updated dependencies [91f4c78]
|
|
205
|
+
- Updated dependencies [820eff9]
|
|
206
|
+
- Updated dependencies [8d895ff]
|
|
207
|
+
- Updated dependencies [f6472d7]
|
|
208
|
+
- Updated dependencies [78caf51]
|
|
209
|
+
- Updated dependencies [62a789b]
|
|
210
|
+
- Updated dependencies [789ad63]
|
|
211
|
+
- Updated dependencies [2af1988]
|
|
212
|
+
- Updated dependencies [0af50a3]
|
|
213
|
+
- Updated dependencies [2e836de]
|
|
214
|
+
- Updated dependencies [12a19a8]
|
|
215
|
+
- Updated dependencies [41dcda3]
|
|
216
|
+
- Updated dependencies [c8124e5]
|
|
217
|
+
- Updated dependencies [a1a4140]
|
|
218
|
+
- Updated dependencies [217e2e6]
|
|
219
|
+
- Updated dependencies [86a71d1]
|
|
220
|
+
- Updated dependencies [d5c75e2]
|
|
221
|
+
- Updated dependencies [03d26f7]
|
|
222
|
+
- Updated dependencies [4384921]
|
|
223
|
+
- Updated dependencies [3c628ce]
|
|
224
|
+
- Updated dependencies [7cb922e]
|
|
225
|
+
- Updated dependencies [1d22114]
|
|
226
|
+
- Updated dependencies [b5f9397]
|
|
227
|
+
- Updated dependencies [ed77493]
|
|
228
|
+
- Updated dependencies [58a03d2]
|
|
229
|
+
- Updated dependencies [dc530b4]
|
|
230
|
+
- Updated dependencies [e59786e]
|
|
231
|
+
- Updated dependencies [bcf1112]
|
|
232
|
+
- Updated dependencies [9774b78]
|
|
233
|
+
- Updated dependencies [b07d829]
|
|
234
|
+
- Updated dependencies [a648e96]
|
|
235
|
+
- Updated dependencies [a47ac06]
|
|
236
|
+
- Updated dependencies [e4c61a7]
|
|
237
|
+
- Updated dependencies [cc60165]
|
|
238
|
+
- Updated dependencies [081aa6f]
|
|
239
|
+
- Updated dependencies [91f4c78]
|
|
240
|
+
- Updated dependencies [e8d0c21]
|
|
241
|
+
- Updated dependencies [45dc446]
|
|
242
|
+
- Updated dependencies [c1d44f7]
|
|
243
|
+
- Updated dependencies [ab9fb5c]
|
|
244
|
+
- Updated dependencies [f985b3f]
|
|
245
|
+
- Updated dependencies [9a4932a]
|
|
246
|
+
- Updated dependencies [f9fc874]
|
|
247
|
+
- Updated dependencies [011b386]
|
|
248
|
+
- Updated dependencies [7777e8f]
|
|
249
|
+
- Updated dependencies [507b92a]
|
|
250
|
+
- Updated dependencies [7309c81]
|
|
251
|
+
- Updated dependencies [20bc1ec]
|
|
252
|
+
- Updated dependencies [90c2b15]
|
|
253
|
+
- Updated dependencies [42eeb7d]
|
|
254
|
+
- Updated dependencies [01e124d]
|
|
255
|
+
- Updated dependencies [7ce02eb]
|
|
256
|
+
- Updated dependencies [a13827e]
|
|
257
|
+
- Updated dependencies [7733604]
|
|
258
|
+
- Updated dependencies [40e420f]
|
|
259
|
+
- Updated dependencies [d13004a]
|
|
260
|
+
- Updated dependencies [be7360c]
|
|
261
|
+
- Updated dependencies [5b47ab5]
|
|
262
|
+
- Updated dependencies [b09d8d9]
|
|
263
|
+
- Updated dependencies [b09d8d9]
|
|
264
|
+
- Updated dependencies [8675db6]
|
|
265
|
+
- Updated dependencies [b09d8d9]
|
|
266
|
+
- Updated dependencies [3eb1b2b]
|
|
267
|
+
- Updated dependencies [59b85c0]
|
|
268
|
+
- Updated dependencies [6e357ed]
|
|
269
|
+
- Updated dependencies [d6938bf]
|
|
270
|
+
- Updated dependencies [31e0be9]
|
|
271
|
+
- Updated dependencies [4bfd455]
|
|
272
|
+
- Updated dependencies [ffd2ce2]
|
|
273
|
+
- Updated dependencies [62f8017]
|
|
274
|
+
- Updated dependencies [a831df1]
|
|
275
|
+
- Updated dependencies [f752ee3]
|
|
276
|
+
- Updated dependencies [a1b61e0]
|
|
277
|
+
- Updated dependencies [cd6b9f2]
|
|
278
|
+
- Updated dependencies [2cb6d3c]
|
|
279
|
+
- Updated dependencies [af2a095]
|
|
280
|
+
- Updated dependencies [ec796d5]
|
|
281
|
+
- Updated dependencies [e87fea1]
|
|
282
|
+
- Updated dependencies [c65e529]
|
|
283
|
+
- Updated dependencies [3ca34c1]
|
|
284
|
+
- Updated dependencies [239c3a3]
|
|
285
|
+
- Updated dependencies [94a0bbc]
|
|
286
|
+
- Updated dependencies [d6bfb3d]
|
|
287
|
+
- Updated dependencies [a2266a6]
|
|
288
|
+
- Updated dependencies [d25a0ec]
|
|
289
|
+
- Updated dependencies [667b83e]
|
|
290
|
+
- Updated dependencies [627b188]
|
|
291
|
+
- Updated dependencies [8d4eae7]
|
|
292
|
+
- Updated dependencies [857a6cf]
|
|
293
|
+
- Updated dependencies [65a3a84]
|
|
294
|
+
- Updated dependencies [ccd9397]
|
|
295
|
+
- Updated dependencies [bca935b]
|
|
296
|
+
- Updated dependencies [d92c72d]
|
|
297
|
+
- Updated dependencies [c54c822]
|
|
298
|
+
- Updated dependencies [8dcc0f5]
|
|
299
|
+
- Updated dependencies [75b9e51]
|
|
300
|
+
- Updated dependencies [0a2f233]
|
|
301
|
+
- Updated dependencies [8621cdd]
|
|
302
|
+
- Updated dependencies [6f23667]
|
|
303
|
+
- Updated dependencies [5d21a48]
|
|
304
|
+
- Updated dependencies [19365b7]
|
|
305
|
+
- Updated dependencies [b7ed26d]
|
|
306
|
+
- Updated dependencies [b3a3d83]
|
|
307
|
+
- Updated dependencies [7a55913]
|
|
308
|
+
- Updated dependencies [35accbf]
|
|
309
|
+
- Updated dependencies [6038de7]
|
|
310
|
+
- Updated dependencies [eb95d97]
|
|
311
|
+
- Updated dependencies [e4c2dc8]
|
|
312
|
+
- Updated dependencies [1bd2795]
|
|
313
|
+
- Updated dependencies [8186a70]
|
|
314
|
+
- Updated dependencies [a329cca]
|
|
315
|
+
- Updated dependencies [6eec18c]
|
|
316
|
+
- Updated dependencies [4d7bebf]
|
|
317
|
+
- Updated dependencies [821ac7a]
|
|
318
|
+
- Updated dependencies [8f81731]
|
|
319
|
+
- Updated dependencies [8b50cb3]
|
|
320
|
+
- Updated dependencies [8c2db68]
|
|
321
|
+
- Updated dependencies [22b5e54]
|
|
322
|
+
- Updated dependencies [0166bd5]
|
|
323
|
+
- Updated dependencies [9b702dc]
|
|
324
|
+
- Updated dependencies [ab16331]
|
|
325
|
+
- @objectstack/spec@17.0.0-rc.1
|
|
326
|
+
- @objectstack/core@17.0.0-rc.1
|
|
327
|
+
|
|
3
328
|
## 17.0.0-rc.0
|
|
4
329
|
|
|
5
330
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/connector-slack",
|
|
3
|
-
"version": "17.0.0-rc.
|
|
3
|
+
"version": "17.0.0-rc.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Slack Web API connector for ObjectStack — registers `chat.postMessage` / `chat.update` / `call` actions on the automation engine's connector registry (ADR-0018 §Addendum, ADR-0022).",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@objectstack/core": "17.0.0-rc.
|
|
17
|
-
"@objectstack/spec": "17.0.0-rc.
|
|
16
|
+
"@objectstack/core": "17.0.0-rc.2",
|
|
17
|
+
"@objectstack/spec": "17.0.0-rc.2"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@types/node": "^26.1.
|
|
20
|
+
"@types/node": "^26.1.2",
|
|
21
21
|
"typescript": "^6.0.3",
|
|
22
22
|
"vitest": "^4.1.10",
|
|
23
|
-
"@objectstack/service-automation": "17.0.0-rc.
|
|
23
|
+
"@objectstack/service-automation": "17.0.0-rc.2"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"objectstack",
|
|
@@ -29,8 +29,14 @@
|
|
|
29
29
|
"integration",
|
|
30
30
|
"messaging"
|
|
31
31
|
],
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md",
|
|
35
|
+
"CHANGELOG.md"
|
|
36
|
+
],
|
|
32
37
|
"scripts": {
|
|
33
38
|
"build": "tsup --config ../../../tsup.config.ts",
|
|
34
|
-
"test": "vitest run --passWithNoTests"
|
|
39
|
+
"test": "vitest run --passWithNoTests",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
35
41
|
}
|
|
36
42
|
}
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @objectstack/connector-slack@17.0.0-rc.0 build /home/runner/work/objectstack/objectstack/packages/connectors/connector-slack
|
|
3
|
-
> tsup --config ../../../tsup.config.ts
|
|
4
|
-
|
|
5
|
-
[34mCLI[39m Building entry: src/index.ts
|
|
6
|
-
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup v8.5.1
|
|
8
|
-
[34mCLI[39m Using tsup config: /home/runner/work/objectstack/objectstack/tsup.config.ts
|
|
9
|
-
[34mCLI[39m Target: es2020
|
|
10
|
-
[34mCLI[39m Cleaning output folder
|
|
11
|
-
[34mESM[39m Build start
|
|
12
|
-
[34mCJS[39m Build start
|
|
13
|
-
[32mESM[39m [1mdist/index.mjs [22m[32m5.40 KB[39m
|
|
14
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[32m15.25 KB[39m
|
|
15
|
-
[32mESM[39m ⚡️ Build success in 96ms
|
|
16
|
-
[32mCJS[39m [1mdist/index.js [22m[32m6.48 KB[39m
|
|
17
|
-
[32mCJS[39m [1mdist/index.js.map [22m[32m16.39 KB[39m
|
|
18
|
-
[32mCJS[39m ⚡️ Build success in 96ms
|
|
19
|
-
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in 15023ms
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m4.81 KB[39m
|
|
22
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m4.81 KB[39m
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import { describe, it, expect } from 'vitest';
|
|
4
|
-
import { LiteKernel } from '@objectstack/core';
|
|
5
|
-
import { AutomationServicePlugin, type AutomationEngine } from '@objectstack/service-automation';
|
|
6
|
-
import { ConnectorSlackPlugin } from './connector-slack-plugin.js';
|
|
7
|
-
|
|
8
|
-
/** A fetch stub mimicking the Slack Web API (HTTP 200 + ok in the body). */
|
|
9
|
-
function stubSlack() {
|
|
10
|
-
const calls: Array<{ url: string; init: RequestInit }> = [];
|
|
11
|
-
const impl = (async (url: string, init: RequestInit) => {
|
|
12
|
-
calls.push({ url, init });
|
|
13
|
-
return {
|
|
14
|
-
status: 200,
|
|
15
|
-
ok: true,
|
|
16
|
-
headers: { get: () => 'application/json' },
|
|
17
|
-
json: async () => ({ ok: true, ts: '1700000000.000200', channel: 'C42' }),
|
|
18
|
-
text: async () => '{"ok":true}',
|
|
19
|
-
};
|
|
20
|
-
}) as unknown as typeof fetch;
|
|
21
|
-
return { impl, calls };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
describe('ConnectorSlackPlugin — end to end with the automation engine', () => {
|
|
25
|
-
it('registers the Slack connector so a connector_action flow can post a message', async () => {
|
|
26
|
-
const { impl, calls } = stubSlack();
|
|
27
|
-
|
|
28
|
-
const kernel = new LiteKernel();
|
|
29
|
-
kernel.use(new AutomationServicePlugin());
|
|
30
|
-
kernel.use(new ConnectorSlackPlugin({ token: 'xoxb-secret-token', fetchImpl: impl }));
|
|
31
|
-
await kernel.bootstrap();
|
|
32
|
-
|
|
33
|
-
const engine = kernel.getService<AutomationEngine>('automation');
|
|
34
|
-
|
|
35
|
-
// The baseline dispatch node and the plugin-contributed connector are both present.
|
|
36
|
-
expect(engine.getRegisteredNodeTypes()).toContain('connector_action');
|
|
37
|
-
expect(engine.getRegisteredConnectors()).toContain('slack');
|
|
38
|
-
|
|
39
|
-
engine.registerFlow('notify_channel', {
|
|
40
|
-
name: 'notify_channel',
|
|
41
|
-
label: 'Post to Slack',
|
|
42
|
-
type: 'autolaunched',
|
|
43
|
-
variables: [{ name: 'post.ok', type: 'boolean', isOutput: true }],
|
|
44
|
-
nodes: [
|
|
45
|
-
{ id: 'start', type: 'start', label: 'Start' },
|
|
46
|
-
{
|
|
47
|
-
id: 'post',
|
|
48
|
-
type: 'connector_action',
|
|
49
|
-
label: 'Post to #sales',
|
|
50
|
-
connectorConfig: {
|
|
51
|
-
connectorId: 'slack',
|
|
52
|
-
actionId: 'chat.postMessage',
|
|
53
|
-
input: { channel: 'C42', text: 'Deal closed 🎉' },
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
{ id: 'end', type: 'end', label: 'End' },
|
|
57
|
-
],
|
|
58
|
-
edges: [
|
|
59
|
-
{ id: 'e1', source: 'start', target: 'post' },
|
|
60
|
-
{ id: 'e2', source: 'post', target: 'end' },
|
|
61
|
-
],
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const result = await engine.execute('notify_channel');
|
|
65
|
-
|
|
66
|
-
expect(result.success).toBe(true);
|
|
67
|
-
// The Slack connector handled the dispatch: one POST with bearer auth + JSON body.
|
|
68
|
-
expect(calls).toHaveLength(1);
|
|
69
|
-
expect(calls[0].url).toBe('https://slack.com/api/chat.postMessage');
|
|
70
|
-
expect(calls[0].init.method).toBe('POST');
|
|
71
|
-
expect((calls[0].init.headers as Record<string, string>).Authorization).toBe('Bearer xoxb-secret-token');
|
|
72
|
-
expect(calls[0].init.body).toBe('{"channel":"C42","text":"Deal closed 🎉"}');
|
|
73
|
-
// Slack's logical `ok` propagated back into the flow output.
|
|
74
|
-
expect(result.output).toEqual({ 'post.ok': true });
|
|
75
|
-
|
|
76
|
-
await kernel.shutdown();
|
|
77
|
-
});
|
|
78
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import type { Plugin, PluginContext } from '@objectstack/core';
|
|
4
|
-
import type { Connector } from '@objectstack/spec/integration';
|
|
5
|
-
import { createSlackConnector, type SlackConnectorOptions } from './slack-connector.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Minimal surface of the automation engine this plugin depends on — the
|
|
9
|
-
* connector registry from ADR-0018 §Addendum. Kept structural so the plugin
|
|
10
|
-
* needs no runtime dependency on `@objectstack/service-automation`.
|
|
11
|
-
*/
|
|
12
|
-
export interface ConnectorRegistrySurface {
|
|
13
|
-
registerConnector(
|
|
14
|
-
def: Connector,
|
|
15
|
-
handlers: Record<
|
|
16
|
-
string,
|
|
17
|
-
(input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>
|
|
18
|
-
>,
|
|
19
|
-
): void;
|
|
20
|
-
unregisterConnector(name: string): void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface ConnectorSlackPluginOptions extends SlackConnectorOptions {}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* ConnectorSlackPlugin — registers a Slack Web API connector on the automation
|
|
27
|
-
* engine. The second reference concrete connector (ADR-0018 §Addendum); it
|
|
28
|
-
* enables the ADR-0022 "raw API call" path — a flow's `connector_action` step
|
|
29
|
-
* can dispatch to `slack.chat.postMessage` without the messaging stack.
|
|
30
|
-
*
|
|
31
|
-
* If no automation engine is present the plugin logs and skips — the connector
|
|
32
|
-
* has nowhere to register, which is not an error.
|
|
33
|
-
*/
|
|
34
|
-
export class ConnectorSlackPlugin implements Plugin {
|
|
35
|
-
name = 'com.objectstack.connector.slack';
|
|
36
|
-
version = '1.0.0';
|
|
37
|
-
type = 'standard' as const;
|
|
38
|
-
// Ensure the automation engine (and its connector registry) is started first.
|
|
39
|
-
dependencies = ['com.objectstack.service-automation'];
|
|
40
|
-
|
|
41
|
-
private readonly options: ConnectorSlackPluginOptions;
|
|
42
|
-
private connectorName?: string;
|
|
43
|
-
private automation?: ConnectorRegistrySurface;
|
|
44
|
-
|
|
45
|
-
constructor(options: ConnectorSlackPluginOptions) {
|
|
46
|
-
this.options = options;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async init(_ctx: PluginContext): Promise<void> {
|
|
50
|
-
// No services to register; the connector is registered in start() once
|
|
51
|
-
// the automation engine is available.
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async start(ctx: PluginContext): Promise<void> {
|
|
55
|
-
let automation: ConnectorRegistrySurface | undefined;
|
|
56
|
-
try {
|
|
57
|
-
automation = ctx.getService<ConnectorRegistrySurface>('automation');
|
|
58
|
-
} catch {
|
|
59
|
-
automation = undefined;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (!automation || typeof automation.registerConnector !== 'function') {
|
|
63
|
-
ctx.logger.info('ConnectorSlackPlugin: no automation engine — Slack connector not registered');
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const { def, handlers } = createSlackConnector(this.options);
|
|
68
|
-
automation.registerConnector(def, handlers);
|
|
69
|
-
this.automation = automation;
|
|
70
|
-
this.connectorName = def.name;
|
|
71
|
-
ctx.logger.info(`ConnectorSlackPlugin: Slack connector '${def.name}' registered`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async stop(_ctx: PluginContext): Promise<void> {
|
|
75
|
-
if (this.automation && this.connectorName) {
|
|
76
|
-
try { this.automation.unregisterConnector(this.connectorName); } catch { /* ignore */ }
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @objectstack/connector-slack
|
|
5
|
-
*
|
|
6
|
-
* Slack Web API connector — a concrete connector (ADR-0018 §Addendum) and the
|
|
7
|
-
* second reference implementation after `@objectstack/connector-rest`. The
|
|
8
|
-
* baseline automation engine ships the `connector_action` dispatch node + an
|
|
9
|
-
* empty connector registry; this plugin populates it with a `slack` connector
|
|
10
|
-
* exposing `chat.postMessage`, `chat.update`, and a generic `call` action.
|
|
11
|
-
*
|
|
12
|
-
* This is the integration mechanism (ADR-0022 "raw API call" path), not the
|
|
13
|
-
* human-notification layer. Static bot-token auth only; OAuth2 install/refresh,
|
|
14
|
-
* credential vaulting, and multi-tenant lifecycle are the enterprise tier.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
export {
|
|
18
|
-
createSlackConnector,
|
|
19
|
-
type SlackConnectorOptions,
|
|
20
|
-
type SlackConnectorBundle,
|
|
21
|
-
type SlackPostMessageInput,
|
|
22
|
-
type SlackResult,
|
|
23
|
-
} from './slack-connector.js';
|
|
24
|
-
export {
|
|
25
|
-
ConnectorSlackPlugin,
|
|
26
|
-
type ConnectorSlackPluginOptions,
|
|
27
|
-
type ConnectorRegistrySurface,
|
|
28
|
-
} from './connector-slack-plugin.js';
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import { describe, it, expect } from 'vitest';
|
|
4
|
-
import { createSlackConnector } from './slack-connector.js';
|
|
5
|
-
|
|
6
|
-
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
7
|
-
|
|
8
|
-
interface CapturedCall {
|
|
9
|
-
url: string;
|
|
10
|
-
init: RequestInit;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* A fetch stub mimicking the Slack Web API: always HTTP 200, with the logical
|
|
15
|
-
* outcome carried in the JSON body's `ok` field.
|
|
16
|
-
*/
|
|
17
|
-
function stubSlack(responseBody: Record<string, unknown> = { ok: true }) {
|
|
18
|
-
const calls: CapturedCall[] = [];
|
|
19
|
-
const impl = (async (url: string, init: RequestInit) => {
|
|
20
|
-
calls.push({ url, init });
|
|
21
|
-
return {
|
|
22
|
-
status: 200,
|
|
23
|
-
ok: true,
|
|
24
|
-
headers: { get: () => 'application/json' },
|
|
25
|
-
json: async () => responseBody,
|
|
26
|
-
text: async () => JSON.stringify(responseBody),
|
|
27
|
-
};
|
|
28
|
-
}) as unknown as typeof fetch;
|
|
29
|
-
return { impl, calls };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function headersOf(call: CapturedCall): Record<string, string> {
|
|
33
|
-
return (call.init.headers ?? {}) as Record<string, string>;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ─── definition ──────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
describe('createSlackConnector — definition', () => {
|
|
39
|
-
it('declares a slack connector with the expected actions and bearer auth', () => {
|
|
40
|
-
const { def, handlers } = createSlackConnector({ token: 'xoxb-1' });
|
|
41
|
-
|
|
42
|
-
expect(def.name).toBe('slack');
|
|
43
|
-
expect(def.type).toBe('api');
|
|
44
|
-
expect(def.authentication).toEqual({ type: 'bearer', token: 'xoxb-1' });
|
|
45
|
-
|
|
46
|
-
const keys = (def.actions ?? []).map((a) => a.key);
|
|
47
|
-
expect(keys).toEqual(['chat.postMessage', 'chat.update', 'call']);
|
|
48
|
-
// Every declared action has a handler (the registry enforces this too).
|
|
49
|
-
for (const k of keys) expect(typeof handlers[k]).toBe('function');
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// ─── chat.postMessage ────────────────────────────────────────────────
|
|
54
|
-
|
|
55
|
-
describe('createSlackConnector — chat.postMessage', () => {
|
|
56
|
-
it('POSTs JSON to the method URL with a bearer token and returns ok from the payload', async () => {
|
|
57
|
-
const { impl, calls } = stubSlack({ ok: true, ts: '1700000000.000100', channel: 'C123' });
|
|
58
|
-
const { handlers } = createSlackConnector({ token: 'xoxb-secret', fetchImpl: impl });
|
|
59
|
-
|
|
60
|
-
const out = await handlers['chat.postMessage'](
|
|
61
|
-
{ channel: 'C123', text: 'hello', thread_ts: '1699999999.0001' },
|
|
62
|
-
{},
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
expect(calls).toHaveLength(1);
|
|
66
|
-
expect(calls[0].url).toBe('https://slack.com/api/chat.postMessage');
|
|
67
|
-
expect(calls[0].init.method).toBe('POST');
|
|
68
|
-
expect(headersOf(calls[0]).Authorization).toBe('Bearer xoxb-secret');
|
|
69
|
-
expect(calls[0].init.body).toBe('{"channel":"C123","text":"hello","thread_ts":"1699999999.0001"}');
|
|
70
|
-
|
|
71
|
-
expect(out.ok).toBe(true);
|
|
72
|
-
expect(out.status).toBe(200);
|
|
73
|
-
expect(out.body).toEqual({ ok: true, ts: '1700000000.000100', channel: 'C123' });
|
|
74
|
-
expect(out.error).toBeUndefined();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('surfaces a Slack logical failure (HTTP 200, ok:false) without throwing', async () => {
|
|
78
|
-
const { impl } = stubSlack({ ok: false, error: 'channel_not_found' });
|
|
79
|
-
const { handlers } = createSlackConnector({ token: 'xoxb-1', fetchImpl: impl });
|
|
80
|
-
|
|
81
|
-
const out = await handlers['chat.postMessage']({ channel: 'nope', text: 'hi' }, {});
|
|
82
|
-
|
|
83
|
-
expect(out.ok).toBe(false);
|
|
84
|
-
expect(out.error).toBe('channel_not_found');
|
|
85
|
-
expect(out.status).toBe(200);
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// ─── chat.update + call ───────────────────────────────────────────────
|
|
90
|
-
|
|
91
|
-
describe('createSlackConnector — chat.update & generic call', () => {
|
|
92
|
-
it('chat.update hits the chat.update method', async () => {
|
|
93
|
-
const { impl, calls } = stubSlack({ ok: true });
|
|
94
|
-
const { handlers } = createSlackConnector({ token: 'xoxb-1', fetchImpl: impl });
|
|
95
|
-
|
|
96
|
-
await handlers['chat.update']({ channel: 'C1', ts: '170.1', text: 'edited' }, {});
|
|
97
|
-
expect(calls[0].url).toBe('https://slack.com/api/chat.update');
|
|
98
|
-
expect(calls[0].init.body).toBe('{"channel":"C1","ts":"170.1","text":"edited"}');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('call dispatches to an arbitrary Web API method with params', async () => {
|
|
102
|
-
const { impl, calls } = stubSlack({ ok: true, channels: [] });
|
|
103
|
-
const { handlers } = createSlackConnector({ token: 'xoxb-1', fetchImpl: impl });
|
|
104
|
-
|
|
105
|
-
const out = await handlers.call({ method: 'conversations.list', params: { limit: 50 } }, {});
|
|
106
|
-
expect(calls[0].url).toBe('https://slack.com/api/conversations.list');
|
|
107
|
-
expect(calls[0].init.body).toBe('{"limit":50}');
|
|
108
|
-
expect(out.ok).toBe(true);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('call throws when method is missing', async () => {
|
|
112
|
-
const { impl } = stubSlack();
|
|
113
|
-
const { handlers } = createSlackConnector({ token: 'xoxb-1', fetchImpl: impl });
|
|
114
|
-
await expect(handlers.call({ params: {} }, {})).rejects.toThrow(/method.*required/);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('honours a custom baseUrl and merges defaultHeaders', async () => {
|
|
118
|
-
const { impl, calls } = stubSlack();
|
|
119
|
-
const { handlers } = createSlackConnector({
|
|
120
|
-
token: 'xoxb-1',
|
|
121
|
-
baseUrl: 'https://slack.example.test/api/',
|
|
122
|
-
defaultHeaders: { 'X-Trace': 'on' },
|
|
123
|
-
fetchImpl: impl,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
await handlers['chat.postMessage']({ channel: 'C1', text: 'x' }, {});
|
|
127
|
-
expect(calls[0].url).toBe('https://slack.example.test/api/chat.postMessage');
|
|
128
|
-
expect(headersOf(calls[0])['X-Trace']).toBe('on');
|
|
129
|
-
// Auth still wins over defaultHeaders.
|
|
130
|
-
expect(headersOf(calls[0]).Authorization).toBe('Bearer xoxb-1');
|
|
131
|
-
});
|
|
132
|
-
});
|
package/src/slack-connector.ts
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
import type { Connector } from '@objectstack/spec/integration';
|
|
4
|
-
import { resilientFetch } from '@objectstack/spec/shared';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Slack connector — a *concrete* connector (ADR-0018 §Addendum) and the second
|
|
8
|
-
* reference implementation after `@objectstack/connector-rest`. It produces a
|
|
9
|
-
* {@link Connector} definition plus handlers for a small set of Slack Web API
|
|
10
|
-
* actions, which the baseline `connector_action` node dispatches to.
|
|
11
|
-
*
|
|
12
|
-
* Scope (ADR-0022 "raw API call" path): this is the *integration mechanism*
|
|
13
|
-
* for talking to Slack's API — "post this exact text to this channel". It is
|
|
14
|
-
* deliberately **not** the human-notification layer: there is no preference
|
|
15
|
-
* matrix, inbox, outbox, or thread/session semantics here. Those belong to a
|
|
16
|
-
* `MessagingChannel` (ADR-0012/0013), which may itself delegate its transport
|
|
17
|
-
* to this connector.
|
|
18
|
-
*
|
|
19
|
-
* Open-source scope: **static** auth only — a Slack **bot token** (`xoxb-…`),
|
|
20
|
-
* supplied by the caller and sent as a bearer credential. OAuth2 install/refresh,
|
|
21
|
-
* credential vaulting, and multi-tenant connection lifecycle are the enterprise
|
|
22
|
-
* tier (see `../cloud/docs/design/connector-tiering.md`) and are out of scope.
|
|
23
|
-
*
|
|
24
|
-
* Slack quirk: the Web API returns HTTP `200` even on logical failure, with the
|
|
25
|
-
* real outcome in the JSON body's `ok` field (and `error` on failure). Handlers
|
|
26
|
-
* therefore surface `ok` from the payload, not from the HTTP status, and never
|
|
27
|
-
* throw on a logical failure — the flow author branches on `${node.ok}`.
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
export interface SlackConnectorOptions {
|
|
31
|
-
/** Connector machine name (snake_case). Defaults to `slack`. */
|
|
32
|
-
name?: string;
|
|
33
|
-
/** Human-readable label. Defaults to `Slack`. */
|
|
34
|
-
label?: string;
|
|
35
|
-
/** Slack bot token (`xoxb-…`), sent as `Authorization: Bearer <token>`. */
|
|
36
|
-
token: string;
|
|
37
|
-
/** Web API base URL. Defaults to `https://slack.com/api`. */
|
|
38
|
-
baseUrl?: string;
|
|
39
|
-
/** Headers merged into every request (request-level headers win). */
|
|
40
|
-
defaultHeaders?: Record<string, string>;
|
|
41
|
-
/** Injected for tests; defaults to the global `fetch`. */
|
|
42
|
-
fetchImpl?: typeof fetch;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Input accepted by `chat.postMessage`. */
|
|
46
|
-
export interface SlackPostMessageInput {
|
|
47
|
-
/** Channel id (`C…`), user id (`U…`), or channel name (`#general`). */
|
|
48
|
-
channel: string;
|
|
49
|
-
/** Message text (fallback when `blocks` are present). */
|
|
50
|
-
text?: string;
|
|
51
|
-
/** Thread root `ts` to reply into an existing thread. */
|
|
52
|
-
thread_ts?: string;
|
|
53
|
-
/** Block Kit blocks. */
|
|
54
|
-
blocks?: unknown[];
|
|
55
|
-
[key: string]: unknown;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Generic Slack Web API result envelope. */
|
|
59
|
-
export interface SlackResult {
|
|
60
|
-
/** Slack's logical success flag (from the JSON body, not the HTTP status). */
|
|
61
|
-
ok: boolean;
|
|
62
|
-
/** HTTP status (almost always 200 for the Slack Web API). */
|
|
63
|
-
status: number;
|
|
64
|
-
/** Full parsed Slack payload. */
|
|
65
|
-
body: Record<string, unknown>;
|
|
66
|
-
/** Slack error code when `ok` is false (e.g. `channel_not_found`). */
|
|
67
|
-
error?: string;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** A connector definition paired with its action handlers, ready for registerConnector(). */
|
|
71
|
-
export interface SlackConnectorBundle {
|
|
72
|
-
def: Connector;
|
|
73
|
-
handlers: Record<
|
|
74
|
-
string,
|
|
75
|
-
(input: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>
|
|
76
|
-
>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function createSlackConnector(opts: SlackConnectorOptions): SlackConnectorBundle {
|
|
80
|
-
const name = opts.name ?? 'slack';
|
|
81
|
-
const baseUrl = (opts.baseUrl ?? 'https://slack.com/api').replace(/\/+$/, '');
|
|
82
|
-
|
|
83
|
-
const def: Connector = {
|
|
84
|
-
name,
|
|
85
|
-
label: opts.label ?? 'Slack',
|
|
86
|
-
type: 'api',
|
|
87
|
-
description: 'Slack Web API connector (static bot-token auth). Post and update messages, or call any Web API method.',
|
|
88
|
-
icon: 'slack',
|
|
89
|
-
authentication: { type: 'bearer', token: opts.token },
|
|
90
|
-
// Defaulted by ConnectorSchema; set explicitly so the literal satisfies
|
|
91
|
-
// the (post-parse) Connector output type.
|
|
92
|
-
status: 'active',
|
|
93
|
-
enabled: true,
|
|
94
|
-
connectionTimeoutMs: 30000,
|
|
95
|
-
requestTimeoutMs: 30000,
|
|
96
|
-
actions: [
|
|
97
|
-
{
|
|
98
|
-
key: 'chat.postMessage',
|
|
99
|
-
label: 'Post Message',
|
|
100
|
-
description: 'Post a message to a channel, DM, or thread (Slack chat.postMessage).',
|
|
101
|
-
inputSchema: {
|
|
102
|
-
type: 'object',
|
|
103
|
-
required: ['channel'],
|
|
104
|
-
properties: {
|
|
105
|
-
channel: { type: 'string', description: 'Channel id, user id, or #name' },
|
|
106
|
-
text: { type: 'string', description: 'Message text' },
|
|
107
|
-
thread_ts: { type: 'string', description: 'Thread root ts to reply into' },
|
|
108
|
-
blocks: { type: 'array', description: 'Block Kit blocks' },
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
outputSchema: slackOutputSchema(),
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
key: 'chat.update',
|
|
115
|
-
label: 'Update Message',
|
|
116
|
-
description: 'Edit an existing message (Slack chat.update).',
|
|
117
|
-
inputSchema: {
|
|
118
|
-
type: 'object',
|
|
119
|
-
required: ['channel', 'ts'],
|
|
120
|
-
properties: {
|
|
121
|
-
channel: { type: 'string', description: 'Channel id' },
|
|
122
|
-
ts: { type: 'string', description: 'Timestamp of the message to update' },
|
|
123
|
-
text: { type: 'string', description: 'New message text' },
|
|
124
|
-
blocks: { type: 'array', description: 'New Block Kit blocks' },
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
outputSchema: slackOutputSchema(),
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
key: 'call',
|
|
131
|
-
label: 'Call Web API Method',
|
|
132
|
-
description: 'Escape hatch — call any Slack Web API method with arbitrary params.',
|
|
133
|
-
inputSchema: {
|
|
134
|
-
type: 'object',
|
|
135
|
-
required: ['method'],
|
|
136
|
-
properties: {
|
|
137
|
-
method: { type: 'string', description: 'Web API method, e.g. conversations.list' },
|
|
138
|
-
params: { type: 'object', description: 'Method parameters (JSON body)' },
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
outputSchema: slackOutputSchema(),
|
|
142
|
-
},
|
|
143
|
-
],
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
/** POST a JSON body to a Slack Web API method and normalise the result. */
|
|
147
|
-
async function callSlack(method: string, params: Record<string, unknown>): Promise<SlackResult> {
|
|
148
|
-
const headers: Record<string, string> = {
|
|
149
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
150
|
-
...opts.defaultHeaders,
|
|
151
|
-
Authorization: `Bearer ${opts.token}`,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const response = await resilientFetch(`${baseUrl}/${method}`, {
|
|
155
|
-
method: 'POST',
|
|
156
|
-
headers,
|
|
157
|
-
body: JSON.stringify(params),
|
|
158
|
-
}, { fetchImpl: opts.fetchImpl });
|
|
159
|
-
|
|
160
|
-
// The Slack Web API always answers with JSON; `ok` is the real outcome.
|
|
161
|
-
const body = (await response.json()) as Record<string, unknown>;
|
|
162
|
-
const ok = body.ok === true;
|
|
163
|
-
return {
|
|
164
|
-
ok,
|
|
165
|
-
status: response.status,
|
|
166
|
-
body,
|
|
167
|
-
error: ok ? undefined : (body.error as string | undefined),
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async function postMessage(input: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
172
|
-
return toRecord(await callSlack('chat.postMessage', input));
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async function update(input: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
176
|
-
return toRecord(await callSlack('chat.update', input));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async function call(input: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
180
|
-
const method = String(input.method ?? '');
|
|
181
|
-
if (!method) throw new Error("slack 'call' action: 'method' is required");
|
|
182
|
-
const params = (input.params as Record<string, unknown>) ?? {};
|
|
183
|
-
return toRecord(await callSlack(method, params));
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
def,
|
|
188
|
-
handlers: {
|
|
189
|
-
'chat.postMessage': postMessage,
|
|
190
|
-
'chat.update': update,
|
|
191
|
-
call,
|
|
192
|
-
},
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function toRecord(r: SlackResult): Record<string, unknown> {
|
|
197
|
-
return { ok: r.ok, status: r.status, body: r.body, error: r.error };
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function slackOutputSchema(): Record<string, unknown> {
|
|
201
|
-
return {
|
|
202
|
-
type: 'object',
|
|
203
|
-
properties: {
|
|
204
|
-
ok: { type: 'boolean', description: "Slack's logical success flag" },
|
|
205
|
-
status: { type: 'number', description: 'HTTP status' },
|
|
206
|
-
body: { type: 'object', description: 'Full Slack response payload' },
|
|
207
|
-
error: { type: 'string', description: 'Slack error code when ok is false' },
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
}
|