managed-deepagents 0.4.0-dev.68 → 0.4.0-dev.70
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/README.md +1 -1
- package/dist/channels/assistant-text.d.ts +7 -0
- package/dist/channels/assistant-text.d.ts.map +1 -0
- package/dist/channels/assistant-text.js +28 -0
- package/dist/channels/assistant-text.js.map +1 -0
- package/dist/channels/binding.d.ts +34 -0
- package/dist/channels/binding.d.ts.map +1 -0
- package/dist/channels/binding.js +67 -0
- package/dist/channels/binding.js.map +1 -0
- package/dist/channels/errors.d.ts +11 -0
- package/dist/channels/errors.d.ts.map +1 -0
- package/dist/channels/errors.js +25 -0
- package/dist/channels/errors.js.map +1 -0
- package/dist/channels/index.d.ts +19 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +14 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/runtime.d.ts +40 -0
- package/dist/channels/runtime.d.ts.map +1 -0
- package/dist/channels/runtime.js +76 -0
- package/dist/channels/runtime.js.map +1 -0
- package/dist/channels/schedule-delivery.d.ts +67 -0
- package/dist/channels/schedule-delivery.d.ts.map +1 -0
- package/dist/channels/schedule-delivery.js +193 -0
- package/dist/channels/schedule-delivery.js.map +1 -0
- package/dist/channels/slack/define.d.ts +87 -0
- package/dist/channels/slack/define.d.ts.map +1 -0
- package/dist/channels/slack/define.js +141 -0
- package/dist/channels/slack/define.js.map +1 -0
- package/dist/channels/slack/http.d.ts +86 -0
- package/dist/channels/slack/http.d.ts.map +1 -0
- package/dist/channels/slack/http.js +441 -0
- package/dist/channels/slack/http.js.map +1 -0
- package/dist/channels/slack/index.d.ts +18 -0
- package/dist/channels/slack/index.d.ts.map +1 -0
- package/dist/channels/slack/index.js +13 -0
- package/dist/channels/slack/index.js.map +1 -0
- package/dist/channels/slack/normalize.d.ts +62 -0
- package/dist/channels/slack/normalize.d.ts.map +1 -0
- package/dist/channels/slack/normalize.js +320 -0
- package/dist/channels/slack/normalize.js.map +1 -0
- package/dist/channels/slack/source-thread.d.ts +34 -0
- package/dist/channels/slack/source-thread.d.ts.map +1 -0
- package/dist/channels/slack/source-thread.js +92 -0
- package/dist/channels/slack/source-thread.js.map +1 -0
- package/dist/channels/slack/transport.d.ts +48 -0
- package/dist/channels/slack/transport.d.ts.map +1 -0
- package/dist/channels/slack/transport.js +178 -0
- package/dist/channels/slack/transport.js.map +1 -0
- package/dist/channels/store.d.ts +51 -0
- package/dist/channels/store.d.ts.map +1 -0
- package/dist/channels/store.js +76 -0
- package/dist/channels/store.js.map +1 -0
- package/dist/channels/types.d.ts +116 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +24 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/identity/links.d.ts +62 -0
- package/dist/identity/links.d.ts.map +1 -0
- package/dist/identity/links.js +176 -0
- package/dist/identity/links.js.map +1 -0
- package/dist/identity/slack-connect-http.d.ts +21 -0
- package/dist/identity/slack-connect-http.d.ts.map +1 -0
- package/dist/identity/slack-connect-http.js +129 -0
- package/dist/identity/slack-connect-http.js.map +1 -0
- package/dist/identity/slack-oauth.d.ts +60 -0
- package/dist/identity/slack-oauth.d.ts.map +1 -0
- package/dist/identity/slack-oauth.js +193 -0
- package/dist/identity/slack-oauth.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/auth.d.ts +40 -0
- package/dist/runtime/auth.d.ts.map +1 -1
- package/dist/runtime/auth.js +123 -9
- package/dist/runtime/auth.js.map +1 -1
- package/dist/runtime/cors.d.ts +28 -0
- package/dist/runtime/cors.d.ts.map +1 -0
- package/dist/runtime/cors.js +92 -0
- package/dist/runtime/cors.js.map +1 -0
- package/dist/runtime/identity-http.d.ts +6 -0
- package/dist/runtime/identity-http.d.ts.map +1 -1
- package/dist/runtime/identity-http.js +90 -2
- package/dist/runtime/identity-http.js.map +1 -1
- package/dist/runtime/identity-runtime.d.ts +41 -1
- package/dist/runtime/identity-runtime.d.ts.map +1 -1
- package/dist/runtime/identity-runtime.js +142 -2
- package/dist/runtime/identity-runtime.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +75 -191
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/langsmith-connector.d.ts.map +1 -1
- package/dist/runtime/langsmith-connector.js +4 -3
- package/dist/runtime/langsmith-connector.js.map +1 -1
- package/dist/runtime/managed-tools.d.ts +6 -0
- package/dist/runtime/managed-tools.d.ts.map +1 -1
- package/dist/runtime/managed-tools.js +10 -0
- package/dist/runtime/managed-tools.js.map +1 -1
- package/dist/runtime/memory/context-io.d.ts +5 -0
- package/dist/runtime/memory/context-io.d.ts.map +1 -0
- package/dist/runtime/memory/context-io.js +28 -0
- package/dist/runtime/memory/context-io.js.map +1 -0
- package/dist/runtime/memory/index.d.ts +8 -0
- package/dist/runtime/memory/index.d.ts.map +1 -0
- package/dist/runtime/memory/index.js +6 -0
- package/dist/runtime/memory/index.js.map +1 -0
- package/dist/runtime/memory/mounts.d.ts +38 -0
- package/dist/runtime/memory/mounts.d.ts.map +1 -0
- package/dist/runtime/memory/mounts.js +185 -0
- package/dist/runtime/memory/mounts.js.map +1 -0
- package/dist/runtime/memory/paths.d.ts +10 -0
- package/dist/runtime/memory/paths.d.ts.map +1 -0
- package/dist/runtime/memory/paths.js +50 -0
- package/dist/runtime/memory/paths.js.map +1 -0
- package/dist/runtime/memory/seed.d.ts +37 -0
- package/dist/runtime/memory/seed.d.ts.map +1 -0
- package/dist/runtime/memory/seed.js +203 -0
- package/dist/runtime/memory/seed.js.map +1 -0
- package/dist/runtime/memory/user-repo.d.ts +19 -0
- package/dist/runtime/memory/user-repo.d.ts.map +1 -0
- package/dist/runtime/memory/user-repo.js +57 -0
- package/dist/runtime/memory/user-repo.js.map +1 -0
- package/dist/runtime/types.d.ts +11 -2
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/schedules.d.ts +6 -3
- package/dist/schedules.d.ts.map +1 -1
- package/dist/schedules.js +22 -0
- package/dist/schedules.js.map +1 -1
- package/dist/types.d.ts +4 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +16 -7
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable Slack ↔ actor account links (Open SWE–style mapping).
|
|
3
|
+
*
|
|
4
|
+
* Stored in the LangGraph Store under `["mda_identity_links"]`, with an
|
|
5
|
+
* in-memory backend for unit tests. Slack Events look up `slack:T:U` before
|
|
6
|
+
* invoke; the web Connect-with-Slack flow upserts after OIDC.
|
|
7
|
+
*/
|
|
8
|
+
import { Client } from "@langchain/langgraph-sdk";
|
|
9
|
+
import { ACTOR_HEADER, IDENTITY_LINKS_SERVICE_ACTOR, IDENTITY_LINKS_STORE_PREFIX, INGRESS_SECRET_ENV, INGRESS_SECRET_HEADER, } from "../runtime/auth.js";
|
|
10
|
+
export const IDENTITY_LINKS_NAMESPACE = [IDENTITY_LINKS_STORE_PREFIX];
|
|
11
|
+
/** In-memory store for tests (and as a process-local cache layer). */
|
|
12
|
+
export class InMemoryIdentityLinkStore {
|
|
13
|
+
bySlack = new Map();
|
|
14
|
+
byActor = new Map();
|
|
15
|
+
async getBySlackActorId(slackActorId) {
|
|
16
|
+
return this.bySlack.get(slackActorId) ?? null;
|
|
17
|
+
}
|
|
18
|
+
async getByActorId(actorId) {
|
|
19
|
+
return this.byActor.get(actorId) ?? null;
|
|
20
|
+
}
|
|
21
|
+
async upsert(record) {
|
|
22
|
+
const previous = this.byActor.get(record.actorId);
|
|
23
|
+
if (previous && previous.slackActorId !== record.slackActorId) {
|
|
24
|
+
this.bySlack.delete(previous.slackActorId);
|
|
25
|
+
}
|
|
26
|
+
const existingSlack = this.bySlack.get(record.slackActorId);
|
|
27
|
+
if (existingSlack && existingSlack.actorId !== record.actorId) {
|
|
28
|
+
this.byActor.delete(existingSlack.actorId);
|
|
29
|
+
}
|
|
30
|
+
this.bySlack.set(record.slackActorId, record);
|
|
31
|
+
this.byActor.set(record.actorId, record);
|
|
32
|
+
}
|
|
33
|
+
async removeByActorId(actorId) {
|
|
34
|
+
const existing = this.byActor.get(actorId);
|
|
35
|
+
if (!existing) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
this.byActor.delete(actorId);
|
|
39
|
+
this.bySlack.delete(existing.slackActorId);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** LangGraph Store–backed identity links. */
|
|
43
|
+
export class LangGraphIdentityLinkStore {
|
|
44
|
+
client;
|
|
45
|
+
constructor(client) {
|
|
46
|
+
this.client = client;
|
|
47
|
+
}
|
|
48
|
+
async getBySlackActorId(slackActorId) {
|
|
49
|
+
return this.getItem(slackKey(slackActorId));
|
|
50
|
+
}
|
|
51
|
+
async getByActorId(actorId) {
|
|
52
|
+
return this.getItem(actorKey(actorId));
|
|
53
|
+
}
|
|
54
|
+
async upsert(record) {
|
|
55
|
+
const previous = await this.getByActorId(record.actorId);
|
|
56
|
+
if (previous && previous.slackActorId !== record.slackActorId) {
|
|
57
|
+
await this.client.store.deleteItem([...IDENTITY_LINKS_NAMESPACE], slackKey(previous.slackActorId));
|
|
58
|
+
}
|
|
59
|
+
const existingSlack = await this.getBySlackActorId(record.slackActorId);
|
|
60
|
+
if (existingSlack && existingSlack.actorId !== record.actorId) {
|
|
61
|
+
await this.client.store.deleteItem([...IDENTITY_LINKS_NAMESPACE], actorKey(existingSlack.actorId));
|
|
62
|
+
}
|
|
63
|
+
const value = recordToValue(record);
|
|
64
|
+
await this.client.store.putItem([...IDENTITY_LINKS_NAMESPACE], slackKey(record.slackActorId), value);
|
|
65
|
+
await this.client.store.putItem([...IDENTITY_LINKS_NAMESPACE], actorKey(record.actorId), value);
|
|
66
|
+
}
|
|
67
|
+
async removeByActorId(actorId) {
|
|
68
|
+
const existing = await this.getByActorId(actorId);
|
|
69
|
+
if (!existing) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await this.client.store.deleteItem([...IDENTITY_LINKS_NAMESPACE], actorKey(actorId));
|
|
73
|
+
await this.client.store.deleteItem([...IDENTITY_LINKS_NAMESPACE], slackKey(existing.slackActorId));
|
|
74
|
+
}
|
|
75
|
+
async getItem(key) {
|
|
76
|
+
const item = await this.client.store.getItem([...IDENTITY_LINKS_NAMESPACE], key);
|
|
77
|
+
if (!item?.value || typeof item.value !== "object") {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return valueToRecord(item.value);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let defaultStore = null;
|
|
84
|
+
/** Override the process-default link store (tests). */
|
|
85
|
+
export function setIdentityLinkStore(store) {
|
|
86
|
+
defaultStore = store;
|
|
87
|
+
}
|
|
88
|
+
/** Resolve the process-default link store (in-memory until a Client is wired). */
|
|
89
|
+
export function getIdentityLinkStore() {
|
|
90
|
+
if (defaultStore) {
|
|
91
|
+
return defaultStore;
|
|
92
|
+
}
|
|
93
|
+
defaultStore =
|
|
94
|
+
createLangGraphIdentityLinkStore() ?? new InMemoryIdentityLinkStore();
|
|
95
|
+
return defaultStore;
|
|
96
|
+
}
|
|
97
|
+
/** Build a Store-backed client when loopback + ingress secret are available. */
|
|
98
|
+
export function createLangGraphIdentityLinkStore(options = {}) {
|
|
99
|
+
const ingressSecret = options.ingressSecret ?? process.env[INGRESS_SECRET_ENV];
|
|
100
|
+
if (!ingressSecret) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const apiUrl = resolveLoopbackApiUrl(options.apiUrl);
|
|
104
|
+
const apiKey = options.apiKey ??
|
|
105
|
+
process.env.LANGSMITH_API_KEY ??
|
|
106
|
+
process.env.LANGGRAPH_API_KEY ??
|
|
107
|
+
"local";
|
|
108
|
+
const client = new Client({
|
|
109
|
+
apiUrl,
|
|
110
|
+
apiKey,
|
|
111
|
+
defaultHeaders: {
|
|
112
|
+
[INGRESS_SECRET_HEADER]: ingressSecret,
|
|
113
|
+
[ACTOR_HEADER]: IDENTITY_LINKS_SERVICE_ACTOR,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
return new LangGraphIdentityLinkStore(client);
|
|
117
|
+
}
|
|
118
|
+
export function slackActorIdFromParts(teamId, userId) {
|
|
119
|
+
return `slack:${teamId}:${userId}`;
|
|
120
|
+
}
|
|
121
|
+
export function buildIdentityLinkRecord(input) {
|
|
122
|
+
const team = input.slackTeamId?.trim() || "unknown";
|
|
123
|
+
return {
|
|
124
|
+
actorId: input.actorId,
|
|
125
|
+
slackUserId: input.slackUserId,
|
|
126
|
+
...(input.slackTeamId ? { slackTeamId: input.slackTeamId } : {}),
|
|
127
|
+
slackActorId: slackActorIdFromParts(team, input.slackUserId),
|
|
128
|
+
...(input.email ? { email: input.email } : {}),
|
|
129
|
+
linkedAt: new Date().toISOString(),
|
|
130
|
+
source: "slack_oauth",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function slackKey(slackActorId) {
|
|
134
|
+
return `slack:${slackActorId.replace(/^slack:/, "")}`;
|
|
135
|
+
}
|
|
136
|
+
function actorKey(actorId) {
|
|
137
|
+
return `actor:${actorId}`;
|
|
138
|
+
}
|
|
139
|
+
function recordToValue(record) {
|
|
140
|
+
return { ...record };
|
|
141
|
+
}
|
|
142
|
+
function valueToRecord(value) {
|
|
143
|
+
const actorId = value.actorId;
|
|
144
|
+
const slackUserId = value.slackUserId;
|
|
145
|
+
const slackActorId = value.slackActorId;
|
|
146
|
+
if (typeof actorId !== "string" ||
|
|
147
|
+
typeof slackUserId !== "string" ||
|
|
148
|
+
typeof slackActorId !== "string") {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
actorId,
|
|
153
|
+
slackUserId,
|
|
154
|
+
slackActorId,
|
|
155
|
+
...(typeof value.slackTeamId === "string"
|
|
156
|
+
? { slackTeamId: value.slackTeamId }
|
|
157
|
+
: {}),
|
|
158
|
+
...(typeof value.email === "string" ? { email: value.email } : {}),
|
|
159
|
+
linkedAt: typeof value.linkedAt === "string"
|
|
160
|
+
? value.linkedAt
|
|
161
|
+
: new Date().toISOString(),
|
|
162
|
+
source: "slack_oauth",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function resolveLoopbackApiUrl(explicit) {
|
|
166
|
+
const fromEnv = explicit ??
|
|
167
|
+
process.env.MDA_CHANNEL_API_URL ??
|
|
168
|
+
process.env.LANGGRAPH_API_URL ??
|
|
169
|
+
process.env.LANGSMITH_ENDPOINT;
|
|
170
|
+
if (fromEnv && fromEnv.trim().length > 0) {
|
|
171
|
+
return fromEnv.replace(/\/$/, "");
|
|
172
|
+
}
|
|
173
|
+
const port = process.env.PORT ?? "8000";
|
|
174
|
+
return `http://127.0.0.1:${port}`;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/identity/links.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connect-with-Slack HTTP handlers mounted under `/identity/slack/*`.
|
|
3
|
+
*
|
|
4
|
+
* Only registered when the project declares at least one Slack channel.
|
|
5
|
+
*/
|
|
6
|
+
import type { Hono } from "hono";
|
|
7
|
+
import type { IdentityConfig } from "./index.js";
|
|
8
|
+
import { type IdentityLinkStore } from "./links.js";
|
|
9
|
+
export declare const SLACK_CONNECT_STATUS_PATH = "/identity/slack/status";
|
|
10
|
+
export declare const SLACK_CONNECT_START_PATH = "/identity/slack/connect";
|
|
11
|
+
export declare const SLACK_CONNECT_CALLBACK_PATH = "/identity/slack/callback";
|
|
12
|
+
export declare const SLACK_CONNECT_LINK_PATH = "/identity/slack/link";
|
|
13
|
+
export declare function projectHasSlackChannel(channels: Record<string, {
|
|
14
|
+
provider?: string;
|
|
15
|
+
}> | undefined): boolean;
|
|
16
|
+
export declare function mountSlackConnectRoutes(app: Hono, cfg: IdentityConfig, options?: {
|
|
17
|
+
linkStore?: IdentityLinkStore;
|
|
18
|
+
/** Absolute base URL of this deployment (for OAuth redirect_uri). */
|
|
19
|
+
deploymentBaseUrl?: string;
|
|
20
|
+
}): void;
|
|
21
|
+
//# sourceMappingURL=slack-connect-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-connect-http.d.ts","sourceRoot":"","sources":["../../src/identity/slack-connect-http.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAEjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,YAAY,CAAC;AAcpB,eAAO,MAAM,yBAAyB,2BAA2B,CAAC;AAClE,eAAO,MAAM,wBAAwB,4BAA4B,CAAC;AAClE,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AACtE,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAE9D,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,GAC1D,OAAO,CAOT;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,IAAI,EACT,GAAG,EAAE,cAAc,EACnB,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACvB,GACL,IAAI,CAwGN"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connect-with-Slack HTTP handlers mounted under `/identity/slack/*`.
|
|
3
|
+
*
|
|
4
|
+
* Only registered when the project declares at least one Slack channel.
|
|
5
|
+
*/
|
|
6
|
+
import { buildIdentityLinkRecord, getIdentityLinkStore, } from "./links.js";
|
|
7
|
+
import { buildSlackAuthorizeUrl, createSlackOauthState, exchangeSlackOidcCode, MDA_PUBLIC_APP_URL_ENV, OAUTH_STATE_SIGNING_KEY_ENV, readOauthStateSigningKey, readSlackOidcConfig, resolveSlackOauthRedirectBase, verifySlackOauthState, } from "./slack-oauth.js";
|
|
8
|
+
import { resolveRequestIdentity } from "../runtime/auth.js";
|
|
9
|
+
export const SLACK_CONNECT_STATUS_PATH = "/identity/slack/status";
|
|
10
|
+
export const SLACK_CONNECT_START_PATH = "/identity/slack/connect";
|
|
11
|
+
export const SLACK_CONNECT_CALLBACK_PATH = "/identity/slack/callback";
|
|
12
|
+
export const SLACK_CONNECT_LINK_PATH = "/identity/slack/link";
|
|
13
|
+
export function projectHasSlackChannel(channels) {
|
|
14
|
+
if (!channels) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return Object.values(channels).some((manifest) => manifest.provider === "slack");
|
|
18
|
+
}
|
|
19
|
+
export function mountSlackConnectRoutes(app, cfg, options = {}) {
|
|
20
|
+
const store = options.linkStore ?? getIdentityLinkStore();
|
|
21
|
+
app.get(SLACK_CONNECT_STATUS_PATH, async (c) => {
|
|
22
|
+
const identity = await resolveOrUnauthorized(cfg, c.req.raw);
|
|
23
|
+
if (identity instanceof Response) {
|
|
24
|
+
return identity;
|
|
25
|
+
}
|
|
26
|
+
const link = await store.getByActorId(identity.actor.id);
|
|
27
|
+
return c.json({
|
|
28
|
+
linked: Boolean(link),
|
|
29
|
+
...(link
|
|
30
|
+
? {
|
|
31
|
+
slackUserId: link.slackUserId,
|
|
32
|
+
slackActorId: link.slackActorId,
|
|
33
|
+
linkedAt: link.linkedAt,
|
|
34
|
+
}
|
|
35
|
+
: {}),
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
app.get(SLACK_CONNECT_START_PATH, async (c) => {
|
|
39
|
+
const identity = await resolveOrUnauthorized(cfg, c.req.raw);
|
|
40
|
+
if (identity instanceof Response) {
|
|
41
|
+
return identity;
|
|
42
|
+
}
|
|
43
|
+
const oauth = readSlackOidcConfig();
|
|
44
|
+
const stateKey = readOauthStateSigningKey();
|
|
45
|
+
if (!oauth || !stateKey) {
|
|
46
|
+
return c.json({
|
|
47
|
+
error: `Slack connect is not configured (set SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, MDA_PUBLIC_APP_URL, ${OAUTH_STATE_SIGNING_KEY_ENV})`,
|
|
48
|
+
}, 503);
|
|
49
|
+
}
|
|
50
|
+
const redirectUri = slackCallbackRedirectUri(c.req.raw, options.deploymentBaseUrl);
|
|
51
|
+
const state = await createSlackOauthState(identity.actor.id, stateKey);
|
|
52
|
+
const authorizeUrl = buildSlackAuthorizeUrl(oauth, state, redirectUri);
|
|
53
|
+
// JSON for browser clients that send Bearer via fetch; redirect for plain GET.
|
|
54
|
+
const wantsJson = c.req.query("format") === "json" ||
|
|
55
|
+
(c.req.header("accept") ?? "").includes("application/json");
|
|
56
|
+
if (wantsJson) {
|
|
57
|
+
return c.json({ authorizeUrl });
|
|
58
|
+
}
|
|
59
|
+
return c.redirect(authorizeUrl, 302);
|
|
60
|
+
});
|
|
61
|
+
app.get(SLACK_CONNECT_CALLBACK_PATH, async (c) => {
|
|
62
|
+
const oauth = readSlackOidcConfig();
|
|
63
|
+
const publicApp = oauth?.publicAppUrl ??
|
|
64
|
+
process.env[MDA_PUBLIC_APP_URL_ENV]?.replace(/\/$/, "");
|
|
65
|
+
const failRedirect = publicApp ? `${publicApp}/settings?slack=error` : "/";
|
|
66
|
+
try {
|
|
67
|
+
if (!oauth) {
|
|
68
|
+
throw new Error("Slack OAuth is not configured");
|
|
69
|
+
}
|
|
70
|
+
const code = c.req.query("code");
|
|
71
|
+
const state = c.req.query("state");
|
|
72
|
+
if (!code || !state) {
|
|
73
|
+
throw new Error("missing code or state");
|
|
74
|
+
}
|
|
75
|
+
const stateKey = readOauthStateSigningKey();
|
|
76
|
+
if (!stateKey) {
|
|
77
|
+
throw new Error(`${OAUTH_STATE_SIGNING_KEY_ENV} is not configured`);
|
|
78
|
+
}
|
|
79
|
+
const { actorId } = await verifySlackOauthState(state, stateKey);
|
|
80
|
+
const redirectUri = slackCallbackRedirectUri(c.req.raw, options.deploymentBaseUrl);
|
|
81
|
+
const slackIdentity = await exchangeSlackOidcCode(oauth, code, redirectUri);
|
|
82
|
+
const teamId = slackIdentity.teamId ?? oauth.teamId;
|
|
83
|
+
const record = buildIdentityLinkRecord({
|
|
84
|
+
actorId,
|
|
85
|
+
slackUserId: slackIdentity.userId,
|
|
86
|
+
...(teamId ? { slackTeamId: teamId } : {}),
|
|
87
|
+
...(slackIdentity.email ? { email: slackIdentity.email } : {}),
|
|
88
|
+
});
|
|
89
|
+
await store.upsert(record);
|
|
90
|
+
return c.redirect(`${oauth.publicAppUrl}/settings?slack=connected`, 302);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error("[mda] Slack OAuth callback failed:", error);
|
|
94
|
+
return c.redirect(failRedirect, 302);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
app.delete(SLACK_CONNECT_LINK_PATH, async (c) => {
|
|
98
|
+
const identity = await resolveOrUnauthorized(cfg, c.req.raw);
|
|
99
|
+
if (identity instanceof Response) {
|
|
100
|
+
return identity;
|
|
101
|
+
}
|
|
102
|
+
await store.removeByActorId(identity.actor.id);
|
|
103
|
+
return c.json({ linked: false });
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async function resolveOrUnauthorized(cfg, request) {
|
|
107
|
+
try {
|
|
108
|
+
return await resolveRequestIdentity(cfg, request);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const status = typeof error.status === "number"
|
|
112
|
+
? error.status
|
|
113
|
+
: 401;
|
|
114
|
+
const message = error instanceof Error && error.message ? error.message : "unauthorized";
|
|
115
|
+
return new Response(JSON.stringify({ error: message }), {
|
|
116
|
+
status,
|
|
117
|
+
headers: { "content-type": "application/json" },
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function slackCallbackRedirectUri(request, deploymentBaseUrl) {
|
|
122
|
+
const base = resolveSlackOauthRedirectBase({
|
|
123
|
+
requestUrl: request.url,
|
|
124
|
+
headers: request.headers,
|
|
125
|
+
deploymentBaseUrl,
|
|
126
|
+
});
|
|
127
|
+
return `${base}${SLACK_CONNECT_CALLBACK_PATH}`;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=slack-connect-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-connect-http.js","sourceRoot":"","sources":["../../src/identity/slack-connect-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack OpenID Connect helpers for Connect-with-Slack account linking.
|
|
3
|
+
*/
|
|
4
|
+
export declare const SLACK_CLIENT_ID_ENV = "SLACK_CLIENT_ID";
|
|
5
|
+
export declare const SLACK_CLIENT_SECRET_ENV = "SLACK_CLIENT_SECRET";
|
|
6
|
+
export declare const SLACK_TEAM_ID_ENV = "SLACK_TEAM_ID";
|
|
7
|
+
export declare const MDA_PUBLIC_APP_URL_ENV = "MDA_PUBLIC_APP_URL";
|
|
8
|
+
/**
|
|
9
|
+
* Public Agent Server base URL used for Slack OAuth `redirect_uri`.
|
|
10
|
+
* Required on LangGraph Host where the ASGI request origin is an internal
|
|
11
|
+
* loopback (e.g. `http://localhost:5557`) rather than `*.langgraph.app`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MDA_PUBLIC_API_URL_ENV = "MDA_PUBLIC_API_URL";
|
|
14
|
+
/**
|
|
15
|
+
* Signing key for OAuth `state` JWTs (Connect-with-Slack). Reuses the guest
|
|
16
|
+
* token key so deployments do not need a third secret; never the Slack
|
|
17
|
+
* client secret (that value is an OAuth credential, not a signing key).
|
|
18
|
+
*/
|
|
19
|
+
export declare const OAUTH_STATE_SIGNING_KEY_ENV = "MDA_GUEST_SIGNING_KEY";
|
|
20
|
+
/** Override Slack OIDC base (tests). */
|
|
21
|
+
export declare const SLACK_OIDC_BASE_ENV = "SLACK_OIDC_BASE";
|
|
22
|
+
export interface SlackOidcConfig {
|
|
23
|
+
clientId: string;
|
|
24
|
+
clientSecret: string;
|
|
25
|
+
teamId?: string;
|
|
26
|
+
publicAppUrl: string;
|
|
27
|
+
oidcBase: string;
|
|
28
|
+
}
|
|
29
|
+
export interface SlackOidcIdentity {
|
|
30
|
+
userId: string;
|
|
31
|
+
teamId?: string;
|
|
32
|
+
email?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function readSlackOidcConfig(env?: NodeJS.ProcessEnv): SlackOidcConfig | null;
|
|
35
|
+
export declare function slackConnectUrl(publicAppUrl: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Public base URL for Slack OAuth `redirect_uri` (`…/identity/slack/callback`).
|
|
38
|
+
*
|
|
39
|
+
* Prefer an explicit public Agent Server URL over the ASGI request origin:
|
|
40
|
+
* LangGraph Host rewrites requests to an internal loopback that Slack cannot
|
|
41
|
+
* use as a redirect.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveSlackOauthRedirectBase(options: {
|
|
44
|
+
requestUrl: string;
|
|
45
|
+
headers?: Headers | {
|
|
46
|
+
get(name: string): string | null | undefined;
|
|
47
|
+
};
|
|
48
|
+
deploymentBaseUrl?: string;
|
|
49
|
+
env?: NodeJS.ProcessEnv;
|
|
50
|
+
}): string;
|
|
51
|
+
/** Server-side key for OAuth state JWTs; null when Connect cannot bind actors. */
|
|
52
|
+
export declare function readOauthStateSigningKey(env?: NodeJS.ProcessEnv): string | null;
|
|
53
|
+
export declare function buildSlackAuthorizeUrl(config: SlackOidcConfig, state: string, redirectUri: string): string;
|
|
54
|
+
/** Signed state binding the authenticated actor to the OAuth round-trip. */
|
|
55
|
+
export declare function createSlackOauthState(actorId: string, signingKey: string, nowMs?: number): Promise<string>;
|
|
56
|
+
export declare function verifySlackOauthState(state: string, signingKey: string, nowMs?: number): Promise<{
|
|
57
|
+
actorId: string;
|
|
58
|
+
}>;
|
|
59
|
+
export declare function exchangeSlackOidcCode(config: SlackOidcConfig, code: string, redirectUri: string): Promise<SlackOidcIdentity>;
|
|
60
|
+
//# sourceMappingURL=slack-oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-oauth.d.ts","sourceRoot":"","sources":["../../src/identity/slack-oauth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AACrD,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAC7D,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AACjD,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAC3D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,0BAA0B,CAAC;AAEnE,wCAAwC;AACxC,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAMrD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,eAAe,GAAG,IAAI,CAmBxB;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,GAAG;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;KAAE,CAAC;IACrE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,MAAM,CAcT;AAqCD,kFAAkF;AAClF,wBAAgB,wBAAwB,CACtC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,IAAI,CAGf;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,MAAM,CAWR;AAED,4EAA4E;AAC5E,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAmB,GACzB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAmB,GACzB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB9B;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAsD5B"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack OpenID Connect helpers for Connect-with-Slack account linking.
|
|
3
|
+
*/
|
|
4
|
+
import { randomBytes } from "node:crypto";
|
|
5
|
+
import { jwtVerify, SignJWT } from "jose";
|
|
6
|
+
export const SLACK_CLIENT_ID_ENV = "SLACK_CLIENT_ID";
|
|
7
|
+
export const SLACK_CLIENT_SECRET_ENV = "SLACK_CLIENT_SECRET";
|
|
8
|
+
export const SLACK_TEAM_ID_ENV = "SLACK_TEAM_ID";
|
|
9
|
+
export const MDA_PUBLIC_APP_URL_ENV = "MDA_PUBLIC_APP_URL";
|
|
10
|
+
/**
|
|
11
|
+
* Public Agent Server base URL used for Slack OAuth `redirect_uri`.
|
|
12
|
+
* Required on LangGraph Host where the ASGI request origin is an internal
|
|
13
|
+
* loopback (e.g. `http://localhost:5557`) rather than `*.langgraph.app`.
|
|
14
|
+
*/
|
|
15
|
+
export const MDA_PUBLIC_API_URL_ENV = "MDA_PUBLIC_API_URL";
|
|
16
|
+
/**
|
|
17
|
+
* Signing key for OAuth `state` JWTs (Connect-with-Slack). Reuses the guest
|
|
18
|
+
* token key so deployments do not need a third secret; never the Slack
|
|
19
|
+
* client secret (that value is an OAuth credential, not a signing key).
|
|
20
|
+
*/
|
|
21
|
+
export const OAUTH_STATE_SIGNING_KEY_ENV = "MDA_GUEST_SIGNING_KEY";
|
|
22
|
+
/** Override Slack OIDC base (tests). */
|
|
23
|
+
export const SLACK_OIDC_BASE_ENV = "SLACK_OIDC_BASE";
|
|
24
|
+
const DEFAULT_OIDC_BASE = "https://slack.com";
|
|
25
|
+
const STATE_TTL_MS = 10 * 60 * 1000;
|
|
26
|
+
const STATE_JWT_TYP = "mda-slack-oauth-state";
|
|
27
|
+
export function readSlackOidcConfig(env = process.env) {
|
|
28
|
+
const clientId = env[SLACK_CLIENT_ID_ENV]?.trim();
|
|
29
|
+
const clientSecret = env[SLACK_CLIENT_SECRET_ENV]?.trim();
|
|
30
|
+
const publicAppUrl = env[MDA_PUBLIC_APP_URL_ENV]?.trim();
|
|
31
|
+
if (!clientId || !clientSecret || !publicAppUrl) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
clientId,
|
|
36
|
+
clientSecret,
|
|
37
|
+
...(env[SLACK_TEAM_ID_ENV]?.trim()
|
|
38
|
+
? { teamId: env[SLACK_TEAM_ID_ENV].trim() }
|
|
39
|
+
: {}),
|
|
40
|
+
publicAppUrl: publicAppUrl.replace(/\/$/, ""),
|
|
41
|
+
oidcBase: (env[SLACK_OIDC_BASE_ENV]?.trim() || DEFAULT_OIDC_BASE).replace(/\/$/, ""),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function slackConnectUrl(publicAppUrl) {
|
|
45
|
+
return `${publicAppUrl.replace(/\/$/, "")}/settings`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Public base URL for Slack OAuth `redirect_uri` (`…/identity/slack/callback`).
|
|
49
|
+
*
|
|
50
|
+
* Prefer an explicit public Agent Server URL over the ASGI request origin:
|
|
51
|
+
* LangGraph Host rewrites requests to an internal loopback that Slack cannot
|
|
52
|
+
* use as a redirect.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveSlackOauthRedirectBase(options) {
|
|
55
|
+
const env = options.env ?? process.env;
|
|
56
|
+
if (options.deploymentBaseUrl?.trim()) {
|
|
57
|
+
return options.deploymentBaseUrl.trim().replace(/\/$/, "");
|
|
58
|
+
}
|
|
59
|
+
const fromEnv = env[MDA_PUBLIC_API_URL_ENV]?.trim().replace(/\/$/, "");
|
|
60
|
+
if (fromEnv && !isLoopbackUrl(fromEnv)) {
|
|
61
|
+
return fromEnv;
|
|
62
|
+
}
|
|
63
|
+
const forwarded = publicOriginFromForwardedHeaders(options.headers);
|
|
64
|
+
if (forwarded) {
|
|
65
|
+
return forwarded;
|
|
66
|
+
}
|
|
67
|
+
return new URL(options.requestUrl).origin;
|
|
68
|
+
}
|
|
69
|
+
function publicOriginFromForwardedHeaders(headers) {
|
|
70
|
+
if (!headers) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const host = headers.get("x-forwarded-host")?.split(",")[0]?.trim();
|
|
74
|
+
if (!host || isLoopbackHost(host)) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const proto = headers.get("x-forwarded-proto")?.split(",")[0]?.trim() ||
|
|
78
|
+
(host.includes("localhost") || host.startsWith("127.") ? "http" : "https");
|
|
79
|
+
return `${proto}://${host}`;
|
|
80
|
+
}
|
|
81
|
+
function isLoopbackUrl(value) {
|
|
82
|
+
try {
|
|
83
|
+
return isLoopbackHost(new URL(value).hostname);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function isLoopbackHost(host) {
|
|
90
|
+
const hostname = host
|
|
91
|
+
.replace(/^\[|\]$/g, "")
|
|
92
|
+
.split(":")[0]
|
|
93
|
+
?.toLowerCase() ?? "";
|
|
94
|
+
return (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1");
|
|
95
|
+
}
|
|
96
|
+
/** Server-side key for OAuth state JWTs; null when Connect cannot bind actors. */
|
|
97
|
+
export function readOauthStateSigningKey(env = process.env) {
|
|
98
|
+
const key = env[OAUTH_STATE_SIGNING_KEY_ENV]?.trim();
|
|
99
|
+
return key || null;
|
|
100
|
+
}
|
|
101
|
+
export function buildSlackAuthorizeUrl(config, state, redirectUri) {
|
|
102
|
+
const url = new URL(`${config.oidcBase}/openid/connect/authorize`);
|
|
103
|
+
url.searchParams.set("response_type", "code");
|
|
104
|
+
url.searchParams.set("client_id", config.clientId);
|
|
105
|
+
url.searchParams.set("scope", "openid email profile");
|
|
106
|
+
url.searchParams.set("redirect_uri", redirectUri);
|
|
107
|
+
url.searchParams.set("state", state);
|
|
108
|
+
if (config.teamId) {
|
|
109
|
+
url.searchParams.set("team", config.teamId);
|
|
110
|
+
}
|
|
111
|
+
return url.toString();
|
|
112
|
+
}
|
|
113
|
+
/** Signed state binding the authenticated actor to the OAuth round-trip. */
|
|
114
|
+
export async function createSlackOauthState(actorId, signingKey, nowMs = Date.now()) {
|
|
115
|
+
const iat = Math.floor(nowMs / 1000);
|
|
116
|
+
const exp = Math.floor((nowMs + STATE_TTL_MS) / 1000);
|
|
117
|
+
return new SignJWT({
|
|
118
|
+
actorId,
|
|
119
|
+
nonce: randomBytes(16).toString("hex"),
|
|
120
|
+
})
|
|
121
|
+
.setProtectedHeader({ alg: "HS256", typ: STATE_JWT_TYP })
|
|
122
|
+
.setIssuedAt(iat)
|
|
123
|
+
.setExpirationTime(exp)
|
|
124
|
+
.sign(stateSigningKey(signingKey));
|
|
125
|
+
}
|
|
126
|
+
export async function verifySlackOauthState(state, signingKey, nowMs = Date.now()) {
|
|
127
|
+
try {
|
|
128
|
+
const { payload } = await jwtVerify(state, stateSigningKey(signingKey), {
|
|
129
|
+
algorithms: ["HS256"],
|
|
130
|
+
typ: STATE_JWT_TYP,
|
|
131
|
+
currentDate: new Date(nowMs),
|
|
132
|
+
});
|
|
133
|
+
if (typeof payload.actorId !== "string" || !payload.actorId) {
|
|
134
|
+
throw new Error("invalid OAuth state actor");
|
|
135
|
+
}
|
|
136
|
+
return { actorId: payload.actorId };
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
if (err instanceof Error && err.message.startsWith("invalid OAuth state")) {
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
143
|
+
if (/exp|expir/i.test(message)) {
|
|
144
|
+
throw new Error("OAuth state expired");
|
|
145
|
+
}
|
|
146
|
+
throw new Error("invalid OAuth state signature");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export async function exchangeSlackOidcCode(config, code, redirectUri) {
|
|
150
|
+
const tokenUrl = `${config.oidcBase}/api/openid.connect.token`;
|
|
151
|
+
const body = new URLSearchParams({
|
|
152
|
+
client_id: config.clientId,
|
|
153
|
+
client_secret: config.clientSecret,
|
|
154
|
+
code,
|
|
155
|
+
redirect_uri: redirectUri,
|
|
156
|
+
grant_type: "authorization_code",
|
|
157
|
+
});
|
|
158
|
+
const tokenResponse = await fetch(tokenUrl, {
|
|
159
|
+
method: "POST",
|
|
160
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
161
|
+
body,
|
|
162
|
+
});
|
|
163
|
+
const tokenJson = (await tokenResponse.json());
|
|
164
|
+
if (!tokenResponse.ok || tokenJson.ok === false || !tokenJson.access_token) {
|
|
165
|
+
throw new Error(tokenJson.error ?? "Slack OIDC token exchange failed");
|
|
166
|
+
}
|
|
167
|
+
const userInfoUrl = `${config.oidcBase}/api/openid.connect.userInfo`;
|
|
168
|
+
const userResponse = await fetch(userInfoUrl, {
|
|
169
|
+
headers: { Authorization: `Bearer ${tokenJson.access_token}` },
|
|
170
|
+
});
|
|
171
|
+
const userJson = (await userResponse.json());
|
|
172
|
+
if (!userResponse.ok || userJson.ok === false) {
|
|
173
|
+
throw new Error(userJson.error ?? "Slack OIDC userInfo failed");
|
|
174
|
+
}
|
|
175
|
+
const userId = userJson["https://slack.com/user_id"] ??
|
|
176
|
+
(typeof userJson.sub === "string"
|
|
177
|
+
? userJson.sub.split("|").pop()
|
|
178
|
+
: undefined);
|
|
179
|
+
if (!userId) {
|
|
180
|
+
throw new Error("Slack OIDC userInfo missing user id");
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
userId,
|
|
184
|
+
...(userJson["https://slack.com/team_id"]
|
|
185
|
+
? { teamId: userJson["https://slack.com/team_id"] }
|
|
186
|
+
: {}),
|
|
187
|
+
...(typeof userJson.email === "string" ? { email: userJson.email } : {}),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function stateSigningKey(signingKey) {
|
|
191
|
+
return new TextEncoder().encode(signingKey);
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=slack-oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack-oauth.js","sourceRoot":"","sources":["../../src/identity/slack-oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,10 +5,15 @@ export type { LangSmithCapability, LangSmithCallerSurface, LangSmithCapabilitySc
|
|
|
5
5
|
export { defineSchedule } from "./schedules.js";
|
|
6
6
|
export { defineSandbox } from "./sandbox.js";
|
|
7
7
|
export { defineIdentity, providers, validateIdentity, } from "./identity/index.js";
|
|
8
|
+
export { defineSlackChannel } from "./channels/slack/index.js";
|
|
9
|
+
export { CHANNEL_ERROR_CODES, ChannelError, createRuntimeChannel, normalizeChannelDestination, wasFinalPosted, } from "./channels/index.js";
|
|
10
|
+
export { decodeSlackSourceThreadKey, encodeSlackSourceThreadKey, normalizeSlackEvent, requiredSlackScopes, toChannelManifest, verifySlackRequest, } from "./channels/slack/index.js";
|
|
8
11
|
export type { CredentialResolver, CredentialResolverConfig, CredentialScope, CredentialTarget, DefineIdentity, HttpIngress, IdentityConfig, IdentityDefinition, IdentityPresetName, MemoryScope, ResolvedCredential, RuntimeIdentity, Tenancy, ThreadScope, ValidatedTokenIngress, ValidatedTokenProvider, } from "./identity/index.js";
|
|
9
12
|
export type { HttpMcpServerConfig, McpServersConfig, McpServersDefinition, McpToolSelectionConfig, RemoteMcpServerBaseConfig, RemoteMcpServerConfig, SseMcpServerConfig, } from "./connectors.js";
|
|
10
13
|
export type { ScheduleConfig, ScheduleDefinition, ScheduleDeliveryTarget, ScheduleThreadConfig, } from "./schedules.js";
|
|
11
|
-
export type { ChannelDestination,
|
|
14
|
+
export type { ChannelAddress, ChannelCapabilities, ChannelDestination, ChannelErrorCode, ChannelEvent, ChannelMessage, ChannelMessageUpdate, ChannelProvider, PostedChannelMessage, RuntimeChannel, } from "./channels/index.js";
|
|
15
|
+
export type { ChannelManifest, SlackChannelConfig, SlackChannelDefinition, SlackChannelTrigger, } from "./channels/slack/index.js";
|
|
16
|
+
export type { DeepAgentDefinition, DefineDeepAgentConfig, InferConfigMiddlewareState, InferConfigStateSchema, ManagedDeepAgentKey, } from "./types.js";
|
|
12
17
|
export type { ManagedDeepAgentRuntime, ManagedRuntimeExtras, } from "./runtime/managed-tools.js";
|
|
13
18
|
export type { DefineSandboxOptions, ManagedSandboxOptionKey, SandboxDefinition, SandboxProviderClass, SandboxProviderOptions, SandboxScope, } from "./sandbox.js";
|
|
14
19
|
//# sourceMappingURL=index.d.ts.map
|