@spectrum-ts/slack 12.0.0 → 12.1.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.
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ type SlackMessage = SchemaMessage<typeof userSchema, typeof spaceSchema> & {
15
15
  };
16
16
  //#endregion
17
17
  //#region src/index.d.ts
18
- declare const slack: import("@spectrum-ts/core").Platform<import("@spectrum-ts/core").PlatformDef<"Slack", import("zod").ZodUnion<readonly [import("zod").ZodObject<{
18
+ declare const slack: import("@spectrum-ts/core").Platform<import("@spectrum-ts/core").PlatformDef<"slack", import("zod").ZodUnion<readonly [import("zod").ZodObject<{
19
19
  endpoint: import("zod").ZodOptional<import("zod").ZodString>;
20
20
  teams: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodObject<{
21
21
  appId: import("zod").ZodString;
package/dist/index.js CHANGED
@@ -1,12 +1,8 @@
1
1
  import { createClient, staticTokens } from "@photon-ai/slack";
2
2
  import { UnsupportedError, cloud, definePlatform, mergeStreams, stream } from "@spectrum-ts/core";
3
- import { asAttachment, asCustom, asReaction, asText, createLogger, errorAttrs } from "@spectrum-ts/core/authoring";
3
+ import { asAttachment, asCustom, asReaction, asText, createTokenRenewal } from "@spectrum-ts/core/authoring";
4
4
  import z from "zod";
5
5
  //#region src/auth.ts
6
- const log = createLogger("spectrum.slack.auth");
7
- const RENEWAL_RATIO = .8;
8
- const EXPIRY_BUFFER_MS = 3e4;
9
- const RETRY_DELAY_MS = 3e4;
10
6
  const cloudAuthState = /* @__PURE__ */ new WeakMap();
11
7
  const toTeamMetadata = (meta) => ({
12
8
  appId: meta.appId,
@@ -26,96 +22,34 @@ const toTeamMetadata = (meta) => ({
26
22
  */
27
23
  async function createCloudClients(projectId, projectSecret, endpoint) {
28
24
  let tokenData = await cloud.issueSlackTokens(projectId, projectSecret);
29
- let tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
30
- let disposed = false;
31
- let renewalTimer;
32
- let refreshFailures = 0;
33
- const clearRenewalTimer = () => {
34
- if (renewalTimer !== void 0) {
35
- clearTimeout(renewalTimer);
36
- renewalTimer = void 0;
25
+ const renewal = createTokenRenewal({
26
+ expiresInSeconds: () => tokenData.expiresIn,
27
+ name: "slack",
28
+ refresh: async () => {
29
+ tokenData = await cloud.issueSlackTokens(projectId, projectSecret);
37
30
  }
38
- };
39
- const refreshTokens = async () => {
40
- tokenData = await cloud.issueSlackTokens(projectId, projectSecret);
41
- tokenExpiresAt = Date.now() + tokenData.expiresIn * 1e3;
42
- };
43
- const onRefreshSuccess = () => {
44
- if (refreshFailures > 0) {
45
- log.info("slack token refresh recovered", { "spectrum.slack.auth.attempt": refreshFailures });
46
- refreshFailures = 0;
47
- }
48
- };
49
- const onRefreshFailure = (error) => {
50
- refreshFailures += 1;
51
- log.warn("slack token refresh failed; retrying", {
52
- "spectrum.slack.auth.attempt": refreshFailures,
53
- "spectrum.slack.auth.retry_in_ms": RETRY_DELAY_MS,
54
- ...errorAttrs(error)
55
- }, error);
56
- };
57
- const scheduleRetry = () => {
58
- if (disposed) return;
59
- clearRenewalTimer();
60
- renewalTimer = setTimeout(async () => {
61
- if (disposed) return;
62
- try {
63
- await refreshTokens();
64
- onRefreshSuccess();
65
- scheduleRenewal();
66
- } catch (retryErr) {
67
- onRefreshFailure(retryErr);
68
- scheduleRetry();
69
- }
70
- }, RETRY_DELAY_MS);
71
- renewalTimer?.unref?.();
72
- };
73
- const scheduleRenewal = () => {
74
- if (disposed) return;
75
- clearRenewalTimer();
76
- const ttlMs = tokenData.expiresIn * 1e3;
77
- const renewInMs = Math.max(ttlMs * RENEWAL_RATIO, 5e3);
78
- renewalTimer = setTimeout(async () => {
79
- try {
80
- await refreshTokens();
81
- onRefreshSuccess();
82
- scheduleRenewal();
83
- } catch (err) {
84
- onRefreshFailure(err);
85
- scheduleRetry();
86
- }
87
- }, renewInMs);
88
- renewalTimer?.unref?.();
89
- };
90
- const refreshIfNeeded = async () => {
91
- if (Date.now() < tokenExpiresAt - EXPIRY_BUFFER_MS) return;
92
- await refreshTokens();
93
- onRefreshSuccess();
94
- scheduleRenewal();
95
- };
96
- scheduleRenewal();
31
+ });
97
32
  const client = createClient({
98
33
  spectrumSlackEndpoint: endpoint,
99
34
  tokenProvider: {
100
35
  async getAccessToken(teamId) {
101
- await refreshIfNeeded();
36
+ await renewal.refreshIfNeeded();
102
37
  const token = tokenData.auth[teamId];
103
38
  if (!token) throw new Error(`Slack team ${teamId} has no active installation in this project`);
104
39
  return token;
105
40
  },
106
41
  invalidate(_teamId) {
107
- tokenExpiresAt = 0;
42
+ renewal.invalidate();
108
43
  },
109
44
  async listTeams() {
110
- await refreshIfNeeded();
45
+ await renewal.refreshIfNeeded();
111
46
  const entries = Object.entries(tokenData.teams).map(([teamId, meta]) => [teamId, toTeamMetadata(meta)]);
112
47
  return new Map(entries);
113
48
  }
114
49
  }
115
50
  });
116
51
  cloudAuthState.set(client, { dispose: async () => {
117
- disposed = true;
118
- clearRenewalTimer();
52
+ renewal.dispose();
119
53
  } });
120
54
  return client;
121
55
  }
@@ -404,7 +338,8 @@ const messageSchema = z.object({
404
338
  });
405
339
  //#endregion
406
340
  //#region src/index.ts
407
- const slack = definePlatform("Slack", {
341
+ const PLATFORM_ID = "slack";
342
+ const slack = definePlatform(PLATFORM_ID, {
408
343
  config: configSchema,
409
344
  lifecycle: {
410
345
  createClient: async ({ config, projectId, projectSecret }) => {
@@ -433,7 +368,7 @@ const slack = definePlatform("Slack", {
433
368
  create: async ({ input }) => {
434
369
  const teamId = input.params?.teamId;
435
370
  if (!teamId) throw new Error("Slack space creation requires a teamId param. Pass it via space.create(user, { teamId }).");
436
- if (input.users.length > 1) throw UnsupportedError.action("space.create", "Slack", "group DMs require an explicit channel id (Slack's conversations.open is not exposed); use space.get(channelId, { teamId })");
371
+ if (input.users.length > 1) throw UnsupportedError.action("space.create", PLATFORM_ID, "group DMs require an explicit channel id (Slack's conversations.open is not exposed); use space.get(channelId, { teamId })");
437
372
  const user = input.users[0];
438
373
  if (!user) throw new Error("Slack space creation requires a user");
439
374
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectrum-ts/slack",
3
- "version": "12.0.0",
3
+ "version": "12.1.0",
4
4
  "description": "Slack provider for spectrum-ts.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "spectrum": {
29
29
  "key": "slack",
30
30
  "import": "slack",
31
- "label": "Slack"
31
+ "label": "slack"
32
32
  },
33
33
  "dependencies": {
34
34
  "@photon-ai/slack": "^0.2.0",