@squadbase/vite-server 0.1.17-dev.e4768d1 → 0.1.18
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/cli/index.js +333 -49
- package/dist/connectors/google-analytics-oauth.js +1 -1
- package/dist/connectors/google-calendar-oauth.js +1 -1
- package/dist/connectors/hackernews.js +1 -1
- package/dist/connectors/slack.d.ts +5 -0
- package/dist/connectors/slack.js +656 -0
- package/dist/connectors/x.js +1 -1
- package/dist/index.js +333 -49
- package/dist/main.js +333 -49
- package/dist/vite-plugin.js +333 -49
- package/package.json +5 -1
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
// ../connectors/src/connectors/slack/sdk/index.ts
|
|
2
|
+
var BASE_URL = "https://slack.com/api";
|
|
3
|
+
function createClient(_params, fetchFn = fetch) {
|
|
4
|
+
function request(path2, init) {
|
|
5
|
+
const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
6
|
+
const headers = new Headers(init?.headers);
|
|
7
|
+
if (init?.body && !headers.has("Content-Type")) {
|
|
8
|
+
headers.set("Content-Type", "application/json; charset=utf-8");
|
|
9
|
+
}
|
|
10
|
+
return fetchFn(url, { ...init, headers });
|
|
11
|
+
}
|
|
12
|
+
return { request };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ../connectors/src/connector-onboarding.ts
|
|
16
|
+
var ConnectorOnboarding = class {
|
|
17
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
18
|
+
connectionSetupInstructions;
|
|
19
|
+
/** Phase 2: Data overview instructions */
|
|
20
|
+
dataOverviewInstructions;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
23
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
24
|
+
}
|
|
25
|
+
getConnectionSetupPrompt(language) {
|
|
26
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
27
|
+
}
|
|
28
|
+
getDataOverviewInstructions(language) {
|
|
29
|
+
return this.dataOverviewInstructions[language];
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ../connectors/src/connector-tool.ts
|
|
34
|
+
var ConnectorTool = class {
|
|
35
|
+
name;
|
|
36
|
+
description;
|
|
37
|
+
inputSchema;
|
|
38
|
+
outputSchema;
|
|
39
|
+
_execute;
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.name = config.name;
|
|
42
|
+
this.description = config.description;
|
|
43
|
+
this.inputSchema = config.inputSchema;
|
|
44
|
+
this.outputSchema = config.outputSchema;
|
|
45
|
+
this._execute = config.execute;
|
|
46
|
+
}
|
|
47
|
+
createTool(connections, config) {
|
|
48
|
+
return {
|
|
49
|
+
description: this.description,
|
|
50
|
+
inputSchema: this.inputSchema,
|
|
51
|
+
outputSchema: this.outputSchema,
|
|
52
|
+
execute: (input) => this._execute(input, connections, config)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// ../connectors/src/connector-plugin.ts
|
|
58
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
59
|
+
slug;
|
|
60
|
+
authType;
|
|
61
|
+
name;
|
|
62
|
+
description;
|
|
63
|
+
iconUrl;
|
|
64
|
+
parameters;
|
|
65
|
+
releaseFlag;
|
|
66
|
+
proxyPolicy;
|
|
67
|
+
experimentalAttributes;
|
|
68
|
+
categories;
|
|
69
|
+
onboarding;
|
|
70
|
+
systemPrompt;
|
|
71
|
+
tools;
|
|
72
|
+
query;
|
|
73
|
+
checkConnection;
|
|
74
|
+
/**
|
|
75
|
+
* SQPD-1212: Logic-based, rule-driven connection setup. Connectors that
|
|
76
|
+
* implement this expose a step-by-step exploration flow (database/schema/
|
|
77
|
+
* table/etc. discovery) that the dashboard backend drives via the
|
|
78
|
+
* `/connections/:connectionId/setup` endpoint. Implement by delegating to
|
|
79
|
+
* `runSetupFlow` from `setup-flow.ts`.
|
|
80
|
+
*/
|
|
81
|
+
setup;
|
|
82
|
+
/**
|
|
83
|
+
* 統一 introspection。SQL DB の `information_schema` / `SHOW` / `DESCRIBE` や SaaS の
|
|
84
|
+
* メタデータ API といった取得経路の差を吸収し、tables / columns / PK / FK を共通型
|
|
85
|
+
* {@link IntrospectedSchema} へ正規化して返す。取得経路は {@link IntrospectContext} で
|
|
86
|
+
* 抽象化され、SQL DB は `ctx.query`、SaaS は `ctx.proxyFetch` + `ctx.params` を使う。
|
|
87
|
+
* `ctx.profile === true` のときは L2 プロファイル(行数・NULL 率等)も best-effort で埋める。
|
|
88
|
+
* coding-agent の `DataContextIndex` がデータ地図を構築する際に使う。
|
|
89
|
+
*/
|
|
90
|
+
introspect;
|
|
91
|
+
/**
|
|
92
|
+
* Opt-out of the default "verify before save" behavior on connection
|
|
93
|
+
* creation. The backend invokes `checkConnection` synchronously while
|
|
94
|
+
* creating the connection and aborts (no row inserted) if it fails — this
|
|
95
|
+
* flag disables that for connectors where the check cannot succeed pre-save:
|
|
96
|
+
*
|
|
97
|
+
* - `squadbase-db` populates `connection-url` only after Neon provisioning
|
|
98
|
+
* - OAuth connectors require an OAuth-aware proxyFetch keyed by the
|
|
99
|
+
* connectionId, which doesn't exist until the row is saved
|
|
100
|
+
*
|
|
101
|
+
* Exceptions are the explicit position; new credential-input connectors get
|
|
102
|
+
* the default verify-on-create behavior without opt-in.
|
|
103
|
+
*/
|
|
104
|
+
skipConnectionCheckOnCreate;
|
|
105
|
+
/**
|
|
106
|
+
* 決定論的な「立ち上げ survey」レシピ(ルールベース prewarm 基盤)。実装した connector は、LLM を使わずに
|
|
107
|
+
* read-only で自分を survey する probe 列(テーブル/列メタデータ → 小サンプル)を宣言する。coding-agent の
|
|
108
|
+
* recon driver がこれを読み、connector ツールの `execute` を直接呼んで結果を seed にする。未実装の connector は
|
|
109
|
+
* driver 側で safely skip される(その connection は listConnections のみ seed)。標準 `information_schema` を
|
|
110
|
+
* 持つ SQL connector は `makeStandardSqlSurveyProbes` を使える。**probe は必ず read-only**。
|
|
111
|
+
*/
|
|
112
|
+
surveyProbes;
|
|
113
|
+
constructor(config) {
|
|
114
|
+
this.slug = config.slug;
|
|
115
|
+
this.authType = config.authType;
|
|
116
|
+
this.name = config.name;
|
|
117
|
+
this.description = config.description;
|
|
118
|
+
this.iconUrl = config.iconUrl;
|
|
119
|
+
this.parameters = config.parameters;
|
|
120
|
+
this.releaseFlag = config.releaseFlag;
|
|
121
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
122
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
123
|
+
this.categories = config.categories ?? [];
|
|
124
|
+
this.onboarding = config.onboarding;
|
|
125
|
+
this.systemPrompt = config.systemPrompt;
|
|
126
|
+
this.tools = config.tools;
|
|
127
|
+
this.query = config.query;
|
|
128
|
+
this.checkConnection = config.checkConnection;
|
|
129
|
+
this.setup = config.setup;
|
|
130
|
+
this.introspect = config.introspect;
|
|
131
|
+
this.skipConnectionCheckOnCreate = config.skipConnectionCheckOnCreate;
|
|
132
|
+
this.surveyProbes = config.surveyProbes;
|
|
133
|
+
}
|
|
134
|
+
get connectorKey() {
|
|
135
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create tools for connections that belong to this connector.
|
|
139
|
+
* Filters connections by connectorKey internally.
|
|
140
|
+
* Returns tools keyed as `connector_${connectorKey}_${toolName}`.
|
|
141
|
+
*/
|
|
142
|
+
createTools(connections, config, opts) {
|
|
143
|
+
const myConnections = connections.filter(
|
|
144
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
145
|
+
);
|
|
146
|
+
const result = {};
|
|
147
|
+
for (const t of Object.values(this.tools)) {
|
|
148
|
+
const tool = t.createTool(myConnections, config);
|
|
149
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
150
|
+
result[`connector_${this.connectorKey}_${t.name}`] = {
|
|
151
|
+
...tool,
|
|
152
|
+
toModelOutput: async (options) => {
|
|
153
|
+
if (!originalToModelOutput) {
|
|
154
|
+
return opts.truncateOutput(options.output);
|
|
155
|
+
}
|
|
156
|
+
const modelOutput = await originalToModelOutput(options);
|
|
157
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
158
|
+
return opts.truncateOutput(modelOutput.value);
|
|
159
|
+
}
|
|
160
|
+
return modelOutput;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
static deriveKey(slug, authType) {
|
|
167
|
+
if (authType) return `${slug}-${authType}`;
|
|
168
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
169
|
+
// user-password
|
|
170
|
+
postgresql: "user-password",
|
|
171
|
+
mysql: "user-password",
|
|
172
|
+
clickhouse: "user-password",
|
|
173
|
+
kintone: "user-password",
|
|
174
|
+
"squadbase-db": "user-password",
|
|
175
|
+
// service-account
|
|
176
|
+
snowflake: "service-account",
|
|
177
|
+
bigquery: "service-account",
|
|
178
|
+
"google-analytics": "service-account",
|
|
179
|
+
"google-calendar": "service-account",
|
|
180
|
+
"aws-athena": "service-account",
|
|
181
|
+
redshift: "service-account",
|
|
182
|
+
// api-key
|
|
183
|
+
databricks: "api-key",
|
|
184
|
+
dbt: "api-key",
|
|
185
|
+
airtable: "api-key",
|
|
186
|
+
openai: "api-key",
|
|
187
|
+
gemini: "api-key",
|
|
188
|
+
anthropic: "api-key",
|
|
189
|
+
"wix-store": "api-key"
|
|
190
|
+
};
|
|
191
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
192
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
193
|
+
return slug;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// ../connectors/src/auth-types.ts
|
|
198
|
+
var AUTH_TYPES = {
|
|
199
|
+
OAUTH: "oauth",
|
|
200
|
+
API_KEY: "api-key",
|
|
201
|
+
JWT: "jwt",
|
|
202
|
+
SERVICE_ACCOUNT: "service-account",
|
|
203
|
+
PAT: "pat",
|
|
204
|
+
USER_PASSWORD: "user-password"
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
// ../connectors/src/connectors/slack/tools/request.ts
|
|
208
|
+
import { z } from "zod";
|
|
209
|
+
var BASE_URL2 = "https://slack.com/api";
|
|
210
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
211
|
+
var cachedToken = null;
|
|
212
|
+
async function getProxyToken(config) {
|
|
213
|
+
if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
|
|
214
|
+
return cachedToken.token;
|
|
215
|
+
}
|
|
216
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
217
|
+
const res = await fetch(url, {
|
|
218
|
+
method: "POST",
|
|
219
|
+
headers: {
|
|
220
|
+
"Content-Type": "application/json",
|
|
221
|
+
"x-api-key": config.appApiKey,
|
|
222
|
+
"project-id": config.projectId
|
|
223
|
+
},
|
|
224
|
+
body: JSON.stringify({
|
|
225
|
+
sandboxId: config.sandboxId,
|
|
226
|
+
issuedBy: "coding-agent"
|
|
227
|
+
})
|
|
228
|
+
});
|
|
229
|
+
if (!res.ok) {
|
|
230
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
const data = await res.json();
|
|
236
|
+
cachedToken = {
|
|
237
|
+
token: data.token,
|
|
238
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
239
|
+
};
|
|
240
|
+
return data.token;
|
|
241
|
+
}
|
|
242
|
+
var inputSchema = z.object({
|
|
243
|
+
toolUseIntent: z.string().optional().describe(
|
|
244
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
245
|
+
),
|
|
246
|
+
connectionId: z.string().describe("ID of the Slack connection to use"),
|
|
247
|
+
method: z.enum(["GET", "POST"]).describe("HTTP method"),
|
|
248
|
+
path: z.string().describe(
|
|
249
|
+
"API method path appended to https://slack.com/api, including query parameters (e.g., '/conversations.list?types=public_channel,private_channel&limit=200', '/conversations.history?channel=C0123456789&limit=50')"
|
|
250
|
+
),
|
|
251
|
+
body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST requests")
|
|
252
|
+
});
|
|
253
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
254
|
+
z.object({
|
|
255
|
+
success: z.literal(true),
|
|
256
|
+
status: z.number(),
|
|
257
|
+
data: z.record(z.string(), z.unknown())
|
|
258
|
+
}),
|
|
259
|
+
z.object({
|
|
260
|
+
success: z.literal(false),
|
|
261
|
+
error: z.string()
|
|
262
|
+
})
|
|
263
|
+
]);
|
|
264
|
+
var requestTool = new ConnectorTool({
|
|
265
|
+
name: "request",
|
|
266
|
+
description: `Send authenticated requests to the Slack Web API.
|
|
267
|
+
Authentication is handled automatically via OAuth proxy using the authorizing user's token, so results reflect what that user can see in Slack (public channels plus private channels/DMs they are a member of).
|
|
268
|
+
Use this tool for all Slack API interactions: listing channels, reading channel message history, reading thread replies, and resolving user names.
|
|
269
|
+
Pagination is cursor-based: pass 'cursor' from 'response_metadata.next_cursor' of the previous response. Message timestamps ('ts', 'oldest', 'latest') are Unix epoch seconds as strings.`,
|
|
270
|
+
inputSchema,
|
|
271
|
+
outputSchema,
|
|
272
|
+
async execute({ connectionId, method, path: path2, body }, connections, config) {
|
|
273
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
274
|
+
if (!connection2) {
|
|
275
|
+
return {
|
|
276
|
+
success: false,
|
|
277
|
+
error: `Connection ${connectionId} not found`
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
console.log(
|
|
281
|
+
`[connector-request] slack/${connection2.name}: ${method} ${path2}`
|
|
282
|
+
);
|
|
283
|
+
try {
|
|
284
|
+
const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
285
|
+
const token = await getProxyToken(config.oauthProxy);
|
|
286
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
287
|
+
const controller = new AbortController();
|
|
288
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
289
|
+
try {
|
|
290
|
+
const response = await fetch(proxyUrl, {
|
|
291
|
+
method: "POST",
|
|
292
|
+
headers: {
|
|
293
|
+
"Content-Type": "application/json",
|
|
294
|
+
Authorization: `Bearer ${token}`
|
|
295
|
+
},
|
|
296
|
+
body: JSON.stringify({
|
|
297
|
+
url,
|
|
298
|
+
method,
|
|
299
|
+
headers: method === "POST" ? { "Content-Type": "application/json; charset=utf-8" } : {},
|
|
300
|
+
body: body ? JSON.stringify(body) : void 0
|
|
301
|
+
}),
|
|
302
|
+
signal: controller.signal
|
|
303
|
+
});
|
|
304
|
+
const data = await response.json();
|
|
305
|
+
if (!response.ok || data.ok === false) {
|
|
306
|
+
const errorMessage = typeof data?.error === "string" ? data.error : `HTTP ${response.status} ${response.statusText}`;
|
|
307
|
+
return { success: false, error: errorMessage };
|
|
308
|
+
}
|
|
309
|
+
return { success: true, status: response.status, data };
|
|
310
|
+
} finally {
|
|
311
|
+
clearTimeout(timeout);
|
|
312
|
+
}
|
|
313
|
+
} catch (err) {
|
|
314
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
315
|
+
return { success: false, error: msg };
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ../connectors/src/connectors/slack/setup.ts
|
|
321
|
+
var requestToolName = `slack-oauth_${requestTool.name}`;
|
|
322
|
+
var slackOnboarding = new ConnectorOnboarding({
|
|
323
|
+
connectionSetupInstructions: {
|
|
324
|
+
ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067Slack\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
|
|
325
|
+
|
|
326
|
+
1. \`${requestToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u3001\u8A8D\u53EF\u3057\u305F\u30E6\u30FC\u30B6\u30FC\u3068\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3092\u78BA\u8A8D\u3059\u308B:
|
|
327
|
+
- \`method\`: \`"POST"\`
|
|
328
|
+
- \`path\`: \`"/auth.test"\`
|
|
329
|
+
2. \u30A8\u30E9\u30FC\u304C\u8FD4\u3055\u308C\u305F\u5834\u5408\u3001\u30E6\u30FC\u30B6\u30FC\u306BOAuth\u63A5\u7D9A\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3059\u308B\u3088\u3046\u4F1D\u3048\u308B
|
|
330
|
+
|
|
331
|
+
#### \u5236\u7D04
|
|
332
|
+
- **\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u30E1\u30C3\u30BB\u30FC\u30B8\u672C\u6587\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068**\u3002\u5B9F\u884C\u3057\u3066\u3088\u3044\u306E\u306F\u4E0A\u8A18\u624B\u9806\u3067\u6307\u5B9A\u3055\u308C\u305F\u8A8D\u8A3C\u78BA\u8A8D\u30EA\u30AF\u30A8\u30B9\u30C8\u306E\u307F
|
|
333
|
+
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u3002\u4E0D\u8981\u306A\u8AAC\u660E\u306F\u7701\u7565\u3057\u3001\u52B9\u7387\u7684\u306B\u9032\u3081\u308B`,
|
|
334
|
+
en: `Follow these steps to set up the Slack connection.
|
|
335
|
+
|
|
336
|
+
1. Call \`${requestToolName}\` to verify the authorizing user and workspace:
|
|
337
|
+
- \`method\`: \`"POST"\`
|
|
338
|
+
- \`path\`: \`"/auth.test"\`
|
|
339
|
+
2. If an error is returned, ask the user to check the OAuth connection settings
|
|
340
|
+
|
|
341
|
+
#### Constraints
|
|
342
|
+
- **Do NOT read message contents during setup**. Only the auth verification request specified in the steps above is allowed
|
|
343
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool. Skip unnecessary explanations and proceed efficiently`
|
|
344
|
+
},
|
|
345
|
+
dataOverviewInstructions: {
|
|
346
|
+
en: `1. Call connector_slack-oauth_request with GET /conversations.list?types=public_channel,private_channel&exclude_archived=true&limit=100 to discover channels visible to the authorizing user
|
|
347
|
+
2. For 2-3 channels relevant to the analysis, call connector_slack-oauth_request with GET /conversations.history?channel={channel_id}&limit=10 to sample recent messages
|
|
348
|
+
3. Call connector_slack-oauth_request with GET /users.list?limit=100 to map user IDs to display names
|
|
349
|
+
4. For threads worth exploring, call connector_slack-oauth_request with GET /conversations.replies?channel={channel_id}&ts={thread_ts} as needed`,
|
|
350
|
+
ja: `1. connector_slack-oauth_request \u3067 GET /conversations.list?types=public_channel,private_channel&exclude_archived=true&limit=100 \u3092\u547C\u3073\u51FA\u3057\u3001\u8A8D\u53EF\u30E6\u30FC\u30B6\u30FC\u304C\u898B\u3048\u308B\u30C1\u30E3\u30F3\u30CD\u30EB\u3092\u691C\u51FA
|
|
351
|
+
2. \u5206\u6790\u5BFE\u8C61\u306B\u306A\u308A\u305D\u3046\u306A2\u301C3\u30C1\u30E3\u30F3\u30CD\u30EB\u306B\u3064\u3044\u3066\u3001connector_slack-oauth_request \u3067 GET /conversations.history?channel={channel_id}&limit=10 \u3092\u547C\u3073\u51FA\u3057\u3001\u76F4\u8FD1\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0
|
|
352
|
+
3. connector_slack-oauth_request \u3067 GET /users.list?limit=100 \u3092\u547C\u3073\u51FA\u3057\u3001\u30E6\u30FC\u30B6\u30FCID\u3068\u8868\u793A\u540D\u306E\u5BFE\u5FDC\u3092\u53D6\u5F97
|
|
353
|
+
4. \u5FC5\u8981\u306B\u5FDC\u3058\u3066 GET /conversations.replies?channel={channel_id}&ts={thread_ts} \u3067\u30B9\u30EC\u30C3\u30C9\u3092\u63A2\u7D22`
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// ../connectors/src/connectors/slack/parameters.ts
|
|
358
|
+
var parameters = {};
|
|
359
|
+
|
|
360
|
+
// ../connectors/src/connectors/slack/index.ts
|
|
361
|
+
var tools = { request: requestTool };
|
|
362
|
+
var slackConnector = new ConnectorPlugin({
|
|
363
|
+
slug: "slack",
|
|
364
|
+
authType: AUTH_TYPES.OAUTH,
|
|
365
|
+
skipConnectionCheckOnCreate: true,
|
|
366
|
+
name: "Slack",
|
|
367
|
+
description: "Connect to Slack to analyze channel messages and threads using OAuth. Reads run with the authorizing user's permissions.",
|
|
368
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/75UXS4Ll04liDJiPYKb7gN/eccc8a5e9700174685f7aa3cb23f2830/2111615.png",
|
|
369
|
+
parameters,
|
|
370
|
+
releaseFlag: { dev1: true, dev2: true, prod: false },
|
|
371
|
+
categories: ["productivity"],
|
|
372
|
+
onboarding: slackOnboarding,
|
|
373
|
+
proxyPolicy: {
|
|
374
|
+
allowlist: [
|
|
375
|
+
{
|
|
376
|
+
host: "slack.com",
|
|
377
|
+
methods: ["GET", "POST"]
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
},
|
|
381
|
+
systemPrompt: {
|
|
382
|
+
en: `### Tools
|
|
383
|
+
|
|
384
|
+
- \`connector_slack-oauth_request\`: The only way to call the Slack Web API. Use it to list channels, read channel message history, read thread replies, and resolve user names. Authentication is configured automatically via OAuth with the authorizing user's token \u2014 results reflect what that user can see in Slack (public channels plus private channels they are a member of). Pagination is cursor-based: pass \`cursor\` from \`response_metadata.next_cursor\`.
|
|
385
|
+
|
|
386
|
+
### Slack Web API Reference
|
|
387
|
+
|
|
388
|
+
#### Available Endpoints
|
|
389
|
+
- GET \`/conversations.list?types=public_channel,private_channel&exclude_archived=true&limit=200\` \u2014 List channels visible to the user. Returns \`channels[]\` with \`id\`, \`name\`, \`is_private\`
|
|
390
|
+
- GET \`/conversations.history?channel={id}&limit=50\` \u2014 Channel messages, newest first. Optional: \`oldest\` / \`latest\` (Unix epoch seconds as strings), \`cursor\`. Returns \`messages[]\` with \`user\`, \`ts\`, \`text\`, \`thread_ts\`, \`reply_count\`
|
|
391
|
+
- GET \`/conversations.replies?channel={id}&ts={thread_ts}&limit=50\` \u2014 Messages in a thread (the parent message's \`ts\` is the \`thread_ts\`)
|
|
392
|
+
- GET \`/users.list?limit=200\` \u2014 Workspace members. Returns \`members[]\` with \`id\`, \`name\`, \`real_name\`, \`profile.display_name\`
|
|
393
|
+
- GET \`/users.info?user={id}\` \u2014 Single user detail
|
|
394
|
+
- POST \`/auth.test\` \u2014 Verify the connection; returns the authorizing user and workspace
|
|
395
|
+
|
|
396
|
+
### Tips
|
|
397
|
+
- Message \`ts\` values are Unix epoch seconds as strings (e.g. "1712345678.000200") and double as message IDs; convert for date filtering via \`oldest\`/\`latest\`
|
|
398
|
+
- Messages reference users by ID (e.g. "U0123456789") \u2014 resolve display names via /users.list before presenting results
|
|
399
|
+
- A message with \`thread_ts\` equal to its \`ts\` is a thread parent; fetch the thread with /conversations.replies
|
|
400
|
+
- Respect rate limits: prefer \`limit\` + date bounds over paging through entire channel histories
|
|
401
|
+
|
|
402
|
+
### Business Logic
|
|
403
|
+
|
|
404
|
+
The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables.
|
|
405
|
+
|
|
406
|
+
#### Example
|
|
407
|
+
|
|
408
|
+
\`\`\`ts
|
|
409
|
+
import { connection } from "@squadbase/vite-server/connectors/slack";
|
|
410
|
+
|
|
411
|
+
const slack = connection("<connectionId>");
|
|
412
|
+
|
|
413
|
+
// Authenticated fetch (returns standard Response)
|
|
414
|
+
const res = await slack.request(
|
|
415
|
+
"/conversations.history?channel=C0123456789&limit=50",
|
|
416
|
+
);
|
|
417
|
+
const data = await res.json();
|
|
418
|
+
if (!data.ok) throw new Error(data.error);
|
|
419
|
+
\`\`\``,
|
|
420
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
421
|
+
|
|
422
|
+
- \`connector_slack-oauth_request\`: Slack Web API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30C1\u30E3\u30F3\u30CD\u30EB\u4E00\u89A7\u306E\u53D6\u5F97\u3001\u30C1\u30E3\u30F3\u30CD\u30EB\u30E1\u30C3\u30BB\u30FC\u30B8\u5C65\u6B74\u306E\u8AAD\u307F\u53D6\u308A\u3001\u30B9\u30EC\u30C3\u30C9\u8FD4\u4FE1\u306E\u8AAD\u307F\u53D6\u308A\u3001\u30E6\u30FC\u30B6\u30FC\u540D\u306E\u89E3\u6C7A\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\u306F\u8A8D\u53EF\u3057\u305F\u30E6\u30FC\u30B6\u30FC\u306E\u30C8\u30FC\u30AF\u30F3\u306B\u3088\u308BOAuth\u7D4C\u7531\u3067\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u3001\u7D50\u679C\u306F\u305D\u306E\u30E6\u30FC\u30B6\u30FC\u304CSlack\u3067\u898B\u3048\u308B\u7BC4\u56F2\uFF08public\u30C1\u30E3\u30F3\u30CD\u30EB\u3068\u3001\u53C2\u52A0\u3057\u3066\u3044\u308Bprivate\u30C1\u30E3\u30F3\u30CD\u30EB\uFF09\u3092\u53CD\u6620\u3057\u307E\u3059\u3002\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u306F \`response_metadata.next_cursor\` \u306E\u5024\u3092 \`cursor\` \u306B\u6E21\u3059\u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9\u3067\u3059\u3002
|
|
423
|
+
|
|
424
|
+
### Slack Web API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
425
|
+
|
|
426
|
+
#### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
427
|
+
- GET \`/conversations.list?types=public_channel,private_channel&exclude_archived=true&limit=200\` \u2014 \u30E6\u30FC\u30B6\u30FC\u304C\u898B\u3048\u308B\u30C1\u30E3\u30F3\u30CD\u30EB\u4E00\u89A7\u3002\`channels[]\`\uFF08\`id\`, \`name\`, \`is_private\`\uFF09\u3092\u8FD4\u3059
|
|
428
|
+
- GET \`/conversations.history?channel={id}&limit=50\` \u2014 \u30C1\u30E3\u30F3\u30CD\u30EB\u30E1\u30C3\u30BB\u30FC\u30B8\uFF08\u65B0\u3057\u3044\u9806\uFF09\u3002\u30AA\u30D7\u30B7\u30E7\u30F3: \`oldest\` / \`latest\`\uFF08Unix epoch\u79D2\u306E\u6587\u5B57\u5217\uFF09, \`cursor\`\u3002\`messages[]\`\uFF08\`user\`, \`ts\`, \`text\`, \`thread_ts\`, \`reply_count\`\uFF09\u3092\u8FD4\u3059
|
|
429
|
+
- GET \`/conversations.replies?channel={id}&ts={thread_ts}&limit=50\` \u2014 \u30B9\u30EC\u30C3\u30C9\u5185\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\uFF08\u89AA\u30E1\u30C3\u30BB\u30FC\u30B8\u306E \`ts\` \u304C \`thread_ts\`\uFF09
|
|
430
|
+
- GET \`/users.list?limit=200\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30E1\u30F3\u30D0\u30FC\u3002\`members[]\`\uFF08\`id\`, \`name\`, \`real_name\`, \`profile.display_name\`\uFF09\u3092\u8FD4\u3059
|
|
431
|
+
- GET \`/users.info?user={id}\` \u2014 \u5358\u4E00\u30E6\u30FC\u30B6\u30FC\u306E\u8A73\u7D30
|
|
432
|
+
- POST \`/auth.test\` \u2014 \u63A5\u7D9A\u78BA\u8A8D\u3002\u8A8D\u53EF\u30E6\u30FC\u30B6\u30FC\u3068\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3092\u8FD4\u3059
|
|
433
|
+
|
|
434
|
+
### \u30D2\u30F3\u30C8
|
|
435
|
+
- \u30E1\u30C3\u30BB\u30FC\u30B8\u306E \`ts\` \u306FUnix epoch\u79D2\u306E\u6587\u5B57\u5217\uFF08\u4F8B: "1712345678.000200"\uFF09\u3067\u30E1\u30C3\u30BB\u30FC\u30B8ID\u3092\u517C\u306D\u307E\u3059\u3002\u65E5\u4ED8\u30D5\u30A3\u30EB\u30BF\u306F \`oldest\`/\`latest\` \u306B\u5909\u63DB\u3057\u3066\u6E21\u3057\u307E\u3059
|
|
436
|
+
- \u30E1\u30C3\u30BB\u30FC\u30B8\u5185\u306E\u30E6\u30FC\u30B6\u30FC\u306FID\uFF08\u4F8B: "U0123456789"\uFF09\u3067\u53C2\u7167\u3055\u308C\u308B\u305F\u3081\u3001\u7D50\u679C\u3092\u63D0\u793A\u3059\u308B\u524D\u306B /users.list \u3067\u8868\u793A\u540D\u3092\u89E3\u6C7A\u3057\u3066\u304F\u3060\u3055\u3044
|
|
437
|
+
- \`thread_ts\` \u304C\u81EA\u8EAB\u306E \`ts\` \u3068\u7B49\u3057\u3044\u30E1\u30C3\u30BB\u30FC\u30B8\u306F\u30B9\u30EC\u30C3\u30C9\u306E\u89AA\u3067\u3059\u3002/conversations.replies \u3067\u30B9\u30EC\u30C3\u30C9\u3092\u53D6\u5F97\u3067\u304D\u307E\u3059
|
|
438
|
+
- \u30EC\u30FC\u30C8\u30EA\u30DF\u30C3\u30C8\u306B\u914D\u616E\u3057\u3001\u30C1\u30E3\u30F3\u30CD\u30EB\u5C65\u6B74\u5168\u4F53\u306E\u30DA\u30FC\u30B8\u30F3\u30B0\u3088\u308A \`limit\` + \u671F\u9593\u6307\u5B9A\u3092\u512A\u5148\u3057\u3066\u304F\u3060\u3055\u3044
|
|
439
|
+
|
|
440
|
+
### Business Logic
|
|
441
|
+
|
|
442
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
443
|
+
|
|
444
|
+
#### Example
|
|
445
|
+
|
|
446
|
+
\`\`\`ts
|
|
447
|
+
import { connection } from "@squadbase/vite-server/connectors/slack";
|
|
448
|
+
|
|
449
|
+
const slack = connection("<connectionId>");
|
|
450
|
+
|
|
451
|
+
// Authenticated fetch (returns standard Response)
|
|
452
|
+
const res = await slack.request(
|
|
453
|
+
"/conversations.history?channel=C0123456789&limit=50",
|
|
454
|
+
);
|
|
455
|
+
const data = await res.json();
|
|
456
|
+
if (!data.ok) throw new Error(data.error);
|
|
457
|
+
\`\`\``
|
|
458
|
+
},
|
|
459
|
+
tools,
|
|
460
|
+
async checkConnection(_params, config) {
|
|
461
|
+
const { proxyFetch } = config;
|
|
462
|
+
try {
|
|
463
|
+
const res = await proxyFetch("https://slack.com/api/auth.test", {
|
|
464
|
+
method: "POST"
|
|
465
|
+
});
|
|
466
|
+
if (!res.ok) {
|
|
467
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
468
|
+
return {
|
|
469
|
+
success: false,
|
|
470
|
+
error: `Slack API failed: HTTP ${res.status} ${errorText}`
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
const data = await res.json();
|
|
474
|
+
if (data.ok !== true) {
|
|
475
|
+
return {
|
|
476
|
+
success: false,
|
|
477
|
+
error: `Slack auth.test failed: ${data.error ?? "unknown error"}`
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
return { success: true };
|
|
481
|
+
} catch (error) {
|
|
482
|
+
return {
|
|
483
|
+
success: false,
|
|
484
|
+
error: error instanceof Error ? error.message : String(error)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
// src/connectors/create-connector-sdk.ts
|
|
491
|
+
import { readFileSync } from "fs";
|
|
492
|
+
import path from "path";
|
|
493
|
+
|
|
494
|
+
// src/connector-client/env.ts
|
|
495
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
496
|
+
const envVarName = entry.envVars[key];
|
|
497
|
+
if (!envVarName) {
|
|
498
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
499
|
+
}
|
|
500
|
+
const value = process.env[envVarName];
|
|
501
|
+
if (!value) {
|
|
502
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
503
|
+
}
|
|
504
|
+
return value;
|
|
505
|
+
}
|
|
506
|
+
function resolveEnvVarOptional(entry, key) {
|
|
507
|
+
const envVarName = entry.envVars[key];
|
|
508
|
+
if (!envVarName) return void 0;
|
|
509
|
+
return process.env[envVarName] || void 0;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/connector-client/proxy-fetch.ts
|
|
513
|
+
import { getContext } from "hono/context-storage";
|
|
514
|
+
import { getCookie } from "hono/cookie";
|
|
515
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
516
|
+
var TABLEAU_SESSION_SENTINEL_URL = "squadbase://tableau-session/";
|
|
517
|
+
function normalizeHeaders(input) {
|
|
518
|
+
const out = {};
|
|
519
|
+
if (!input) return out;
|
|
520
|
+
new Headers(input).forEach((value, key) => {
|
|
521
|
+
out[key] = value;
|
|
522
|
+
});
|
|
523
|
+
return out;
|
|
524
|
+
}
|
|
525
|
+
function extractInputUrl(input) {
|
|
526
|
+
if (typeof input === "string") return input;
|
|
527
|
+
if (input instanceof URL) return input.href;
|
|
528
|
+
return input.url;
|
|
529
|
+
}
|
|
530
|
+
function createSandboxProxyFetch(connectionId) {
|
|
531
|
+
return async (input, init) => {
|
|
532
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
533
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
534
|
+
if (!token || !sandboxId) {
|
|
535
|
+
throw new Error(
|
|
536
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
const originalUrl = extractInputUrl(input);
|
|
540
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
541
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
542
|
+
const sessionUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
543
|
+
return fetch(sessionUrl, {
|
|
544
|
+
method: "POST",
|
|
545
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
const originalMethod = init?.method ?? "GET";
|
|
549
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
550
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
551
|
+
return fetch(proxyUrl, {
|
|
552
|
+
method: "POST",
|
|
553
|
+
headers: {
|
|
554
|
+
"Content-Type": "application/json",
|
|
555
|
+
Authorization: `Bearer ${token}`
|
|
556
|
+
},
|
|
557
|
+
body: JSON.stringify({
|
|
558
|
+
url: originalUrl,
|
|
559
|
+
method: originalMethod,
|
|
560
|
+
headers: normalizeHeaders(init?.headers),
|
|
561
|
+
body: originalBody
|
|
562
|
+
})
|
|
563
|
+
});
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
567
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
568
|
+
if (!projectId) {
|
|
569
|
+
throw new Error(
|
|
570
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
574
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
575
|
+
const sessionUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/tableau-session`;
|
|
576
|
+
return async (input, init) => {
|
|
577
|
+
const originalUrl = extractInputUrl(input);
|
|
578
|
+
const c = getContext();
|
|
579
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
580
|
+
if (!appSession) {
|
|
581
|
+
throw new Error(
|
|
582
|
+
"No authentication method available for connection proxy."
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
if (originalUrl === TABLEAU_SESSION_SENTINEL_URL) {
|
|
586
|
+
return fetch(sessionUrl, {
|
|
587
|
+
method: "POST",
|
|
588
|
+
headers: { Authorization: `Bearer ${appSession}` }
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
const originalMethod = init?.method ?? "GET";
|
|
592
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
593
|
+
return fetch(proxyUrl, {
|
|
594
|
+
method: "POST",
|
|
595
|
+
headers: {
|
|
596
|
+
"Content-Type": "application/json",
|
|
597
|
+
Authorization: `Bearer ${appSession}`
|
|
598
|
+
},
|
|
599
|
+
body: JSON.stringify({
|
|
600
|
+
url: originalUrl,
|
|
601
|
+
method: originalMethod,
|
|
602
|
+
headers: normalizeHeaders(init?.headers),
|
|
603
|
+
body: originalBody
|
|
604
|
+
})
|
|
605
|
+
});
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
function createProxyFetch(connectionId) {
|
|
609
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
610
|
+
return createSandboxProxyFetch(connectionId);
|
|
611
|
+
}
|
|
612
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// src/connectors/create-connector-sdk.ts
|
|
616
|
+
function loadConnectionsSync() {
|
|
617
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
618
|
+
try {
|
|
619
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
620
|
+
return JSON.parse(raw);
|
|
621
|
+
} catch {
|
|
622
|
+
return {};
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
626
|
+
return (connectionId) => {
|
|
627
|
+
const connections = loadConnectionsSync();
|
|
628
|
+
const entry = connections[connectionId];
|
|
629
|
+
if (!entry) {
|
|
630
|
+
throw new Error(
|
|
631
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
635
|
+
throw new Error(
|
|
636
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
const params = {};
|
|
640
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
641
|
+
if (param.required) {
|
|
642
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
643
|
+
} else {
|
|
644
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
645
|
+
if (val !== void 0) params[param.slug] = val;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// src/connectors/entries/slack.ts
|
|
653
|
+
var connection = createConnectorSdk(slackConnector, createClient);
|
|
654
|
+
export {
|
|
655
|
+
connection
|
|
656
|
+
};
|
package/dist/connectors/x.js
CHANGED
|
@@ -609,7 +609,7 @@ var xConnector = new ConnectorPlugin({
|
|
|
609
609
|
description: "Connect to X API v2 for posts, users, search, timelines, trends, and related social media data using a user-provided Bearer Token.",
|
|
610
610
|
iconUrl: "https://cdn.simpleicons.org/x/000000",
|
|
611
611
|
parameters,
|
|
612
|
-
releaseFlag: { dev1: true, dev2: true, prod:
|
|
612
|
+
releaseFlag: { dev1: true, dev2: true, prod: true },
|
|
613
613
|
categories: ["social_media"],
|
|
614
614
|
onboarding: xOnboarding,
|
|
615
615
|
systemPrompt: {
|