@cuylabs/channel-slack 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +25 -136
  2. package/dist/app-home.d.ts +23 -0
  3. package/dist/app-home.js +40 -0
  4. package/dist/artifacts/index.d.ts +135 -0
  5. package/dist/artifacts/index.js +299 -0
  6. package/dist/{assistant.d.ts → assistant/index.d.ts} +1 -1
  7. package/dist/{assistant.js → assistant/index.js} +2 -2
  8. package/dist/auth/index.d.ts +56 -0
  9. package/dist/auth/index.js +168 -0
  10. package/dist/{chunk-IDVDMJ5U.js → chunk-6JSGIVQH.js} +110 -3
  11. package/dist/chunk-6WHFQUYQ.js +54 -0
  12. package/dist/{bolt.js → chunk-73QXT7MA.js} +25 -320
  13. package/dist/{chunk-CMR6B76C.js → chunk-DNVSH7H5.js} +407 -1
  14. package/dist/chunk-IRFKUPJN.js +235 -0
  15. package/dist/chunk-QJYCHWN6.js +76 -0
  16. package/dist/chunk-S3SWPYXJ.js +81 -0
  17. package/dist/{chunk-JZG4IETE.js → chunk-X4WBBBYM.js} +0 -52
  18. package/dist/core.js +5 -3
  19. package/dist/diagnostics/index.d.ts +71 -0
  20. package/dist/{diagnostics.js → diagnostics/index.js} +5 -1
  21. package/dist/entrypoints/index.d.ts +120 -0
  22. package/dist/entrypoints/index.js +132 -0
  23. package/dist/{feedback.js → feedback/index.js} +5 -7
  24. package/dist/{history.d.ts → history/index.d.ts} +2 -2
  25. package/dist/{history.js → history/index.js} +1 -1
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.js +28 -15
  28. package/dist/{policy.d.ts → policy/index.d.ts} +103 -2
  29. package/dist/{policy.js → policy/index.js} +13 -1
  30. package/dist/runtime-BNBHOZSQ.d.ts +53 -0
  31. package/dist/{setup.d.ts → setup/index.d.ts} +30 -3
  32. package/dist/{setup.js → setup/index.js} +137 -3
  33. package/dist/transports/http/index.d.ts +68 -0
  34. package/dist/transports/http/index.js +8 -0
  35. package/dist/transports/index.d.ts +8 -0
  36. package/dist/transports/index.js +24 -0
  37. package/dist/transports/socket/index.d.ts +94 -0
  38. package/dist/transports/socket/index.js +19 -0
  39. package/dist/types-B9NfCVrk.d.ts +141 -0
  40. package/dist/views/index.d.ts +98 -0
  41. package/dist/views/index.js +22 -0
  42. package/docs/README.md +32 -0
  43. package/docs/concepts/activity.md +3 -3
  44. package/docs/concepts/artifacts.md +56 -0
  45. package/docs/concepts/entrypoints.md +73 -0
  46. package/docs/concepts/setup-requirements.md +23 -0
  47. package/docs/concepts/{bolt-runtime.md → transport-runtime.md} +9 -4
  48. package/docs/concepts/views.md +46 -0
  49. package/docs/recipes/generate-slack-manifest.md +16 -0
  50. package/docs/recipes/publish-artifact.md +45 -0
  51. package/docs/recipes/slash-command-and-shortcut.md +51 -0
  52. package/docs/recipes/socket-mode-app.md +1 -1
  53. package/docs/reference/channel-slack-boundary.md +10 -6
  54. package/docs/reference/exports.md +18 -12
  55. package/docs/reference/source-layout.md +36 -0
  56. package/package.json +68 -39
  57. package/dist/bolt.d.ts +0 -364
  58. package/dist/chunk-NE57BLLU.js +0 -0
  59. package/dist/diagnostics.d.ts +0 -22
  60. package/dist/shared.d.ts +0 -2
  61. package/dist/shared.js +0 -43
  62. /package/dist/{feedback.d.ts → feedback/index.d.ts} +0 -0
  63. /package/dist/{targets.d.ts → targets/index.d.ts} +0 -0
  64. /package/dist/{targets.js → targets/index.js} +0 -0
  65. /package/dist/{users.d.ts → users/index.d.ts} +0 -0
  66. /package/dist/{users.js → users/index.js} +0 -0
@@ -1,147 +1,9 @@
1
- // src/bolt/auth.ts
2
- function resolveDirectAuth(options) {
3
- const provided = options.auth;
4
- if (!provided || provided.mode === void 0 || provided.mode === "single-workspace") {
5
- const singleWorkspace = provided;
6
- const botToken = firstNonEmptyString(
7
- singleWorkspace?.botToken,
8
- options.botToken,
9
- process.env.SLACK_BOT_TOKEN
10
- );
11
- if (!botToken) {
12
- throw new Error(
13
- 'Slack bot token is required for single-workspace mode. Pass `botToken`, use `auth: { mode: "oauth", ... }`, or use `auth: { mode: "authorize", ... }`.'
14
- );
15
- }
16
- return {
17
- mode: "single-workspace",
18
- botToken,
19
- botId: singleWorkspace?.botId,
20
- botUserId: singleWorkspace?.botUserId
21
- };
22
- }
23
- if (provided.mode === "authorize") {
24
- return provided;
25
- }
26
- const oauth = provided;
27
- const clientId = firstNonEmptyString(
28
- oauth.clientId,
29
- process.env.SLACK_CLIENT_ID
30
- );
31
- const clientSecret = firstNonEmptyString(
32
- oauth.clientSecret,
33
- process.env.SLACK_CLIENT_SECRET
34
- );
35
- if (!clientId || !clientSecret) {
36
- throw new Error(
37
- "Slack OAuth mode requires `clientId` and `clientSecret` or SLACK_CLIENT_ID / SLACK_CLIENT_SECRET."
38
- );
39
- }
40
- if (oauth.stateVerification !== false && !trimToUndefined(oauth.stateSecret) && !oauth.stateStore && !trimToUndefined(process.env.SLACK_STATE_SECRET)) {
41
- throw new Error(
42
- "Slack OAuth mode requires `stateSecret` or a custom `stateStore` when state verification is enabled."
43
- );
44
- }
45
- return {
46
- ...oauth,
47
- mode: "oauth",
48
- clientId,
49
- clientSecret,
50
- stateSecret: firstNonEmptyString(
51
- oauth.stateSecret,
52
- process.env.SLACK_STATE_SECRET
53
- )
54
- };
55
- }
56
- function normalizeSlackEventsPath(path2) {
57
- const trimmed = path2.trim();
58
- if (!trimmed) {
59
- throw new Error("Slack events path must not be empty.");
60
- }
61
- return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
62
- }
63
- function trimToUndefined(value) {
64
- const trimmed = value?.trim();
65
- return trimmed || void 0;
66
- }
67
- function firstNonEmptyString(...values) {
68
- for (const value of values) {
69
- const trimmed = trimToUndefined(value);
70
- if (trimmed) {
71
- return trimmed;
72
- }
73
- }
74
- return void 0;
75
- }
1
+ import {
2
+ resolveDirectAuth,
3
+ trimToUndefined
4
+ } from "./chunk-S3SWPYXJ.js";
76
5
 
77
- // src/bolt/app.ts
78
- async function createSlackBoltApp(options = {}) {
79
- const boltModule = await import("@slack/bolt");
80
- const routePath = normalizeSlackEventsPath(options.path ?? "/slack/events");
81
- const signingSecret = trimToUndefined(
82
- options.signingSecret ?? process.env.SLACK_SIGNING_SECRET
83
- );
84
- if (!signingSecret) {
85
- throw new Error(
86
- "Slack signing secret is required. Pass `signingSecret` or set SLACK_SIGNING_SECRET."
87
- );
88
- }
89
- const auth = resolveDirectAuth(options);
90
- const receiver = new boltModule.ExpressReceiver({
91
- ...options.receiverOptions,
92
- signingSecret,
93
- endpoints: routePath,
94
- processBeforeResponse: options.processBeforeResponse,
95
- signatureVerification: options.signatureVerification,
96
- // Bolt is typed against Express 4 while this repo uses Express 5 types.
97
- // The runtime contract is compatible; keep the cast localized here.
98
- app: options.app,
99
- ...auth.mode === "oauth" ? {
100
- clientId: auth.clientId,
101
- clientSecret: auth.clientSecret,
102
- stateSecret: auth.stateSecret,
103
- installationStore: auth.installationStore,
104
- redirectUri: auth.redirectUri,
105
- scopes: auth.scopes,
106
- installerOptions: {
107
- stateStore: auth.stateStore,
108
- stateVerification: auth.stateVerification,
109
- legacyStateVerification: auth.legacyStateVerification,
110
- stateCookieName: auth.stateCookieName,
111
- stateCookieExpirationSeconds: auth.stateCookieExpirationSeconds,
112
- metadata: auth.metadata,
113
- userScopes: auth.userScopes,
114
- installPath: auth.installPath,
115
- redirectUriPath: auth.callbackPath,
116
- renderHtmlForInstallPath: auth.renderHtmlForInstallPath,
117
- installPathOptions: auth.installPathOptions,
118
- callbackOptions: auth.callbackOptions,
119
- directInstall: auth.directInstall,
120
- authVersion: auth.authVersion,
121
- authorizationUrl: auth.authorizationUrl
122
- }
123
- } : {}
124
- });
125
- const boltApp = new boltModule.App({
126
- ...options.boltAppOptions,
127
- receiver,
128
- ...auth.mode === "single-workspace" ? {
129
- token: auth.botToken,
130
- botId: auth.botId,
131
- botUserId: auth.botUserId
132
- } : {},
133
- ...auth.mode === "authorize" ? { authorize: auth.authorize } : {}
134
- });
135
- return {
136
- boltApp,
137
- receiver,
138
- app: options.app ?? receiver.app,
139
- authMode: auth.mode,
140
- routePath
141
- };
142
- }
143
-
144
- // src/bolt/socket-app.ts
6
+ // src/transports/socket/bolt-app.ts
145
7
  async function createSlackSocketBoltApp(options = {}) {
146
8
  const appToken = trimToUndefined(
147
9
  options.appToken ?? process.env.SLACK_APP_TOKEN
@@ -206,11 +68,12 @@ async function createSlackSocketBoltApp(options = {}) {
206
68
  return { boltApp, authMode: auth.mode };
207
69
  }
208
70
 
209
- // src/bolt/socket-lock.ts
71
+ // src/transports/socket/process-lock.ts
210
72
  import crypto from "crypto";
211
73
  import fs from "fs";
212
74
  import os from "os";
213
75
  import path from "path";
76
+ var REDACTED_LOCK_PATH = "[redacted]";
214
77
  function acquireSlackSocketModeProcessLock({
215
78
  appSlug,
216
79
  appToken,
@@ -250,7 +113,7 @@ function createLockFile({
250
113
  fd = tryOpenLockFile({ lockPath, logger });
251
114
  }
252
115
  if (fd === void 0) {
253
- throw new Error(`Unable to acquire Slack Socket Mode lock at ${lockPath}`);
116
+ throw new Error("Unable to acquire Slack Socket Mode lock");
254
117
  }
255
118
  const record = {
256
119
  appSlug,
@@ -262,7 +125,7 @@ function createLockFile({
262
125
  fs.writeFileSync(fd, `${JSON.stringify(record, null, 2)}
263
126
  `);
264
127
  logger?.info?.("Slack Socket Mode process lock acquired", {
265
- lockPath,
128
+ lockPath: REDACTED_LOCK_PATH,
266
129
  pid: record.pid
267
130
  });
268
131
  let released = false;
@@ -293,7 +156,7 @@ function tryOpenLockFile({
293
156
  return void 0;
294
157
  }
295
158
  logger?.error("Failed to create Slack Socket Mode process lock", {
296
- lockPath,
159
+ lockPath: REDACTED_LOCK_PATH,
297
160
  error: formatLockError(error)
298
161
  });
299
162
  throw error;
@@ -306,11 +169,11 @@ function removeStaleLockOrThrow({
306
169
  const record = readLockRecord(lockPath);
307
170
  if (record?.pid && isProcessAlive(record.pid)) {
308
171
  throw new Error(
309
- `Another Slack Socket Mode process appears to be active (pid=${record.pid}, lock=${lockPath})`
172
+ `Another Slack Socket Mode process appears to be active (pid=${record.pid})`
310
173
  );
311
174
  }
312
175
  logger?.warn?.("Removing stale Slack Socket Mode process lock", {
313
- lockPath,
176
+ lockPath: REDACTED_LOCK_PATH,
314
177
  previousPid: record?.pid
315
178
  });
316
179
  fs.rmSync(lockPath, { force: true });
@@ -322,7 +185,7 @@ function releaseLockFile({
322
185
  const record = readLockRecord(lockPath);
323
186
  if (record?.pid !== process.pid) {
324
187
  logger?.warn?.("Slack Socket Mode process lock not released", {
325
- lockPath,
188
+ lockPath: REDACTED_LOCK_PATH,
326
189
  reason: "lock-owned-by-another-process",
327
190
  ownerPid: record?.pid
328
191
  });
@@ -330,7 +193,7 @@ function releaseLockFile({
330
193
  }
331
194
  fs.rmSync(lockPath, { force: true });
332
195
  logger?.debug?.("Slack Socket Mode process lock released", {
333
- lockPath
196
+ lockPath: REDACTED_LOCK_PATH
334
197
  });
335
198
  }
336
199
  function readLockRecord(lockPath) {
@@ -363,9 +226,10 @@ function formatLockError(error) {
363
226
  return error instanceof Error ? error.message : String(error);
364
227
  }
365
228
 
366
- // src/bolt/postgres-socket-lock.ts
229
+ // src/transports/socket/postgres-lock.ts
367
230
  import crypto2 from "crypto";
368
231
  var DEFAULT_LOCK_NAMESPACE = "channel-slack-socket";
232
+ var REDACTED_LOCK_PATH2 = "[redacted]";
369
233
  async function acquireSlackSocketModePostgresLock({
370
234
  appSlug,
371
235
  appToken,
@@ -422,12 +286,11 @@ async function acquireSlackSocketModePostgresLock({
422
286
  activePool = void 0;
423
287
  }
424
288
  throw new Error(
425
- `Another Slack Socket Mode process appears to hold the Postgres advisory lock (${lockPath})`
289
+ "Another Slack Socket Mode process appears to hold the Postgres advisory lock"
426
290
  );
427
291
  }
428
292
  logger?.info?.("Slack Socket Mode Postgres lock acquired", {
429
- lockPath,
430
- tokenHash
293
+ lockPath: REDACTED_LOCK_PATH2
431
294
  });
432
295
  async function release() {
433
296
  if (released) {
@@ -441,11 +304,11 @@ async function acquireSlackSocketModePostgresLock({
441
304
  );
442
305
  if (releaseResult?.rows[0]?.released === false) {
443
306
  logger?.warn?.("Slack Socket Mode Postgres lock was not held", {
444
- lockPath
307
+ lockPath: REDACTED_LOCK_PATH2
445
308
  });
446
309
  }
447
310
  logger?.debug?.("Slack Socket Mode Postgres lock released", {
448
- lockPath
311
+ lockPath: REDACTED_LOCK_PATH2
449
312
  });
450
313
  } finally {
451
314
  if (activeClient !== client) {
@@ -498,7 +361,7 @@ function formatImportError(error) {
498
361
  return error instanceof Error ? error.message : String(error);
499
362
  }
500
363
 
501
- // src/bolt/socket-runtime.ts
364
+ // src/transports/socket/runtime.ts
502
365
  var DEFAULT_CLIENT_PING_TIMEOUT_MS = 3e4;
503
366
  var DEFAULT_RESTART_GUARD_MAX_WARNINGS = 3;
504
367
  var DEFAULT_RESTART_GUARD_WINDOW_MS = 6e4;
@@ -692,170 +555,12 @@ function isSensitiveKey(key) {
692
555
  return normalized.includes("token") || normalized.includes("secret") || normalized === "authorization" || normalized === "cookie";
693
556
  }
694
557
 
695
- // src/bolt/installation-store.ts
696
- import fs2 from "fs/promises";
697
- import { dirname } from "path";
698
- var InMemorySlackInstallationStore = class {
699
- devDB = {};
700
- async storeInstallation(installation) {
701
- const key = getSlackInstallationKey(installation);
702
- this.devDB[key] = installation;
703
- }
704
- async fetchInstallation(query) {
705
- const key = getSlackInstallationKey(query);
706
- const installation = this.devDB[key];
707
- if (!installation) {
708
- throw new Error(`No Slack installation found for key: ${key}`);
709
- }
710
- return installation;
711
- }
712
- async deleteInstallation(query) {
713
- const key = getSlackInstallationKey(query);
714
- delete this.devDB[key];
715
- }
716
- };
717
- function createInMemorySlackInstallationStore() {
718
- return new InMemorySlackInstallationStore();
719
- }
720
- var JsonFileSlackInstallationStore = class {
721
- constructor(filePath) {
722
- this.filePath = filePath;
723
- }
724
- filePath;
725
- pending = Promise.resolve();
726
- async storeInstallation(installation) {
727
- await this.withLock(async () => {
728
- const installations = await this.readInstallations();
729
- installations[getSlackInstallationKey(installation)] = installation;
730
- await this.writeInstallations(installations);
731
- });
732
- }
733
- async fetchInstallation(query) {
734
- return await this.withLock(async () => {
735
- const key = getSlackInstallationKey(query);
736
- const installations = await this.readInstallations();
737
- const installation = installations[key];
738
- if (!installation) {
739
- throw new Error(`No Slack installation found for key: ${key}`);
740
- }
741
- return installation;
742
- });
743
- }
744
- async deleteInstallation(query) {
745
- await this.withLock(async () => {
746
- const key = getSlackInstallationKey(query);
747
- const installations = await this.readInstallations();
748
- delete installations[key];
749
- await this.writeInstallations(installations);
750
- });
751
- }
752
- async withLock(operation) {
753
- const run = this.pending.then(operation, operation);
754
- this.pending = run.then(
755
- () => void 0,
756
- () => void 0
757
- );
758
- return await run;
759
- }
760
- async readInstallations() {
761
- let contents;
762
- try {
763
- contents = await fs2.readFile(this.filePath, "utf8");
764
- } catch (error) {
765
- if (isNodeErrorCode(error, "ENOENT")) {
766
- return {};
767
- }
768
- throw error;
769
- }
770
- if (!contents.trim()) {
771
- return {};
772
- }
773
- const parsed = JSON.parse(contents);
774
- const record = asRecord(parsed);
775
- const installations = asRecord(record?.installations) ?? record;
776
- if (!installations) {
777
- return {};
778
- }
779
- const output = {};
780
- for (const [key, value] of Object.entries(installations)) {
781
- if (asRecord(value)) {
782
- output[key] = value;
783
- }
784
- }
785
- return output;
786
- }
787
- async writeInstallations(installations) {
788
- await fs2.mkdir(dirname(this.filePath), { recursive: true });
789
- const tempPath = `${this.filePath}.${process.pid}.${Date.now()}.tmp`;
790
- const payload = JSON.stringify({ version: 1, installations }, null, 2);
791
- await fs2.writeFile(tempPath, `${payload}
792
- `, "utf8");
793
- await fs2.rename(tempPath, this.filePath);
794
- }
795
- };
796
- function createJsonFileSlackInstallationStore(filePath) {
797
- return new JsonFileSlackInstallationStore(filePath);
798
- }
799
- function createSlackInstallationStoreAuthorize(store) {
800
- return async (source) => {
801
- const installation = await store.fetchInstallation({
802
- teamId: source.teamId,
803
- enterpriseId: source.enterpriseId,
804
- userId: source.userId,
805
- conversationId: source.conversationId,
806
- isEnterpriseInstall: source.isEnterpriseInstall
807
- });
808
- const botToken = installation.bot?.token;
809
- if (!botToken) {
810
- throw new Error(
811
- "Slack OAuth installation is missing a bot token. Reinstall the Slack app with bot scopes."
812
- );
813
- }
814
- return {
815
- botToken,
816
- botId: installation.bot?.id,
817
- botUserId: installation.bot?.userId,
818
- teamId: installation.team?.id ?? source.teamId,
819
- enterpriseId: installation.enterprise?.id ?? source.enterpriseId,
820
- userId: installation.user.id,
821
- userToken: installation.user.token
822
- };
823
- };
824
- }
825
- function getSlackInstallationKey(input) {
826
- if (input.isEnterpriseInstall && "enterprise" in input && input.enterprise?.id) {
827
- return `enterprise:${input.enterprise.id}`;
828
- }
829
- if (input.isEnterpriseInstall && "enterpriseId" in input && input.enterpriseId) {
830
- return `enterprise:${input.enterpriseId}`;
831
- }
832
- if ("team" in input && input.team?.id) {
833
- return `team:${input.team.id}`;
834
- }
835
- if ("teamId" in input && input.teamId) {
836
- return `team:${input.teamId}`;
837
- }
838
- throw new Error("Slack installation is missing a team or enterprise id.");
839
- }
840
- function asRecord(value) {
841
- return value && typeof value === "object" ? value : void 0;
842
- }
843
- function isNodeErrorCode(error, code) {
844
- return error instanceof Error && "code" in error && error.code === code;
845
- }
846
558
  export {
847
- InMemorySlackInstallationStore,
848
- JsonFileSlackInstallationStore,
849
- acquireSlackSocketModePostgresLock,
850
- acquireSlackSocketModeProcessLock,
851
- createInMemorySlackInstallationStore,
852
- createJsonFileSlackInstallationStore,
853
- createSlackBoltApp,
854
- createSlackInstallationStoreAuthorize,
855
- createSlackSdkLogger,
856
559
  createSlackSocketBoltApp,
857
- createSlackSocketModeRestartGuard,
560
+ acquireSlackSocketModeProcessLock,
561
+ acquireSlackSocketModePostgresLock,
858
562
  createSlackSocketModeRuntime,
859
- getSlackInstallationKey,
563
+ createSlackSocketModeRestartGuard,
564
+ createSlackSdkLogger,
860
565
  redactSlackSocketModeLogValue
861
566
  };