@squadbase/vite-server 0.1.11-dev.0c78963 → 0.1.12-dev.8860f37
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 +1669 -43
- package/dist/connectors/outlook-oauth.d.ts +5 -0
- package/dist/connectors/outlook-oauth.js +929 -0
- package/dist/connectors/powerbi-oauth.d.ts +5 -0
- package/dist/connectors/powerbi-oauth.js +720 -0
- package/dist/connectors/powerbi.d.ts +5 -0
- package/dist/connectors/powerbi.js +869 -0
- package/dist/connectors/tableau.d.ts +5 -0
- package/dist/connectors/tableau.js +879 -0
- package/dist/index.js +1669 -43
- package/dist/main.js +1669 -43
- package/dist/vite-plugin.js +1669 -43
- package/package.json +17 -1
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
// ../connectors/src/connectors/outlook-oauth/sdk/index.ts
|
|
2
|
+
var BASE_URL = "https://graph.microsoft.com/v1.0";
|
|
3
|
+
function appendListMessagesOptions(qs, options) {
|
|
4
|
+
if (!options) return;
|
|
5
|
+
if (options.top != null) qs.set("$top", String(options.top));
|
|
6
|
+
if (options.skip != null) qs.set("$skip", String(options.skip));
|
|
7
|
+
if (options.filter) qs.set("$filter", options.filter);
|
|
8
|
+
if (options.orderBy) qs.set("$orderby", options.orderBy);
|
|
9
|
+
if (options.select && options.select.length > 0) {
|
|
10
|
+
qs.set("$select", options.select.join(","));
|
|
11
|
+
}
|
|
12
|
+
if (options.search) qs.set("$search", `"${options.search.replace(/"/g, '\\"')}"`);
|
|
13
|
+
}
|
|
14
|
+
function appendListEventsOptions(qs, options) {
|
|
15
|
+
if (!options) return;
|
|
16
|
+
if (options.top != null) qs.set("$top", String(options.top));
|
|
17
|
+
if (options.skip != null) qs.set("$skip", String(options.skip));
|
|
18
|
+
if (options.filter) qs.set("$filter", options.filter);
|
|
19
|
+
if (options.orderBy) qs.set("$orderby", options.orderBy);
|
|
20
|
+
if (options.select && options.select.length > 0) {
|
|
21
|
+
qs.set("$select", options.select.join(","));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function createClient(_params, fetchFn = fetch) {
|
|
25
|
+
function request(path2, init) {
|
|
26
|
+
const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
27
|
+
return fetchFn(url, init);
|
|
28
|
+
}
|
|
29
|
+
async function getJson(path2) {
|
|
30
|
+
const res = await request(path2);
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
const body = await res.text();
|
|
33
|
+
throw new Error(`outlook: GET ${path2} failed (${res.status}): ${body}`);
|
|
34
|
+
}
|
|
35
|
+
return await res.json();
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
request,
|
|
39
|
+
// ---------- Mail ----------
|
|
40
|
+
async getProfile() {
|
|
41
|
+
return getJson("/me");
|
|
42
|
+
},
|
|
43
|
+
async listMailFolders() {
|
|
44
|
+
return getJson("/me/mailFolders");
|
|
45
|
+
},
|
|
46
|
+
async listMessages(options) {
|
|
47
|
+
const qs = new URLSearchParams();
|
|
48
|
+
appendListMessagesOptions(qs, options);
|
|
49
|
+
const query = qs.toString();
|
|
50
|
+
return getJson(
|
|
51
|
+
`/me/messages${query ? `?${query}` : ""}`
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
async listMessagesInFolder(folderId, options) {
|
|
55
|
+
const qs = new URLSearchParams();
|
|
56
|
+
appendListMessagesOptions(qs, options);
|
|
57
|
+
const query = qs.toString();
|
|
58
|
+
return getJson(
|
|
59
|
+
`/me/mailFolders/${encodeURIComponent(folderId)}/messages${query ? `?${query}` : ""}`
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
async getMessage(messageId, options) {
|
|
63
|
+
const qs = new URLSearchParams();
|
|
64
|
+
if (options?.select && options.select.length > 0) {
|
|
65
|
+
qs.set("$select", options.select.join(","));
|
|
66
|
+
}
|
|
67
|
+
const query = qs.toString();
|
|
68
|
+
return getJson(
|
|
69
|
+
`/me/messages/${encodeURIComponent(messageId)}${query ? `?${query}` : ""}`
|
|
70
|
+
);
|
|
71
|
+
},
|
|
72
|
+
async listConversation(conversationId, options) {
|
|
73
|
+
const qs = new URLSearchParams();
|
|
74
|
+
qs.set(
|
|
75
|
+
"$filter",
|
|
76
|
+
`conversationId eq '${conversationId.replace(/'/g, "''")}'`
|
|
77
|
+
);
|
|
78
|
+
if (!options?.orderBy) qs.set("$orderby", "receivedDateTime asc");
|
|
79
|
+
appendListMessagesOptions(
|
|
80
|
+
qs,
|
|
81
|
+
options ? { ...options, filter: void 0 } : void 0
|
|
82
|
+
);
|
|
83
|
+
return getJson(
|
|
84
|
+
`/me/messages?${qs.toString()}`
|
|
85
|
+
);
|
|
86
|
+
},
|
|
87
|
+
// ---------- Attachments ----------
|
|
88
|
+
async listAttachments(messageId) {
|
|
89
|
+
return getJson(
|
|
90
|
+
`/me/messages/${encodeURIComponent(messageId)}/attachments`
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
async getAttachment(messageId, attachmentId) {
|
|
94
|
+
return getJson(
|
|
95
|
+
`/me/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`
|
|
96
|
+
);
|
|
97
|
+
},
|
|
98
|
+
// ---------- Calendar ----------
|
|
99
|
+
async listCalendars() {
|
|
100
|
+
return getJson("/me/calendars");
|
|
101
|
+
},
|
|
102
|
+
async listEvents(options) {
|
|
103
|
+
const qs = new URLSearchParams();
|
|
104
|
+
appendListEventsOptions(qs, options);
|
|
105
|
+
const query = qs.toString();
|
|
106
|
+
const basePath = options?.calendarId ? `/me/calendars/${encodeURIComponent(options.calendarId)}/events` : "/me/events";
|
|
107
|
+
return getJson(
|
|
108
|
+
`${basePath}${query ? `?${query}` : ""}`
|
|
109
|
+
);
|
|
110
|
+
},
|
|
111
|
+
async getEvent(eventId) {
|
|
112
|
+
return getJson(
|
|
113
|
+
`/me/events/${encodeURIComponent(eventId)}`
|
|
114
|
+
);
|
|
115
|
+
},
|
|
116
|
+
async listCalendarView(startDateTime, endDateTime, options) {
|
|
117
|
+
const qs = new URLSearchParams();
|
|
118
|
+
qs.set("startDateTime", startDateTime);
|
|
119
|
+
qs.set("endDateTime", endDateTime);
|
|
120
|
+
appendListEventsOptions(qs, options);
|
|
121
|
+
const basePath = options?.calendarId ? `/me/calendars/${encodeURIComponent(options.calendarId)}/calendarView` : "/me/calendarView";
|
|
122
|
+
return getJson(
|
|
123
|
+
`${basePath}?${qs.toString()}`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ../connectors/src/connector-onboarding.ts
|
|
130
|
+
var ConnectorOnboarding = class {
|
|
131
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
132
|
+
connectionSetupInstructions;
|
|
133
|
+
/** Phase 2: Data overview instructions */
|
|
134
|
+
dataOverviewInstructions;
|
|
135
|
+
constructor(config) {
|
|
136
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
137
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
138
|
+
}
|
|
139
|
+
getConnectionSetupPrompt(language) {
|
|
140
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
141
|
+
}
|
|
142
|
+
getDataOverviewInstructions(language) {
|
|
143
|
+
return this.dataOverviewInstructions[language];
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// ../connectors/src/connector-tool.ts
|
|
148
|
+
var ConnectorTool = class {
|
|
149
|
+
name;
|
|
150
|
+
description;
|
|
151
|
+
inputSchema;
|
|
152
|
+
outputSchema;
|
|
153
|
+
_execute;
|
|
154
|
+
constructor(config) {
|
|
155
|
+
this.name = config.name;
|
|
156
|
+
this.description = config.description;
|
|
157
|
+
this.inputSchema = config.inputSchema;
|
|
158
|
+
this.outputSchema = config.outputSchema;
|
|
159
|
+
this._execute = config.execute;
|
|
160
|
+
}
|
|
161
|
+
createTool(connections, config) {
|
|
162
|
+
return {
|
|
163
|
+
description: this.description,
|
|
164
|
+
inputSchema: this.inputSchema,
|
|
165
|
+
outputSchema: this.outputSchema,
|
|
166
|
+
execute: (input) => this._execute(input, connections, config)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// ../connectors/src/connector-plugin.ts
|
|
172
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
173
|
+
slug;
|
|
174
|
+
authType;
|
|
175
|
+
name;
|
|
176
|
+
description;
|
|
177
|
+
iconUrl;
|
|
178
|
+
parameters;
|
|
179
|
+
releaseFlag;
|
|
180
|
+
proxyPolicy;
|
|
181
|
+
experimentalAttributes;
|
|
182
|
+
categories;
|
|
183
|
+
onboarding;
|
|
184
|
+
systemPrompt;
|
|
185
|
+
tools;
|
|
186
|
+
query;
|
|
187
|
+
checkConnection;
|
|
188
|
+
constructor(config) {
|
|
189
|
+
this.slug = config.slug;
|
|
190
|
+
this.authType = config.authType;
|
|
191
|
+
this.name = config.name;
|
|
192
|
+
this.description = config.description;
|
|
193
|
+
this.iconUrl = config.iconUrl;
|
|
194
|
+
this.parameters = config.parameters;
|
|
195
|
+
this.releaseFlag = config.releaseFlag;
|
|
196
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
197
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
198
|
+
this.categories = config.categories ?? [];
|
|
199
|
+
this.onboarding = config.onboarding;
|
|
200
|
+
this.systemPrompt = config.systemPrompt;
|
|
201
|
+
this.tools = config.tools;
|
|
202
|
+
this.query = config.query;
|
|
203
|
+
this.checkConnection = config.checkConnection;
|
|
204
|
+
}
|
|
205
|
+
get connectorKey() {
|
|
206
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Create tools for connections that belong to this connector.
|
|
210
|
+
* Filters connections by connectorKey internally.
|
|
211
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
212
|
+
*/
|
|
213
|
+
createTools(connections, config, opts) {
|
|
214
|
+
const myConnections = connections.filter(
|
|
215
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
216
|
+
);
|
|
217
|
+
const result = {};
|
|
218
|
+
for (const t of Object.values(this.tools)) {
|
|
219
|
+
const tool = t.createTool(myConnections, config);
|
|
220
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
221
|
+
result[`${this.connectorKey}_${t.name}`] = {
|
|
222
|
+
...tool,
|
|
223
|
+
toModelOutput: async (options) => {
|
|
224
|
+
if (!originalToModelOutput) {
|
|
225
|
+
return opts.truncateOutput(options.output);
|
|
226
|
+
}
|
|
227
|
+
const modelOutput = await originalToModelOutput(options);
|
|
228
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
229
|
+
return opts.truncateOutput(modelOutput.value);
|
|
230
|
+
}
|
|
231
|
+
return modelOutput;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
static deriveKey(slug, authType) {
|
|
238
|
+
if (authType) return `${slug}-${authType}`;
|
|
239
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
240
|
+
// user-password
|
|
241
|
+
"postgresql": "user-password",
|
|
242
|
+
"mysql": "user-password",
|
|
243
|
+
"clickhouse": "user-password",
|
|
244
|
+
"kintone": "user-password",
|
|
245
|
+
"squadbase-db": "user-password",
|
|
246
|
+
// service-account
|
|
247
|
+
"snowflake": "service-account",
|
|
248
|
+
"bigquery": "service-account",
|
|
249
|
+
"google-analytics": "service-account",
|
|
250
|
+
"google-calendar": "service-account",
|
|
251
|
+
"aws-athena": "service-account",
|
|
252
|
+
"redshift": "service-account",
|
|
253
|
+
// api-key
|
|
254
|
+
"databricks": "api-key",
|
|
255
|
+
"dbt": "api-key",
|
|
256
|
+
"airtable": "api-key",
|
|
257
|
+
"openai": "api-key",
|
|
258
|
+
"gemini": "api-key",
|
|
259
|
+
"anthropic": "api-key",
|
|
260
|
+
"wix-store": "api-key"
|
|
261
|
+
};
|
|
262
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
263
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
264
|
+
return slug;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// ../connectors/src/auth-types.ts
|
|
269
|
+
var AUTH_TYPES = {
|
|
270
|
+
OAUTH: "oauth",
|
|
271
|
+
API_KEY: "api-key",
|
|
272
|
+
JWT: "jwt",
|
|
273
|
+
SERVICE_ACCOUNT: "service-account",
|
|
274
|
+
PAT: "pat",
|
|
275
|
+
USER_PASSWORD: "user-password"
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// ../connectors/src/lib/normalize-path.ts
|
|
279
|
+
function normalizeRequestPath(path2, basePathSegment) {
|
|
280
|
+
let p = path2.trim();
|
|
281
|
+
if (!p.startsWith("/")) p = "/" + p;
|
|
282
|
+
if (p === basePathSegment || p.startsWith(basePathSegment + "/")) {
|
|
283
|
+
p = p.slice(basePathSegment.length) || "/";
|
|
284
|
+
}
|
|
285
|
+
return p;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// ../connectors/src/connectors/outlook-oauth/tools/request.ts
|
|
289
|
+
import { z } from "zod";
|
|
290
|
+
var BASE_HOST = "https://graph.microsoft.com";
|
|
291
|
+
var BASE_PATH_SEGMENT = "/v1.0";
|
|
292
|
+
var BASE_URL2 = `${BASE_HOST}${BASE_PATH_SEGMENT}`;
|
|
293
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
294
|
+
var cachedToken = null;
|
|
295
|
+
async function getProxyToken(config) {
|
|
296
|
+
if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) {
|
|
297
|
+
return cachedToken.token;
|
|
298
|
+
}
|
|
299
|
+
const url = `${config.appApiBaseUrl}/v0/database/${config.projectId}/environment/${config.environmentId}/oauth-request-proxy-token`;
|
|
300
|
+
const res = await fetch(url, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: {
|
|
303
|
+
"Content-Type": "application/json",
|
|
304
|
+
"x-api-key": config.appApiKey,
|
|
305
|
+
"project-id": config.projectId
|
|
306
|
+
},
|
|
307
|
+
body: JSON.stringify({
|
|
308
|
+
sandboxId: config.sandboxId,
|
|
309
|
+
issuedBy: "coding-agent"
|
|
310
|
+
})
|
|
311
|
+
});
|
|
312
|
+
if (!res.ok) {
|
|
313
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
314
|
+
throw new Error(
|
|
315
|
+
`Failed to get proxy token: HTTP ${res.status} ${errorText}`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
const data = await res.json();
|
|
319
|
+
cachedToken = {
|
|
320
|
+
token: data.token,
|
|
321
|
+
expiresAt: new Date(data.expiresAt).getTime()
|
|
322
|
+
};
|
|
323
|
+
return data.token;
|
|
324
|
+
}
|
|
325
|
+
var inputSchema = z.object({
|
|
326
|
+
toolUseIntent: z.string().optional().describe(
|
|
327
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
328
|
+
),
|
|
329
|
+
connectionId: z.string().describe("ID of the Outlook OAuth connection to use"),
|
|
330
|
+
method: z.enum(["GET"]).describe("HTTP method (read-only, GET only)"),
|
|
331
|
+
path: z.string().describe(
|
|
332
|
+
"Microsoft Graph path appended to https://graph.microsoft.com/v1.0. Covers Outlook Mail (e.g. '/me', '/me/messages', '/me/messages/{id}', '/me/mailFolders', '/me/messages/{id}/attachments') and Outlook Calendar (e.g. '/me/calendars', '/me/events', '/me/events/{id}', '/me/calendarView'). Use '/me' as the user prefix."
|
|
333
|
+
),
|
|
334
|
+
queryParams: z.record(z.string(), z.string()).optional().describe(
|
|
335
|
+
`Query parameters to append. Microsoft Graph supports OData operators ($filter, $orderby, $top, $skip, $select, $expand, $search). Examples: { $top: '10', $select: 'subject,from,receivedDateTime' } for mail; { $filter: "conversationId eq '<id>'", $orderby: 'receivedDateTime asc' } for a thread; { startDateTime: '2025-01-15T00:00:00Z', endDateTime: '2025-01-16T00:00:00Z', $orderby: 'start/dateTime' } for calendarView.`
|
|
336
|
+
)
|
|
337
|
+
});
|
|
338
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
339
|
+
z.object({
|
|
340
|
+
success: z.literal(true),
|
|
341
|
+
status: z.number(),
|
|
342
|
+
data: z.record(z.string(), z.unknown())
|
|
343
|
+
}),
|
|
344
|
+
z.object({
|
|
345
|
+
success: z.literal(false),
|
|
346
|
+
error: z.string()
|
|
347
|
+
})
|
|
348
|
+
]);
|
|
349
|
+
var requestTool = new ConnectorTool({
|
|
350
|
+
name: "request",
|
|
351
|
+
description: `Send authenticated GET requests to Microsoft Graph for Outlook Mail and Calendar.
|
|
352
|
+
Authentication is handled automatically via OAuth proxy (Microsoft Entra ID).
|
|
353
|
+
All paths are relative to https://graph.microsoft.com/v1.0. Use '/me' as the user prefix.
|
|
354
|
+
Covers mailbox (\`/me/messages\`, \`/me/mailFolders\`), threads (\`/me/messages?$filter=conversationId eq '<id>'\`), attachments (\`/me/messages/{id}/attachments\`), calendars (\`/me/calendars\`), and events (\`/me/events\`, \`/me/calendarView\` for expanded occurrences).
|
|
355
|
+
For full-text search use the \`$search\` query parameter (must be wrapped in double quotes); for filtering use \`$filter\` with OData syntax (e.g., \`receivedDateTime ge 2025-01-01T00:00:00Z\`).`,
|
|
356
|
+
inputSchema,
|
|
357
|
+
outputSchema,
|
|
358
|
+
async execute({ connectionId, method, path: path2, queryParams }, connections, config) {
|
|
359
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
360
|
+
if (!connection2) {
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
error: `Connection ${connectionId} not found`
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
console.log(
|
|
367
|
+
`[connector-request] outlook-oauth/${connection2.name}: ${method} ${path2}`
|
|
368
|
+
);
|
|
369
|
+
try {
|
|
370
|
+
const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT);
|
|
371
|
+
let url = `${BASE_URL2}${normalizedPath}`;
|
|
372
|
+
if (queryParams) {
|
|
373
|
+
const searchParams = new URLSearchParams(queryParams);
|
|
374
|
+
url += `?${searchParams.toString()}`;
|
|
375
|
+
}
|
|
376
|
+
const token = await getProxyToken(config.oauthProxy);
|
|
377
|
+
const proxyUrl = `https://${config.oauthProxy.sandboxId}.${config.oauthProxy.previewBaseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
378
|
+
const controller = new AbortController();
|
|
379
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
380
|
+
try {
|
|
381
|
+
const response = await fetch(proxyUrl, {
|
|
382
|
+
method: "POST",
|
|
383
|
+
headers: {
|
|
384
|
+
"Content-Type": "application/json",
|
|
385
|
+
Authorization: `Bearer ${token}`
|
|
386
|
+
},
|
|
387
|
+
body: JSON.stringify({
|
|
388
|
+
url,
|
|
389
|
+
method
|
|
390
|
+
}),
|
|
391
|
+
signal: controller.signal
|
|
392
|
+
});
|
|
393
|
+
const data = await response.json();
|
|
394
|
+
if (!response.ok) {
|
|
395
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
396
|
+
return { success: false, error: errorMessage };
|
|
397
|
+
}
|
|
398
|
+
return { success: true, status: response.status, data };
|
|
399
|
+
} finally {
|
|
400
|
+
clearTimeout(timeout);
|
|
401
|
+
}
|
|
402
|
+
} catch (err) {
|
|
403
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
404
|
+
return { success: false, error: msg };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// ../connectors/src/connectors/outlook-oauth/setup.ts
|
|
410
|
+
var requestToolName = `outlook-oauth_${requestTool.name}`;
|
|
411
|
+
var outlookOnboarding = new ConnectorOnboarding({
|
|
412
|
+
connectionSetupInstructions: {
|
|
413
|
+
ja: `\u4EE5\u4E0B\u306E\u624B\u9806\u3067 Outlook \u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044\u3002
|
|
414
|
+
|
|
415
|
+
1. \`${requestToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u8A8D\u8A3C\u6E08\u307F\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u3092\u53D6\u5F97\u3059\u308B:
|
|
416
|
+
- \`method\`: \`"GET"\`
|
|
417
|
+
- \`path\`: \`"/me"\`
|
|
418
|
+
2. \u30A8\u30E9\u30FC\u304C\u8FD4\u3055\u308C\u305F\u5834\u5408\u306F\u3001OAuth \u8A8D\u8A3C\u304C\u6B63\u3057\u304F\u5B8C\u4E86\u3057\u3066\u3044\u308B\u304B\u3092\u30E6\u30FC\u30B6\u30FC\u306B\u78BA\u8A8D\u3059\u308B\u3088\u3046\u4F1D\u3048\u308B
|
|
419
|
+
3. \`${requestToolName}\` \u3092\u547C\u3073\u51FA\u3057\u3066\u30E1\u30FC\u30EB\u30D5\u30A9\u30EB\u30C0\u4E00\u89A7\u3092\u53D6\u5F97\u3059\u308B:
|
|
420
|
+
- \`method\`: \`"GET"\`
|
|
421
|
+
- \`path\`: \`"/me/mailFolders"\`
|
|
422
|
+
|
|
423
|
+
#### \u5236\u7D04
|
|
424
|
+
- **\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\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u53D6\u5F97\u3068\u30D5\u30A9\u30EB\u30C0\u4E00\u89A7\u53D6\u5F97\u306E\u307F
|
|
425
|
+
- \u30C4\u30FC\u30EB\u9593\u306F1\u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057`,
|
|
426
|
+
en: `Follow these steps to set up the Outlook connection.
|
|
427
|
+
|
|
428
|
+
1. Call \`${requestToolName}\` to get the authenticated user's profile:
|
|
429
|
+
- \`method\`: \`"GET"\`
|
|
430
|
+
- \`path\`: \`"/me"\`
|
|
431
|
+
2. If an error is returned, ask the user to verify that OAuth authentication completed correctly
|
|
432
|
+
3. Call \`${requestToolName}\` to get the mail folder list:
|
|
433
|
+
- \`method\`: \`"GET"\`
|
|
434
|
+
- \`path\`: \`"/me/mailFolders"\`
|
|
435
|
+
|
|
436
|
+
#### Constraints
|
|
437
|
+
- **Do NOT read message bodies during setup**. Only the profile and mail-folder requests specified above are allowed
|
|
438
|
+
- Write only 1 sentence between tool calls, then immediately call the next tool`
|
|
439
|
+
},
|
|
440
|
+
dataOverviewInstructions: {
|
|
441
|
+
en: `Mail
|
|
442
|
+
1. Call outlook-oauth_request with GET /me/mailFolders to list mail folders
|
|
443
|
+
2. Call outlook-oauth_request with GET /me/messages?$top=5&$select=id,subject,from,receivedDateTime,conversationId to sample recent messages
|
|
444
|
+
3. Call outlook-oauth_request with GET /me/messages/{id} for an interesting message to inspect the full payload
|
|
445
|
+
4. Call outlook-oauth_request with GET /me/mailFolders/{folderId}/messages?$top=5 to drill into a specific folder
|
|
446
|
+
5. For threading, call outlook-oauth_request with GET /me/messages?$filter=conversationId%20eq%20'<id>'&$orderby=receivedDateTime%20asc to pull every message in a conversation
|
|
447
|
+
|
|
448
|
+
Calendar
|
|
449
|
+
6. Call outlook-oauth_request with GET /me/calendars to list calendars (default + shared)
|
|
450
|
+
7. Call outlook-oauth_request with GET /me/calendarView?startDateTime=<startISO>&endDateTime=<endISO>&$top=5&$select=id,subject,start,end,attendees to sample upcoming occurrences (expands recurring events)
|
|
451
|
+
8. Call outlook-oauth_request with GET /me/events/{eventId} for an interesting event to inspect attendees, body, and location`,
|
|
452
|
+
ja: `\u30E1\u30FC\u30EB
|
|
453
|
+
1. outlook-oauth_request \u3067 GET /me/mailFolders \u3092\u547C\u3073\u51FA\u3057\u3001\u30E1\u30FC\u30EB\u30D5\u30A9\u30EB\u30C0\u4E00\u89A7\u3092\u53D6\u5F97
|
|
454
|
+
2. outlook-oauth_request \u3067 GET /me/messages?$top=5&$select=id,subject,from,receivedDateTime,conversationId \u3092\u547C\u3073\u51FA\u3057\u3001\u6700\u65B0\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0
|
|
455
|
+
3. \u8208\u5473\u306E\u3042\u308B\u30E1\u30C3\u30BB\u30FC\u30B8\u306B\u3064\u3044\u3066 outlook-oauth_request \u3067 GET /me/messages/{id} \u3092\u547C\u3073\u51FA\u3057\u3001\u30DA\u30A4\u30ED\u30FC\u30C9\u5168\u4F53\u3092\u78BA\u8A8D
|
|
456
|
+
4. outlook-oauth_request \u3067 GET /me/mailFolders/{folderId}/messages?$top=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u7279\u5B9A\u30D5\u30A9\u30EB\u30C0\u306E\u4E2D\u8EAB\u3092\u78BA\u8A8D
|
|
457
|
+
5. \u30B9\u30EC\u30C3\u30C9\u3092\u8FFD\u3046\u5834\u5408\u306F outlook-oauth_request \u3067 GET /me/messages?$filter=conversationId%20eq%20'<id>'&$orderby=receivedDateTime%20asc \u3092\u547C\u3073\u51FA\u3057\u3001\u4F1A\u8A71\u306B\u542B\u307E\u308C\u308B\u5168\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D6\u5F97
|
|
458
|
+
|
|
459
|
+
\u30AB\u30EC\u30F3\u30C0\u30FC
|
|
460
|
+
6. outlook-oauth_request \u3067 GET /me/calendars \u3092\u547C\u3073\u51FA\u3057\u3001\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7 (\u30C7\u30D5\u30A9\u30EB\u30C8 + \u5171\u6709) \u3092\u53D6\u5F97
|
|
461
|
+
7. outlook-oauth_request \u3067 GET /me/calendarView?startDateTime=<startISO>&endDateTime=<endISO>&$top=5&$select=id,subject,start,end,attendees \u3092\u547C\u3073\u51FA\u3057\u3001\u76F4\u8FD1\u306E occurrence \u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0 (\u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u3092\u5C55\u958B)
|
|
462
|
+
8. \u8208\u5473\u306E\u3042\u308B\u30A4\u30D9\u30F3\u30C8\u306B\u3064\u3044\u3066 outlook-oauth_request \u3067 GET /me/events/{eventId} \u3092\u547C\u3073\u51FA\u3057\u3001\u53C2\u52A0\u8005\u30FB\u672C\u6587\u30FB\u5834\u6240\u3092\u78BA\u8A8D`
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// ../connectors/src/connectors/outlook-oauth/parameters.ts
|
|
467
|
+
var parameters = {};
|
|
468
|
+
|
|
469
|
+
// ../connectors/src/connectors/outlook-oauth/index.ts
|
|
470
|
+
var tools = { request: requestTool };
|
|
471
|
+
var outlookOauthConnector = new ConnectorPlugin({
|
|
472
|
+
slug: "outlook",
|
|
473
|
+
authType: AUTH_TYPES.OAUTH,
|
|
474
|
+
name: "Outlook",
|
|
475
|
+
description: "Connect to Microsoft Outlook (Mail + Calendar) via Microsoft Graph using OAuth. Read-only access to the user's mailbox, mail folders, messages, attachments, calendars, and events.",
|
|
476
|
+
iconUrl: "https://upload.wikimedia.org/wikipedia/commons/d/df/Microsoft_Office_Outlook_%282018%E2%80%93present%29.svg",
|
|
477
|
+
parameters,
|
|
478
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
479
|
+
categories: ["productivity"],
|
|
480
|
+
onboarding: outlookOnboarding,
|
|
481
|
+
proxyPolicy: {
|
|
482
|
+
allowlist: [
|
|
483
|
+
{
|
|
484
|
+
host: "graph.microsoft.com",
|
|
485
|
+
methods: ["GET"]
|
|
486
|
+
}
|
|
487
|
+
]
|
|
488
|
+
},
|
|
489
|
+
systemPrompt: {
|
|
490
|
+
en: `### Tools
|
|
491
|
+
|
|
492
|
+
- \`outlook-oauth_request\`: The only way to call Microsoft Graph for Outlook (read-only). Use it to fetch the user profile (\`/me\`), list mail folders (\`/me/mailFolders\`), read messages (\`/me/messages\`, \`/me/messages/{id}\`), fetch attachments (\`/me/messages/{id}/attachments\`), list calendars (\`/me/calendars\`), and read events (\`/me/events\`, \`/me/calendarView\`). Authentication is configured automatically via OAuth.
|
|
493
|
+
|
|
494
|
+
### Microsoft Graph Reference (Outlook Mail)
|
|
495
|
+
|
|
496
|
+
#### Available Endpoints
|
|
497
|
+
- GET \`/me\` \u2014 Get the signed-in user's profile (displayName, mail, userPrincipalName)
|
|
498
|
+
- GET \`/me/mailFolders\` \u2014 List the user's mail folders (Inbox, SentItems, Drafts, etc.)
|
|
499
|
+
- GET \`/me/mailFolders/{folderId}\` \u2014 Get a specific mail folder
|
|
500
|
+
- GET \`/me/mailFolders/{folderId}/messages\` \u2014 List messages within a folder
|
|
501
|
+
- GET \`/me/messages\` \u2014 List messages across all folders
|
|
502
|
+
- GET \`/me/messages/{id}\` \u2014 Get a specific message with full body
|
|
503
|
+
- GET \`/me/messages/{id}/attachments\` \u2014 List attachments on a message
|
|
504
|
+
- GET \`/me/messages/{id}/attachments/{attachmentId}\` \u2014 Get a specific attachment
|
|
505
|
+
|
|
506
|
+
#### Well-Known Folder Names (usable in place of {folderId})
|
|
507
|
+
- \`inbox\`, \`sentitems\`, \`drafts\`, \`deleteditems\`, \`junkemail\`, \`outbox\`, \`archive\`
|
|
508
|
+
|
|
509
|
+
#### Conversations (Threads)
|
|
510
|
+
- Every message has a \`conversationId\`. Fetch all messages in a thread with: GET \`/me/messages?$filter=conversationId eq '<id>'&$orderby=receivedDateTime asc\` (Gmail-style \`getThread\` equivalent).
|
|
511
|
+
|
|
512
|
+
### Microsoft Graph Reference (Outlook Calendar)
|
|
513
|
+
|
|
514
|
+
#### Available Endpoints
|
|
515
|
+
- GET \`/me/calendars\` \u2014 List the user's calendars (default + any shared/group calendars)
|
|
516
|
+
- GET \`/me/calendars/{calendarId}\` \u2014 Get a calendar's metadata
|
|
517
|
+
- GET \`/me/events\` \u2014 List events on the default calendar (recurring events are returned as series masters \u2014 use \`/me/calendarView\` to expand)
|
|
518
|
+
- GET \`/me/calendars/{calendarId}/events\` \u2014 List events on a specific calendar
|
|
519
|
+
- GET \`/me/events/{eventId}\` \u2014 Get a single event
|
|
520
|
+
- GET \`/me/calendarView?startDateTime=&endDateTime=\` \u2014 List event **occurrences** in a date range (expands recurring events). Equivalent to Google Calendar's \`events?singleEvents=true\`
|
|
521
|
+
- GET \`/me/calendars/{calendarId}/calendarView?startDateTime=&endDateTime=\` \u2014 Same, scoped to a specific calendar
|
|
522
|
+
|
|
523
|
+
#### Calendar Tips
|
|
524
|
+
- Use \`/me/calendarView\` when you want individual occurrences of recurring events; \`/me/events\` is closer to the raw stored series
|
|
525
|
+
- \`startDateTime\` / \`endDateTime\` must be ISO-8601 UTC, e.g. \`2025-01-15T00:00:00Z\`
|
|
526
|
+
- Combine with \`$select=subject,start,end,attendees,location\` and \`$orderby=start/dateTime\` to keep responses small and sorted
|
|
527
|
+
|
|
528
|
+
#### Key Query Parameters (OData, shared by Mail + Calendar)
|
|
529
|
+
- \`$top\` \u2014 Maximum number of results (default 10, max 1000)
|
|
530
|
+
- \`$skip\` \u2014 Skip the first N results (for paging)
|
|
531
|
+
- \`$select\` \u2014 Comma-separated list of properties (e.g. \`subject,from,receivedDateTime,bodyPreview\`)
|
|
532
|
+
- \`$orderby\` \u2014 Sort (e.g. \`receivedDateTime desc\`, \`start/dateTime asc\`)
|
|
533
|
+
- \`$filter\` \u2014 OData filter (e.g. \`receivedDateTime ge 2025-01-01T00:00:00Z\`, \`from/emailAddress/address eq 'a@b.com'\`, \`isRead eq false\`, \`conversationId eq '<id>'\`, \`start/dateTime ge '2025-01-15T00:00:00'\`)
|
|
534
|
+
- \`$search\` \u2014 Full-text search; must be wrapped in double quotes (e.g. \`$search="project status"\`). \`$search\` and \`$filter\` cannot be combined
|
|
535
|
+
- \`$expand\` \u2014 Expand related resources (e.g. \`attachments\`, \`instances\` for recurring events)
|
|
536
|
+
- \`$count=true\` \u2014 Return total count (requires \`ConsistencyLevel: eventual\` header on some endpoints)
|
|
537
|
+
|
|
538
|
+
#### Pagination
|
|
539
|
+
- Responses include \`@odata.nextLink\` when more results exist; call that URL (or its path) to get the next page
|
|
540
|
+
|
|
541
|
+
#### Tips
|
|
542
|
+
- Use \`/me\` for the signed-in user \u2014 never substitute another user ID
|
|
543
|
+
- Prefer \`$select\` to avoid huge payloads; the full message body can be MB-sized when HTML
|
|
544
|
+
- \`bodyPreview\` (first ~255 chars) is included by default and is cheap for triage
|
|
545
|
+
- Date/time values are ISO-8601; calendar event times also include a \`timeZone\` field
|
|
546
|
+
|
|
547
|
+
### Business Logic
|
|
548
|
+
|
|
549
|
+
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 and do NOT read \`INTERNAL_SQUADBASE_*\` env vars \u2014 the SDK takes care of OAuth.
|
|
550
|
+
|
|
551
|
+
SDK surface (client created via \`connection(connectionId)\`):
|
|
552
|
+
|
|
553
|
+
Mail:
|
|
554
|
+
- \`client.request(path, init?)\` \u2014 low-level authenticated fetch (path appended to \`https://graph.microsoft.com/v1.0\`)
|
|
555
|
+
- \`client.getProfile()\` \u2014 fetch the authenticated user's profile
|
|
556
|
+
- \`client.listMailFolders()\` \u2014 list all mail folders
|
|
557
|
+
- \`client.listMessages(options?)\` \u2014 list messages with optional \`top\`, \`skip\`, \`filter\`, \`orderBy\`, \`select\`, \`search\`
|
|
558
|
+
- \`client.listMessagesInFolder(folderId, options?)\` \u2014 list messages in a folder (well-known names like \`inbox\` work)
|
|
559
|
+
- \`client.getMessage(id, options?)\` \u2014 fetch a specific message
|
|
560
|
+
- \`client.listConversation(conversationId, options?)\` \u2014 fetch every message in a thread (Gmail-style \`getThread\` equivalent; orders oldest-first by default)
|
|
561
|
+
|
|
562
|
+
Attachments:
|
|
563
|
+
- \`client.listAttachments(messageId)\` \u2014 list attachments on a message
|
|
564
|
+
- \`client.getAttachment(messageId, attachmentId)\` \u2014 fetch a single attachment (file attachments include base64 \`contentBytes\`)
|
|
565
|
+
|
|
566
|
+
Calendar:
|
|
567
|
+
- \`client.listCalendars()\` \u2014 list calendars accessible to the user
|
|
568
|
+
- \`client.listEvents(options?)\` \u2014 list events on the default calendar (or pass \`{ calendarId }\` for a specific one). Recurring events are returned as series masters
|
|
569
|
+
- \`client.getEvent(id)\` \u2014 fetch a single event
|
|
570
|
+
- \`client.listCalendarView(startDateTime, endDateTime, options?)\` \u2014 list event **occurrences** in a date range (recurring events expanded). Equivalent to Google Calendar's \`events?singleEvents=true\`
|
|
571
|
+
|
|
572
|
+
If a handler test fails with \`Connection proxy is not configured\`, retry \u2014 the sandbox is still initializing. Do NOT abandon the SDK and construct OAuth proxy URLs manually.
|
|
573
|
+
|
|
574
|
+
#### Example
|
|
575
|
+
|
|
576
|
+
\`\`\`ts
|
|
577
|
+
import { connection } from "@squadbase/vite-server/connectors/outlook-oauth";
|
|
578
|
+
|
|
579
|
+
const outlook = connection("<connectionId>");
|
|
580
|
+
|
|
581
|
+
// Get user profile
|
|
582
|
+
const profile = await outlook.getProfile();
|
|
583
|
+
console.log(profile.displayName, profile.mail);
|
|
584
|
+
|
|
585
|
+
// List recent unread messages in Inbox
|
|
586
|
+
const messages = await outlook.listMessagesInFolder("inbox", {
|
|
587
|
+
top: 10,
|
|
588
|
+
filter: "isRead eq false",
|
|
589
|
+
orderBy: "receivedDateTime desc",
|
|
590
|
+
select: ["id", "subject", "from", "receivedDateTime", "bodyPreview", "conversationId"],
|
|
591
|
+
});
|
|
592
|
+
for (const msg of messages.value) {
|
|
593
|
+
console.log(msg.receivedDateTime, msg.from?.emailAddress.address, msg.subject);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Pull a whole conversation
|
|
597
|
+
const first = messages.value[0];
|
|
598
|
+
if (first?.conversationId) {
|
|
599
|
+
const thread = await outlook.listConversation(first.conversationId);
|
|
600
|
+
thread.value.forEach(m => console.log(m.receivedDateTime, m.bodyPreview));
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Fetch attachments on a message that has them
|
|
604
|
+
if (first?.hasAttachments) {
|
|
605
|
+
const atts = await outlook.listAttachments(first.id);
|
|
606
|
+
for (const a of atts.value) {
|
|
607
|
+
const full = await outlook.getAttachment(first.id, a.id);
|
|
608
|
+
console.log(full.name, full.contentType, full.size);
|
|
609
|
+
// full.contentBytes is base64 for file attachments
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// List today's calendar events (expanded occurrences)
|
|
614
|
+
const todayStart = new Date(); todayStart.setHours(0, 0, 0, 0);
|
|
615
|
+
const todayEnd = new Date(todayStart); todayEnd.setDate(todayEnd.getDate() + 1);
|
|
616
|
+
const events = await outlook.listCalendarView(
|
|
617
|
+
todayStart.toISOString(),
|
|
618
|
+
todayEnd.toISOString(),
|
|
619
|
+
{ orderBy: "start/dateTime", select: ["id", "subject", "start", "end", "attendees"] },
|
|
620
|
+
);
|
|
621
|
+
events.value.forEach(e => console.log(e.start.dateTime, e.subject));
|
|
622
|
+
\`\`\``,
|
|
623
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
624
|
+
|
|
625
|
+
- \`outlook-oauth_request\`: Outlook \u5411\u3051\u306E Microsoft Graph \u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\uFF08\u8AAD\u307F\u53D6\u308A\u5C02\u7528\uFF09\u3002\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB (\`/me\`)\u3001\u30E1\u30FC\u30EB\u30D5\u30A9\u30EB\u30C0 (\`/me/mailFolders\`)\u3001\u30E1\u30C3\u30BB\u30FC\u30B8 (\`/me/messages\`)\u3001\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB (\`/me/messages/{id}/attachments\`)\u3001\u30AB\u30EC\u30F3\u30C0\u30FC (\`/me/calendars\`)\u3001\u30A4\u30D9\u30F3\u30C8 (\`/me/events\`, \`/me/calendarView\`) \u306E\u53D6\u5F97\u306B\u4F7F\u3044\u307E\u3059\u3002OAuth \u7D4C\u7531\u3067\u8A8D\u8A3C\u306F\u81EA\u52D5\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002
|
|
626
|
+
|
|
627
|
+
### Microsoft Graph \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9 (Outlook \u30E1\u30FC\u30EB)
|
|
628
|
+
|
|
629
|
+
#### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
630
|
+
- GET \`/me\` \u2014 \u30B5\u30A4\u30F3\u30A4\u30F3\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB (displayName, mail, userPrincipalName)
|
|
631
|
+
- GET \`/me/mailFolders\` \u2014 \u30E1\u30FC\u30EB\u30D5\u30A9\u30EB\u30C0\u4E00\u89A7 (Inbox, SentItems, Drafts \u306A\u3069)
|
|
632
|
+
- GET \`/me/mailFolders/{folderId}\` \u2014 \u7279\u5B9A\u30D5\u30A9\u30EB\u30C0\u306E\u53D6\u5F97
|
|
633
|
+
- GET \`/me/mailFolders/{folderId}/messages\` \u2014 \u30D5\u30A9\u30EB\u30C0\u5185\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u4E00\u89A7
|
|
634
|
+
- GET \`/me/messages\` \u2014 \u5168\u30D5\u30A9\u30EB\u30C0\u6A2A\u65AD\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u4E00\u89A7
|
|
635
|
+
- GET \`/me/messages/{id}\` \u2014 \u7279\u5B9A\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u672C\u6587\u8FBC\u307F\u3067\u53D6\u5F97
|
|
636
|
+
- GET \`/me/messages/{id}/attachments\` \u2014 \u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u4E00\u89A7
|
|
637
|
+
- GET \`/me/messages/{id}/attachments/{attachmentId}\` \u2014 \u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u5358\u4F53\u53D6\u5F97
|
|
638
|
+
|
|
639
|
+
#### Well-Known \u30D5\u30A9\u30EB\u30C0\u540D ({folderId} \u306E\u4EE3\u308F\u308A\u306B\u4F7F\u7528\u53EF\u80FD)
|
|
640
|
+
- \`inbox\`, \`sentitems\`, \`drafts\`, \`deleteditems\`, \`junkemail\`, \`outbox\`, \`archive\`
|
|
641
|
+
|
|
642
|
+
#### \u4F1A\u8A71 (\u30B9\u30EC\u30C3\u30C9)
|
|
643
|
+
- \u3059\u3079\u3066\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u306F \`conversationId\` \u3092\u6301\u3064\u3002\u30B9\u30EC\u30C3\u30C9\u5185\u306E\u5168\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D6\u5F97\u3059\u308B\u306B\u306F: GET \`/me/messages?$filter=conversationId eq '<id>'&$orderby=receivedDateTime asc\` (Gmail \u306E \`getThread\` \u76F8\u5F53)\u3002
|
|
644
|
+
|
|
645
|
+
### Microsoft Graph \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9 (Outlook \u30AB\u30EC\u30F3\u30C0\u30FC)
|
|
646
|
+
|
|
647
|
+
#### \u5229\u7528\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
648
|
+
- GET \`/me/calendars\` \u2014 \u30E6\u30FC\u30B6\u30FC\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7 (\u30C7\u30D5\u30A9\u30EB\u30C8 + \u5171\u6709/\u30B0\u30EB\u30FC\u30D7\u30AB\u30EC\u30F3\u30C0\u30FC)
|
|
649
|
+
- GET \`/me/calendars/{calendarId}\` \u2014 \u30AB\u30EC\u30F3\u30C0\u30FC\u5358\u4F53\u53D6\u5F97
|
|
650
|
+
- GET \`/me/events\` \u2014 \u30C7\u30D5\u30A9\u30EB\u30C8\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7\uFF08\u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u306F series master \u306E\u307E\u307E\u8FD4\u308B \u2014 \u5C55\u958B\u3057\u305F\u3044\u5834\u5408\u306F \`/me/calendarView\`\uFF09
|
|
651
|
+
- GET \`/me/calendars/{calendarId}/events\` \u2014 \u7279\u5B9A\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7
|
|
652
|
+
- GET \`/me/events/{eventId}\` \u2014 \u30A4\u30D9\u30F3\u30C8\u5358\u4F53\u53D6\u5F97
|
|
653
|
+
- GET \`/me/calendarView?startDateTime=&endDateTime=\` \u2014 \u65E5\u4ED8\u7BC4\u56F2\u5185\u306E\u30A4\u30D9\u30F3\u30C8 **occurrence** \u4E00\u89A7\uFF08\u7E70\u308A\u8FD4\u3057\u3092\u5C55\u958B\uFF09\u3002Google Calendar \u306E \`events?singleEvents=true\` \u76F8\u5F53
|
|
654
|
+
- GET \`/me/calendars/{calendarId}/calendarView?startDateTime=&endDateTime=\` \u2014 \u540C\u4E0A\u3001\u7279\u5B9A\u30AB\u30EC\u30F3\u30C0\u30FC\u7248
|
|
655
|
+
|
|
656
|
+
#### \u30AB\u30EC\u30F3\u30C0\u30FC Tips
|
|
657
|
+
- \u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u306E\u500B\u5225 occurrence \u304C\u6B32\u3057\u3044\u5834\u5408\u306F \`/me/calendarView\`\u3001\u751F\u306E\u30B7\u30EA\u30FC\u30BA\u304C\u6B32\u3057\u3044\u5834\u5408\u306F \`/me/events\`
|
|
658
|
+
- \`startDateTime\` / \`endDateTime\` \u306F ISO-8601 UTC\u3001\u4F8B \`2025-01-15T00:00:00Z\`
|
|
659
|
+
- \`$select=subject,start,end,attendees,location\` \u3068 \`$orderby=start/dateTime\` \u3092\u7D44\u307F\u5408\u308F\u305B\u308B\u3068\u30DA\u30A4\u30ED\u30FC\u30C9\u6291\u5236 + \u30BD\u30FC\u30C8\u3067\u304D\u308B
|
|
660
|
+
|
|
661
|
+
#### \u4E3B\u8981\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF (OData; Mail \u3068 Calendar \u3067\u5171\u901A)
|
|
662
|
+
- \`$top\` \u2014 \u6700\u5927\u7D50\u679C\u6570 (\u30C7\u30D5\u30A9\u30EB\u30C8 10\u3001\u6700\u5927 1000)
|
|
663
|
+
- \`$skip\` \u2014 \u5148\u982D N \u4EF6\u3092\u30B9\u30AD\u30C3\u30D7 (\u30DA\u30FC\u30B8\u30F3\u30B0)
|
|
664
|
+
- \`$select\` \u2014 \u53D6\u5F97\u3059\u308B\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u30AB\u30F3\u30DE\u533A\u5207\u308A (\u4F8B \`subject,from,receivedDateTime,bodyPreview\`)
|
|
665
|
+
- \`$orderby\` \u2014 \u30BD\u30FC\u30C8 (\u4F8B \`receivedDateTime desc\`\u3001\`start/dateTime asc\`)
|
|
666
|
+
- \`$filter\` \u2014 OData \u30D5\u30A3\u30EB\u30BF (\u4F8B \`receivedDateTime ge 2025-01-01T00:00:00Z\`\u3001\`from/emailAddress/address eq 'a@b.com'\`\u3001\`isRead eq false\`\u3001\`conversationId eq '<id>'\`\u3001\`start/dateTime ge '2025-01-15T00:00:00'\`)
|
|
667
|
+
- \`$search\` \u2014 \u5168\u6587\u691C\u7D22\u3002\u30C0\u30D6\u30EB\u30AF\u30A9\u30FC\u30C8\u3067\u56F2\u3080\u5FC5\u8981\u3042\u308A (\u4F8B \`$search="project status"\`)\u3002\`$filter\` \u3068\u4F75\u7528\u4E0D\u53EF
|
|
668
|
+
- \`$expand\` \u2014 \u95A2\u9023\u30EA\u30BD\u30FC\u30B9\u3092\u5C55\u958B (\u4F8B \`attachments\`\u3001\u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u306E \`instances\`)
|
|
669
|
+
- \`$count=true\` \u2014 \u7DCF\u4EF6\u6570\u3092\u8FD4\u3059 (\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306B\u3088\u3063\u3066\u306F \`ConsistencyLevel: eventual\` \u30D8\u30C3\u30C0\u30FC\u304C\u5FC5\u8981)
|
|
670
|
+
|
|
671
|
+
#### \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3
|
|
672
|
+
- \u7D9A\u304D\u304C\u3042\u308B\u5834\u5408\u30EC\u30B9\u30DD\u30F3\u30B9\u306B \`@odata.nextLink\` \u304C\u542B\u307E\u308C\u308B\u3002\u305D\u306E URL (\u307E\u305F\u306F\u30D1\u30B9) \u3092\u547C\u3073\u51FA\u3057\u3066\u6B21\u30DA\u30FC\u30B8\u3092\u53D6\u5F97
|
|
673
|
+
|
|
674
|
+
#### Tips
|
|
675
|
+
- \u30B5\u30A4\u30F3\u30A4\u30F3\u30E6\u30FC\u30B6\u30FC\u306B\u306F\u5FC5\u305A \`/me\` \u3092\u4F7F\u7528 \u2014 \u4ED6\u30E6\u30FC\u30B6\u30FC\u306E ID \u3092\u5165\u308C\u306A\u3044
|
|
676
|
+
- \u30DA\u30A4\u30ED\u30FC\u30C9\u80A5\u5927\u5316\u3092\u907F\u3051\u308B\u305F\u3081 \`$select\` \u3092\u6D3B\u7528\u3002HTML \u672C\u6587\u8FBC\u307F\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u306F MB \u5358\u4F4D\u306B\u306A\u308B\u3053\u3068\u304C\u3042\u308B
|
|
677
|
+
- \`bodyPreview\` (\u5148\u982D\u7D04 255 \u6587\u5B57) \u306F\u30C7\u30D5\u30A9\u30EB\u30C8\u3067\u542B\u307E\u308C\u3066\u304A\u308A\u3001\u30C8\u30EA\u30A2\u30FC\u30B8\u306B\u4FBF\u5229
|
|
678
|
+
- \u65E5\u6642\u5024\u306F ISO-8601\u3002\u30AB\u30EC\u30F3\u30C0\u30FC\u30A4\u30D9\u30F3\u30C8\u306B\u306F \`timeZone\` \u30D5\u30A3\u30FC\u30EB\u30C9\u3082\u542B\u307E\u308C\u308B
|
|
679
|
+
|
|
680
|
+
### Business Logic
|
|
681
|
+
|
|
682
|
+
\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\u30BF SDK \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\`INTERNAL_SQUADBASE_*\` \u306E\u74B0\u5883\u5909\u6570\u3092\u4F7F\u3063\u3066\u624B\u52D5\u3067 OAuth \u30D7\u30ED\u30AD\u30B7\u3092\u53E9\u304F\u3053\u3068\u3082\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044 \u2014 SDK \u304C OAuth \u3092\u51E6\u7406\u3057\u307E\u3059\u3002
|
|
683
|
+
|
|
684
|
+
SDK (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
685
|
+
|
|
686
|
+
\u30E1\u30FC\u30EB:
|
|
687
|
+
- \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u8A8D\u8A3C\u4ED8\u304D fetch (path \u306F \`https://graph.microsoft.com/v1.0\` \u306B\u8FFD\u52A0\u3055\u308C\u307E\u3059)
|
|
688
|
+
- \`client.getProfile()\` \u2014 \u8A8D\u8A3C\u30E6\u30FC\u30B6\u30FC\u306E\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u3092\u53D6\u5F97
|
|
689
|
+
- \`client.listMailFolders()\` \u2014 \u5168\u30E1\u30FC\u30EB\u30D5\u30A9\u30EB\u30C0\u3092\u4E00\u89A7
|
|
690
|
+
- \`client.listMessages(options?)\` \u2014 \u30E1\u30C3\u30BB\u30FC\u30B8\u4E00\u89A7 (\`top\`, \`skip\`, \`filter\`, \`orderBy\`, \`select\`, \`search\` \u5BFE\u5FDC)
|
|
691
|
+
- \`client.listMessagesInFolder(folderId, options?)\` \u2014 \u30D5\u30A9\u30EB\u30C0\u5185\u306E\u30E1\u30C3\u30BB\u30FC\u30B8\u4E00\u89A7 (\`inbox\` \u306A\u3069\u306E well-known \u540D\u3082\u4F7F\u7528\u53EF)
|
|
692
|
+
- \`client.getMessage(id, options?)\` \u2014 \u7279\u5B9A\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D6\u5F97
|
|
693
|
+
- \`client.listConversation(conversationId, options?)\` \u2014 \u30B9\u30EC\u30C3\u30C9\u5185\u306E\u5168\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u53D6\u5F97 (Gmail \`getThread\` \u76F8\u5F53\u3001\u30C7\u30D5\u30A9\u30EB\u30C8\u3067\u53E4\u3044\u9806)
|
|
694
|
+
|
|
695
|
+
\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB:
|
|
696
|
+
- \`client.listAttachments(messageId)\` \u2014 \u30E1\u30C3\u30BB\u30FC\u30B8\u306E\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u4E00\u89A7
|
|
697
|
+
- \`client.getAttachment(messageId, attachmentId)\` \u2014 \u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u5358\u4F53\u53D6\u5F97 (file attachment \u306F base64 \u306E \`contentBytes\` \u3092\u542B\u3080)
|
|
698
|
+
|
|
699
|
+
\u30AB\u30EC\u30F3\u30C0\u30FC:
|
|
700
|
+
- \`client.listCalendars()\` \u2014 \u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30AB\u30EC\u30F3\u30C0\u30FC\u4E00\u89A7
|
|
701
|
+
- \`client.listEvents(options?)\` \u2014 \u30C7\u30D5\u30A9\u30EB\u30C8\u30AB\u30EC\u30F3\u30C0\u30FC\u306E\u30A4\u30D9\u30F3\u30C8\u4E00\u89A7 (\`{ calendarId }\` \u3067\u7279\u5B9A\u30AB\u30EC\u30F3\u30C0\u30FC\u6307\u5B9A\u53EF)\u3002\u7E70\u308A\u8FD4\u3057\u30A4\u30D9\u30F3\u30C8\u306F series master \u3068\u3057\u3066\u8FD4\u5374
|
|
702
|
+
- \`client.getEvent(id)\` \u2014 \u30A4\u30D9\u30F3\u30C8\u5358\u4F53\u53D6\u5F97
|
|
703
|
+
- \`client.listCalendarView(startDateTime, endDateTime, options?)\` \u2014 \u65E5\u4ED8\u7BC4\u56F2\u5185\u306E\u30A4\u30D9\u30F3\u30C8 **occurrence** \u4E00\u89A7 (\u7E70\u308A\u8FD4\u3057\u3092\u5C55\u958B)\u3002Google Calendar \u306E \`events?singleEvents=true\` \u76F8\u5F53
|
|
704
|
+
|
|
705
|
+
\u30CF\u30F3\u30C9\u30E9\u306E\u30C6\u30B9\u30C8\u304C \`Connection proxy is not configured\` \u3067\u5931\u6557\u3059\u308B\u5834\u5408\u306F\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002SDK \u3092\u8AE6\u3081\u3066 OAuth \u30D7\u30ED\u30AD\u30B7\u306E URL \u3092\u81EA\u5206\u3067\u7D44\u307F\u7ACB\u3066\u308B\u3053\u3068\u306F **\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044**\u3002
|
|
706
|
+
|
|
707
|
+
#### Example
|
|
708
|
+
|
|
709
|
+
\`\`\`ts
|
|
710
|
+
import { connection } from "@squadbase/vite-server/connectors/outlook-oauth";
|
|
711
|
+
|
|
712
|
+
const outlook = connection("<connectionId>");
|
|
713
|
+
|
|
714
|
+
// \u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u53D6\u5F97
|
|
715
|
+
const profile = await outlook.getProfile();
|
|
716
|
+
console.log(profile.displayName, profile.mail);
|
|
717
|
+
|
|
718
|
+
// \u53D7\u4FE1\u30C8\u30EC\u30A4\u306E\u672A\u8AAD\u30E1\u30C3\u30BB\u30FC\u30B8\u6700\u65B010\u4EF6
|
|
719
|
+
const messages = await outlook.listMessagesInFolder("inbox", {
|
|
720
|
+
top: 10,
|
|
721
|
+
filter: "isRead eq false",
|
|
722
|
+
orderBy: "receivedDateTime desc",
|
|
723
|
+
select: ["id", "subject", "from", "receivedDateTime", "bodyPreview", "conversationId"],
|
|
724
|
+
});
|
|
725
|
+
for (const msg of messages.value) {
|
|
726
|
+
console.log(msg.receivedDateTime, msg.from?.emailAddress.address, msg.subject);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// \u30B9\u30EC\u30C3\u30C9\u5168\u4F53\u3092\u53D6\u5F97
|
|
730
|
+
const first = messages.value[0];
|
|
731
|
+
if (first?.conversationId) {
|
|
732
|
+
const thread = await outlook.listConversation(first.conversationId);
|
|
733
|
+
thread.value.forEach(m => console.log(m.receivedDateTime, m.bodyPreview));
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// \u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u3092\u53D6\u5F97
|
|
737
|
+
if (first?.hasAttachments) {
|
|
738
|
+
const atts = await outlook.listAttachments(first.id);
|
|
739
|
+
for (const a of atts.value) {
|
|
740
|
+
const full = await outlook.getAttachment(first.id, a.id);
|
|
741
|
+
console.log(full.name, full.contentType, full.size);
|
|
742
|
+
// full.contentBytes \u306F file attachment \u306E\u5834\u5408 base64
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// \u4ECA\u65E5\u306E\u30AB\u30EC\u30F3\u30C0\u30FC\u30A4\u30D9\u30F3\u30C8 (occurrence \u5C55\u958B)
|
|
747
|
+
const todayStart = new Date(); todayStart.setHours(0, 0, 0, 0);
|
|
748
|
+
const todayEnd = new Date(todayStart); todayEnd.setDate(todayEnd.getDate() + 1);
|
|
749
|
+
const events = await outlook.listCalendarView(
|
|
750
|
+
todayStart.toISOString(),
|
|
751
|
+
todayEnd.toISOString(),
|
|
752
|
+
{ orderBy: "start/dateTime", select: ["id", "subject", "start", "end", "attendees"] },
|
|
753
|
+
);
|
|
754
|
+
events.value.forEach(e => console.log(e.start.dateTime, e.subject));
|
|
755
|
+
\`\`\``
|
|
756
|
+
},
|
|
757
|
+
tools,
|
|
758
|
+
async checkConnection(_params, config) {
|
|
759
|
+
const { proxyFetch } = config;
|
|
760
|
+
const url = "https://graph.microsoft.com/v1.0/me";
|
|
761
|
+
try {
|
|
762
|
+
const res = await proxyFetch(url, { method: "GET" });
|
|
763
|
+
if (!res.ok) {
|
|
764
|
+
const errorText = await res.text().catch(() => res.statusText);
|
|
765
|
+
return {
|
|
766
|
+
success: false,
|
|
767
|
+
error: `Microsoft Graph failed: HTTP ${res.status} ${errorText}`
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
return { success: true };
|
|
771
|
+
} catch (error) {
|
|
772
|
+
return {
|
|
773
|
+
success: false,
|
|
774
|
+
error: error instanceof Error ? error.message : String(error)
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
// src/connectors/create-connector-sdk.ts
|
|
781
|
+
import { readFileSync } from "fs";
|
|
782
|
+
import path from "path";
|
|
783
|
+
|
|
784
|
+
// src/connector-client/env.ts
|
|
785
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
786
|
+
const envVarName = entry.envVars[key];
|
|
787
|
+
if (!envVarName) {
|
|
788
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
789
|
+
}
|
|
790
|
+
const value = process.env[envVarName];
|
|
791
|
+
if (!value) {
|
|
792
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
793
|
+
}
|
|
794
|
+
return value;
|
|
795
|
+
}
|
|
796
|
+
function resolveEnvVarOptional(entry, key) {
|
|
797
|
+
const envVarName = entry.envVars[key];
|
|
798
|
+
if (!envVarName) return void 0;
|
|
799
|
+
return process.env[envVarName] || void 0;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/connector-client/proxy-fetch.ts
|
|
803
|
+
import { getContext } from "hono/context-storage";
|
|
804
|
+
import { getCookie } from "hono/cookie";
|
|
805
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
806
|
+
function normalizeHeaders(input) {
|
|
807
|
+
const out = {};
|
|
808
|
+
if (!input) return out;
|
|
809
|
+
new Headers(input).forEach((value, key) => {
|
|
810
|
+
out[key] = value;
|
|
811
|
+
});
|
|
812
|
+
return out;
|
|
813
|
+
}
|
|
814
|
+
function createSandboxProxyFetch(connectionId) {
|
|
815
|
+
return async (input, init) => {
|
|
816
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
817
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
818
|
+
if (!token || !sandboxId) {
|
|
819
|
+
throw new Error(
|
|
820
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
824
|
+
const originalMethod = init?.method ?? "GET";
|
|
825
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
826
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
827
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
828
|
+
return fetch(proxyUrl, {
|
|
829
|
+
method: "POST",
|
|
830
|
+
headers: {
|
|
831
|
+
"Content-Type": "application/json",
|
|
832
|
+
Authorization: `Bearer ${token}`
|
|
833
|
+
},
|
|
834
|
+
body: JSON.stringify({
|
|
835
|
+
url: originalUrl,
|
|
836
|
+
method: originalMethod,
|
|
837
|
+
headers: normalizeHeaders(init?.headers),
|
|
838
|
+
body: originalBody
|
|
839
|
+
})
|
|
840
|
+
});
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
844
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
845
|
+
if (!projectId) {
|
|
846
|
+
throw new Error(
|
|
847
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
851
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
852
|
+
return async (input, init) => {
|
|
853
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
854
|
+
const originalMethod = init?.method ?? "GET";
|
|
855
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
856
|
+
const c = getContext();
|
|
857
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
858
|
+
if (!appSession) {
|
|
859
|
+
throw new Error(
|
|
860
|
+
"No authentication method available for connection proxy."
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
return fetch(proxyUrl, {
|
|
864
|
+
method: "POST",
|
|
865
|
+
headers: {
|
|
866
|
+
"Content-Type": "application/json",
|
|
867
|
+
Authorization: `Bearer ${appSession}`
|
|
868
|
+
},
|
|
869
|
+
body: JSON.stringify({
|
|
870
|
+
url: originalUrl,
|
|
871
|
+
method: originalMethod,
|
|
872
|
+
headers: normalizeHeaders(init?.headers),
|
|
873
|
+
body: originalBody
|
|
874
|
+
})
|
|
875
|
+
});
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
function createProxyFetch(connectionId) {
|
|
879
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
880
|
+
return createSandboxProxyFetch(connectionId);
|
|
881
|
+
}
|
|
882
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// src/connectors/create-connector-sdk.ts
|
|
886
|
+
function loadConnectionsSync() {
|
|
887
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
888
|
+
try {
|
|
889
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
890
|
+
return JSON.parse(raw);
|
|
891
|
+
} catch {
|
|
892
|
+
return {};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
896
|
+
return (connectionId) => {
|
|
897
|
+
const connections = loadConnectionsSync();
|
|
898
|
+
const entry = connections[connectionId];
|
|
899
|
+
if (!entry) {
|
|
900
|
+
throw new Error(
|
|
901
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
905
|
+
throw new Error(
|
|
906
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
const params = {};
|
|
910
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
911
|
+
if (param.required) {
|
|
912
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
913
|
+
} else {
|
|
914
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
915
|
+
if (val !== void 0) params[param.slug] = val;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// src/connectors/entries/outlook-oauth.ts
|
|
923
|
+
var connection = createConnectorSdk(
|
|
924
|
+
outlookOauthConnector,
|
|
925
|
+
createClient
|
|
926
|
+
);
|
|
927
|
+
export {
|
|
928
|
+
connection
|
|
929
|
+
};
|