@squadbase/vite-server 0.1.3-dev.1 → 0.1.3-dev.3
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 +67381 -4157
- package/dist/connectors/asana.js +1 -1
- package/dist/connectors/customerio.js +1 -1
- package/dist/connectors/gemini.js +1 -1
- package/dist/connectors/gmail-oauth.js +1 -1
- package/dist/connectors/intercom-oauth.js +1 -1
- package/dist/connectors/intercom.js +1 -1
- package/dist/connectors/jira-api-key.js +7 -6
- package/dist/connectors/linkedin-ads-oauth.js +1 -1
- package/dist/connectors/linkedin-ads.js +1 -1
- package/dist/connectors/mailchimp-oauth.js +1 -1
- package/dist/connectors/mailchimp.js +1 -1
- package/dist/connectors/notion-oauth.d.ts +5 -0
- package/dist/connectors/notion-oauth.js +493 -0
- package/dist/connectors/notion.d.ts +5 -0
- package/dist/connectors/notion.js +580 -0
- package/dist/connectors/zendesk-oauth.js +1 -1
- package/dist/connectors/zendesk.js +1 -1
- package/dist/index.js +67270 -1372
- package/dist/main.js +67255 -1357
- package/dist/vite-plugin.js +67154 -1256
- package/package.json +26 -2
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
// ../connectors/src/parameter-definition.ts
|
|
2
|
+
var ParameterDefinition = class {
|
|
3
|
+
slug;
|
|
4
|
+
name;
|
|
5
|
+
description;
|
|
6
|
+
envVarBaseKey;
|
|
7
|
+
type;
|
|
8
|
+
secret;
|
|
9
|
+
required;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.slug = config.slug;
|
|
12
|
+
this.name = config.name;
|
|
13
|
+
this.description = config.description;
|
|
14
|
+
this.envVarBaseKey = config.envVarBaseKey;
|
|
15
|
+
this.type = config.type;
|
|
16
|
+
this.secret = config.secret;
|
|
17
|
+
this.required = config.required;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get the parameter value from a ConnectorConnectionObject.
|
|
21
|
+
*/
|
|
22
|
+
getValue(connection2) {
|
|
23
|
+
const param = connection2.parameters.find(
|
|
24
|
+
(p) => p.parameterSlug === this.slug
|
|
25
|
+
);
|
|
26
|
+
if (!param || param.value == null) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Parameter "${this.slug}" not found or has no value in connection "${connection2.id}"`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return param.value;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Try to get the parameter value. Returns undefined if not found (for optional params).
|
|
35
|
+
*/
|
|
36
|
+
tryGetValue(connection2) {
|
|
37
|
+
const param = connection2.parameters.find(
|
|
38
|
+
(p) => p.parameterSlug === this.slug
|
|
39
|
+
);
|
|
40
|
+
if (!param || param.value == null) return void 0;
|
|
41
|
+
return param.value;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// ../connectors/src/connectors/notion/parameters.ts
|
|
46
|
+
var parameters = {
|
|
47
|
+
apiKey: new ParameterDefinition({
|
|
48
|
+
slug: "api-key",
|
|
49
|
+
name: "Notion Internal Integration Token",
|
|
50
|
+
description: "The Internal Integration Token from your Notion integration settings (starts with ntn_ or secret_).",
|
|
51
|
+
envVarBaseKey: "NOTION_API_KEY",
|
|
52
|
+
type: "text",
|
|
53
|
+
secret: true,
|
|
54
|
+
required: true
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ../connectors/src/connectors/notion/sdk/index.ts
|
|
59
|
+
var BASE_URL = "https://api.notion.com/v1";
|
|
60
|
+
var NOTION_VERSION = "2022-06-28";
|
|
61
|
+
function createClient(params) {
|
|
62
|
+
const apiKey = params[parameters.apiKey.slug];
|
|
63
|
+
if (!apiKey) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`notion: missing required parameter: ${parameters.apiKey.slug}`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function authHeaders(extra) {
|
|
69
|
+
const headers = new Headers(extra);
|
|
70
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
71
|
+
headers.set("Notion-Version", NOTION_VERSION);
|
|
72
|
+
headers.set("Content-Type", "application/json");
|
|
73
|
+
return headers;
|
|
74
|
+
}
|
|
75
|
+
async function assertOk(res, label) {
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
const body = await res.text().catch(() => "(unreadable body)");
|
|
78
|
+
throw new Error(
|
|
79
|
+
`notion ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
request(path2, init) {
|
|
85
|
+
const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
86
|
+
const headers = new Headers(init?.headers);
|
|
87
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
88
|
+
headers.set("Notion-Version", NOTION_VERSION);
|
|
89
|
+
headers.set("Content-Type", "application/json");
|
|
90
|
+
return fetch(url, { ...init, headers });
|
|
91
|
+
},
|
|
92
|
+
async search(options) {
|
|
93
|
+
const body = {};
|
|
94
|
+
if (options?.query) body.query = options.query;
|
|
95
|
+
if (options?.filter) body.filter = options.filter;
|
|
96
|
+
if (options?.sort) body.sort = options.sort;
|
|
97
|
+
if (options?.start_cursor) body.start_cursor = options.start_cursor;
|
|
98
|
+
if (options?.page_size) body.page_size = options.page_size;
|
|
99
|
+
const res = await fetch(`${BASE_URL}/search`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: authHeaders(),
|
|
102
|
+
body: JSON.stringify(body)
|
|
103
|
+
});
|
|
104
|
+
await assertOk(res, "search");
|
|
105
|
+
return await res.json();
|
|
106
|
+
},
|
|
107
|
+
async queryDatabase(databaseId, options) {
|
|
108
|
+
const body = {};
|
|
109
|
+
if (options?.filter) body.filter = options.filter;
|
|
110
|
+
if (options?.sorts) body.sorts = options.sorts;
|
|
111
|
+
if (options?.start_cursor) body.start_cursor = options.start_cursor;
|
|
112
|
+
if (options?.page_size) body.page_size = options.page_size;
|
|
113
|
+
const res = await fetch(
|
|
114
|
+
`${BASE_URL}/databases/${encodeURIComponent(databaseId)}/query`,
|
|
115
|
+
{
|
|
116
|
+
method: "POST",
|
|
117
|
+
headers: authHeaders(),
|
|
118
|
+
body: JSON.stringify(body)
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
await assertOk(res, "queryDatabase");
|
|
122
|
+
return await res.json();
|
|
123
|
+
},
|
|
124
|
+
async getPage(pageId) {
|
|
125
|
+
const res = await fetch(
|
|
126
|
+
`${BASE_URL}/pages/${encodeURIComponent(pageId)}`,
|
|
127
|
+
{ method: "GET", headers: authHeaders() }
|
|
128
|
+
);
|
|
129
|
+
await assertOk(res, "getPage");
|
|
130
|
+
return await res.json();
|
|
131
|
+
},
|
|
132
|
+
async getDatabase(databaseId) {
|
|
133
|
+
const res = await fetch(
|
|
134
|
+
`${BASE_URL}/databases/${encodeURIComponent(databaseId)}`,
|
|
135
|
+
{ method: "GET", headers: authHeaders() }
|
|
136
|
+
);
|
|
137
|
+
await assertOk(res, "getDatabase");
|
|
138
|
+
return await res.json();
|
|
139
|
+
},
|
|
140
|
+
async getBlockChildren(blockId, options) {
|
|
141
|
+
const params2 = new URLSearchParams();
|
|
142
|
+
if (options?.start_cursor)
|
|
143
|
+
params2.set("start_cursor", options.start_cursor);
|
|
144
|
+
if (options?.page_size)
|
|
145
|
+
params2.set("page_size", String(options.page_size));
|
|
146
|
+
const qs = params2.toString();
|
|
147
|
+
const url = `${BASE_URL}/blocks/${encodeURIComponent(blockId)}/children${qs ? `?${qs}` : ""}`;
|
|
148
|
+
const res = await fetch(url, { method: "GET", headers: authHeaders() });
|
|
149
|
+
await assertOk(res, "getBlockChildren");
|
|
150
|
+
return await res.json();
|
|
151
|
+
},
|
|
152
|
+
async listUsers(options) {
|
|
153
|
+
const params2 = new URLSearchParams();
|
|
154
|
+
if (options?.start_cursor)
|
|
155
|
+
params2.set("start_cursor", options.start_cursor);
|
|
156
|
+
if (options?.page_size)
|
|
157
|
+
params2.set("page_size", String(options.page_size));
|
|
158
|
+
const qs = params2.toString();
|
|
159
|
+
const url = `${BASE_URL}/users${qs ? `?${qs}` : ""}`;
|
|
160
|
+
const res = await fetch(url, { method: "GET", headers: authHeaders() });
|
|
161
|
+
await assertOk(res, "listUsers");
|
|
162
|
+
return await res.json();
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ../connectors/src/connector-onboarding.ts
|
|
168
|
+
var ConnectorOnboarding = class {
|
|
169
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
170
|
+
connectionSetupInstructions;
|
|
171
|
+
/** Phase 2: Data overview instructions */
|
|
172
|
+
dataOverviewInstructions;
|
|
173
|
+
constructor(config) {
|
|
174
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
175
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
176
|
+
}
|
|
177
|
+
getConnectionSetupPrompt(language) {
|
|
178
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
179
|
+
}
|
|
180
|
+
getDataOverviewInstructions(language) {
|
|
181
|
+
return this.dataOverviewInstructions[language];
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// ../connectors/src/connector-tool.ts
|
|
186
|
+
var ConnectorTool = class {
|
|
187
|
+
name;
|
|
188
|
+
description;
|
|
189
|
+
inputSchema;
|
|
190
|
+
outputSchema;
|
|
191
|
+
_execute;
|
|
192
|
+
constructor(config) {
|
|
193
|
+
this.name = config.name;
|
|
194
|
+
this.description = config.description;
|
|
195
|
+
this.inputSchema = config.inputSchema;
|
|
196
|
+
this.outputSchema = config.outputSchema;
|
|
197
|
+
this._execute = config.execute;
|
|
198
|
+
}
|
|
199
|
+
createTool(connections, config) {
|
|
200
|
+
return {
|
|
201
|
+
description: this.description,
|
|
202
|
+
inputSchema: this.inputSchema,
|
|
203
|
+
outputSchema: this.outputSchema,
|
|
204
|
+
execute: (input) => this._execute(input, connections, config)
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// ../connectors/src/connector-plugin.ts
|
|
210
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
211
|
+
slug;
|
|
212
|
+
authType;
|
|
213
|
+
name;
|
|
214
|
+
description;
|
|
215
|
+
iconUrl;
|
|
216
|
+
parameters;
|
|
217
|
+
releaseFlag;
|
|
218
|
+
proxyPolicy;
|
|
219
|
+
experimentalAttributes;
|
|
220
|
+
onboarding;
|
|
221
|
+
systemPrompt;
|
|
222
|
+
tools;
|
|
223
|
+
query;
|
|
224
|
+
checkConnection;
|
|
225
|
+
constructor(config) {
|
|
226
|
+
this.slug = config.slug;
|
|
227
|
+
this.authType = config.authType;
|
|
228
|
+
this.name = config.name;
|
|
229
|
+
this.description = config.description;
|
|
230
|
+
this.iconUrl = config.iconUrl;
|
|
231
|
+
this.parameters = config.parameters;
|
|
232
|
+
this.releaseFlag = config.releaseFlag;
|
|
233
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
234
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
235
|
+
this.onboarding = config.onboarding;
|
|
236
|
+
this.systemPrompt = config.systemPrompt;
|
|
237
|
+
this.tools = config.tools;
|
|
238
|
+
this.query = config.query;
|
|
239
|
+
this.checkConnection = config.checkConnection;
|
|
240
|
+
}
|
|
241
|
+
get connectorKey() {
|
|
242
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Create tools for connections that belong to this connector.
|
|
246
|
+
* Filters connections by connectorKey internally.
|
|
247
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
248
|
+
*/
|
|
249
|
+
createTools(connections, config) {
|
|
250
|
+
const myConnections = connections.filter(
|
|
251
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
252
|
+
);
|
|
253
|
+
const result = {};
|
|
254
|
+
for (const t of Object.values(this.tools)) {
|
|
255
|
+
result[`${this.connectorKey}_${t.name}`] = t.createTool(
|
|
256
|
+
myConnections,
|
|
257
|
+
config
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
static deriveKey(slug, authType) {
|
|
263
|
+
return authType ? `${slug}-${authType}` : slug;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// ../connectors/src/connectors/notion/setup.ts
|
|
268
|
+
var notionOnboarding = new ConnectorOnboarding({
|
|
269
|
+
dataOverviewInstructions: {
|
|
270
|
+
en: `1. Call notion_request with POST /search and { "page_size": 5 } to discover available pages and databases
|
|
271
|
+
2. For each database found, call notion_request with POST /databases/{database_id}/query and { "page_size": 5 } to sample records and understand the schema
|
|
272
|
+
3. Call notion_request with GET /users to list workspace members
|
|
273
|
+
4. Explore page content with GET /blocks/{page_id}/children as needed`,
|
|
274
|
+
ja: `1. notion_request \u3067 POST /search \u3092 { "page_size": 5 } \u3067\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30DA\u30FC\u30B8\u3068\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u691C\u51FA
|
|
275
|
+
2. \u898B\u3064\u304B\u3063\u305F\u5404\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306B\u3064\u3044\u3066\u3001notion_request \u3067 POST /databases/{database_id}/query \u3092 { "page_size": 5 } \u3067\u547C\u3073\u51FA\u3057\u3001\u30EC\u30B3\u30FC\u30C9\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u3068\u30B9\u30AD\u30FC\u30DE\u306E\u628A\u63E1\u3092\u884C\u3046
|
|
276
|
+
3. notion_request \u3067 GET /users \u3092\u547C\u3073\u51FA\u3057\u3001\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30E1\u30F3\u30D0\u30FC\u3092\u4E00\u89A7\u8868\u793A
|
|
277
|
+
4. \u5FC5\u8981\u306B\u5FDC\u3058\u3066 GET /blocks/{page_id}/children \u3067\u30DA\u30FC\u30B8\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u63A2\u7D22`
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// ../connectors/src/connectors/notion/tools/request.ts
|
|
282
|
+
import { z } from "zod";
|
|
283
|
+
var BASE_URL2 = "https://api.notion.com/v1";
|
|
284
|
+
var NOTION_VERSION2 = "2022-06-28";
|
|
285
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
286
|
+
var inputSchema = z.object({
|
|
287
|
+
toolUseIntent: z.string().optional().describe(
|
|
288
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
289
|
+
),
|
|
290
|
+
connectionId: z.string().describe("ID of the Notion connection to use"),
|
|
291
|
+
method: z.enum(["GET", "POST", "PATCH", "DELETE"]).describe(
|
|
292
|
+
"HTTP method. GET for reading resources, POST for searching/querying/creating, PATCH for updating, DELETE for deleting."
|
|
293
|
+
),
|
|
294
|
+
path: z.string().describe(
|
|
295
|
+
"API path (e.g., '/search', '/databases/{id}/query', '/pages/{id}', '/blocks/{id}/children')"
|
|
296
|
+
),
|
|
297
|
+
body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST/PATCH requests")
|
|
298
|
+
});
|
|
299
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
300
|
+
z.object({
|
|
301
|
+
success: z.literal(true),
|
|
302
|
+
status: z.number(),
|
|
303
|
+
data: z.record(z.string(), z.unknown())
|
|
304
|
+
}),
|
|
305
|
+
z.object({
|
|
306
|
+
success: z.literal(false),
|
|
307
|
+
error: z.string()
|
|
308
|
+
})
|
|
309
|
+
]);
|
|
310
|
+
var requestTool = new ConnectorTool({
|
|
311
|
+
name: "request",
|
|
312
|
+
description: `Send authenticated requests to the Notion API.
|
|
313
|
+
Authentication (Bearer token) and Notion-Version header are configured automatically.
|
|
314
|
+
Use this tool for all Notion API interactions: searching pages/databases, querying databases, retrieving pages and blocks, managing content.
|
|
315
|
+
Pagination uses cursor-based start_cursor and page_size (max 100).`,
|
|
316
|
+
inputSchema,
|
|
317
|
+
outputSchema,
|
|
318
|
+
async execute({ connectionId, method, path: path2, body }, connections) {
|
|
319
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
320
|
+
if (!connection2) {
|
|
321
|
+
return {
|
|
322
|
+
success: false,
|
|
323
|
+
error: `Connection ${connectionId} not found`
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
console.log(
|
|
327
|
+
`[connector-request] notion/${connection2.name}: ${method} ${path2}`
|
|
328
|
+
);
|
|
329
|
+
try {
|
|
330
|
+
const apiKey = parameters.apiKey.getValue(connection2);
|
|
331
|
+
const url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
332
|
+
const controller = new AbortController();
|
|
333
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
334
|
+
try {
|
|
335
|
+
const response = await fetch(url, {
|
|
336
|
+
method,
|
|
337
|
+
headers: {
|
|
338
|
+
Authorization: `Bearer ${apiKey}`,
|
|
339
|
+
"Notion-Version": NOTION_VERSION2,
|
|
340
|
+
"Content-Type": "application/json"
|
|
341
|
+
},
|
|
342
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
343
|
+
signal: controller.signal
|
|
344
|
+
});
|
|
345
|
+
const data = await response.json();
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
const errorMessage = typeof data?.message === "string" ? data.message : typeof data?.code === "string" ? data.code : `HTTP ${response.status} ${response.statusText}`;
|
|
348
|
+
return { success: false, error: errorMessage };
|
|
349
|
+
}
|
|
350
|
+
return { success: true, status: response.status, data };
|
|
351
|
+
} finally {
|
|
352
|
+
clearTimeout(timeout);
|
|
353
|
+
}
|
|
354
|
+
} catch (err) {
|
|
355
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
356
|
+
return { success: false, error: msg };
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// ../connectors/src/connectors/notion/index.ts
|
|
362
|
+
var tools = { request: requestTool };
|
|
363
|
+
var notionConnector = new ConnectorPlugin({
|
|
364
|
+
slug: "notion",
|
|
365
|
+
authType: null,
|
|
366
|
+
name: "Notion",
|
|
367
|
+
description: "Connect to Notion to query databases, pages, and workspace content using an Internal Integration Token.",
|
|
368
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/797V5GDDTA8bsfKUHBCoQO/290ec49b70b68ddb4acd3bf0a6ab8bda/notion-icon.webp",
|
|
369
|
+
parameters,
|
|
370
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
371
|
+
onboarding: notionOnboarding,
|
|
372
|
+
systemPrompt: {
|
|
373
|
+
en: `### Tools
|
|
374
|
+
|
|
375
|
+
- \`notion_request\`: The only way to call the Notion REST API. Use it to search pages and databases, query database records, retrieve page content and blocks, and manage workspace data. Authentication (Bearer token) and Notion-Version header are configured automatically. Pagination uses cursor-based \`start_cursor\` and \`page_size\` (max 100) with \`has_more\` and \`next_cursor\` in the response.
|
|
376
|
+
|
|
377
|
+
### Business Logic
|
|
378
|
+
|
|
379
|
+
The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
|
|
380
|
+
|
|
381
|
+
SDK methods (client created via \`connection(connectionId)\`):
|
|
382
|
+
- \`client.request(path, init?)\` \u2014 low-level authenticated fetch
|
|
383
|
+
- \`client.search(options?)\` \u2014 search pages and databases by title
|
|
384
|
+
- \`client.queryDatabase(databaseId, options?)\` \u2014 query database records with filter/sorts/pagination
|
|
385
|
+
- \`client.getPage(pageId)\` \u2014 retrieve a page
|
|
386
|
+
- \`client.getDatabase(databaseId)\` \u2014 retrieve a database schema
|
|
387
|
+
- \`client.getBlockChildren(blockId, options?)\` \u2014 retrieve child blocks of a page or block
|
|
388
|
+
- \`client.listUsers(options?)\` \u2014 list workspace users
|
|
389
|
+
|
|
390
|
+
\`\`\`ts
|
|
391
|
+
import type { Context } from "hono";
|
|
392
|
+
import { connection } from "@squadbase/vite-server/connectors/notion";
|
|
393
|
+
|
|
394
|
+
const notion = connection("<connectionId>");
|
|
395
|
+
|
|
396
|
+
export default async function handler(c: Context) {
|
|
397
|
+
const { databaseId, pageSize = 25 } = await c.req.json<{
|
|
398
|
+
databaseId: string;
|
|
399
|
+
pageSize?: number;
|
|
400
|
+
}>();
|
|
401
|
+
|
|
402
|
+
const { results } = await notion.queryDatabase(databaseId, {
|
|
403
|
+
page_size: pageSize,
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
return c.json({ records: results });
|
|
407
|
+
}
|
|
408
|
+
\`\`\`
|
|
409
|
+
|
|
410
|
+
### Notion REST API Reference
|
|
411
|
+
|
|
412
|
+
- Base URL: \`https://api.notion.com/v1\`
|
|
413
|
+
- Authentication: Bearer token (handled automatically)
|
|
414
|
+
- Notion-Version: 2022-06-28 (set automatically)
|
|
415
|
+
- Pagination: Cursor-based with \`start_cursor\`, \`page_size\` (max 100), \`has_more\`, \`next_cursor\`
|
|
416
|
+
|
|
417
|
+
#### Common Endpoints
|
|
418
|
+
- POST \`/search\` \u2014 Search pages and databases by title. Body: \`{ query, filter: { property: "object", value: "page"|"database" }, sort, start_cursor, page_size }\`
|
|
419
|
+
- GET \`/databases/{id}\` \u2014 Retrieve a database (schema, properties)
|
|
420
|
+
- POST \`/databases/{id}/query\` \u2014 Query a database. Body: \`{ filter, sorts, start_cursor, page_size }\`
|
|
421
|
+
- GET \`/pages/{id}\` \u2014 Retrieve a page (properties, metadata)
|
|
422
|
+
- GET \`/pages/{id}/properties/{property_id}\` \u2014 Retrieve a specific page property (for large properties)
|
|
423
|
+
- GET \`/blocks/{id}/children\` \u2014 List child blocks (page content). Query: \`start_cursor\`, \`page_size\`
|
|
424
|
+
- GET \`/blocks/{id}\` \u2014 Retrieve a single block
|
|
425
|
+
- PATCH \`/blocks/{id}/children\` \u2014 Append block children
|
|
426
|
+
- GET \`/users\` \u2014 List workspace users. Query: \`start_cursor\`, \`page_size\`
|
|
427
|
+
- GET \`/users/{id}\` \u2014 Retrieve a user
|
|
428
|
+
- GET \`/users/me\` \u2014 Get the bot user
|
|
429
|
+
- POST \`/pages\` \u2014 Create a page (in a database or as a child of a page)
|
|
430
|
+
- PATCH \`/pages/{id}\` \u2014 Update page properties
|
|
431
|
+
- POST \`/databases\` \u2014 Create a database
|
|
432
|
+
- PATCH \`/databases/{id}\` \u2014 Update a database
|
|
433
|
+
- PATCH \`/blocks/{id}\` \u2014 Update a block
|
|
434
|
+
- DELETE \`/blocks/{id}\` \u2014 Delete a block
|
|
435
|
+
- GET \`/comments?block_id={id}\` \u2014 Retrieve comments on a block or page
|
|
436
|
+
- POST \`/comments\` \u2014 Create a comment
|
|
437
|
+
|
|
438
|
+
#### Tips
|
|
439
|
+
- Use POST /search to discover databases and pages shared with the integration
|
|
440
|
+
- Database queries return page objects with properties matching the database schema
|
|
441
|
+
- Block children are only first-level; recurse for nested content
|
|
442
|
+
- Properties with more than 25 items (e.g., people, relation) need the property endpoint for full data`,
|
|
443
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
444
|
+
|
|
445
|
+
- \`notion_request\`: Notion REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30DA\u30FC\u30B8\u3084\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u691C\u7D22\u3001\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30EC\u30B3\u30FC\u30C9\u306E\u30AF\u30A8\u30EA\u3001\u30DA\u30FC\u30B8\u30B3\u30F3\u30C6\u30F3\u30C4\u3084\u30D6\u30ED\u30C3\u30AF\u306E\u53D6\u5F97\u3001\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30C7\u30FC\u30BF\u306E\u7BA1\u7406\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08Bearer\u30C8\u30FC\u30AF\u30F3\uFF09\u3068Notion-Version\u30D8\u30C3\u30C0\u30FC\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u306F\u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`has_more\` \u3068 \`next_cursor\` \u306B\u3088\u308B\u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9\u3067\u3001\`start_cursor\` \u3068 \`page_size\`\uFF08\u6700\u5927100\uFF09\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002
|
|
446
|
+
|
|
447
|
+
### Business Logic
|
|
448
|
+
|
|
449
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
450
|
+
|
|
451
|
+
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
452
|
+
- \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
|
|
453
|
+
- \`client.search(options?)\` \u2014 \u30BF\u30A4\u30C8\u30EB\u3067\u30DA\u30FC\u30B8\u3068\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u691C\u7D22
|
|
454
|
+
- \`client.queryDatabase(databaseId, options?)\` \u2014 \u30D5\u30A3\u30EB\u30BF/\u30BD\u30FC\u30C8/\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u4ED8\u304D\u3067\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30EC\u30B3\u30FC\u30C9\u3092\u30AF\u30A8\u30EA
|
|
455
|
+
- \`client.getPage(pageId)\` \u2014 \u30DA\u30FC\u30B8\u3092\u53D6\u5F97
|
|
456
|
+
- \`client.getDatabase(databaseId)\` \u2014 \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30B9\u30AD\u30FC\u30DE\u3092\u53D6\u5F97
|
|
457
|
+
- \`client.getBlockChildren(blockId, options?)\` \u2014 \u30DA\u30FC\u30B8\u307E\u305F\u306F\u30D6\u30ED\u30C3\u30AF\u306E\u5B50\u30D6\u30ED\u30C3\u30AF\u3092\u53D6\u5F97
|
|
458
|
+
- \`client.listUsers(options?)\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30E6\u30FC\u30B6\u30FC\u3092\u4E00\u89A7\u8868\u793A
|
|
459
|
+
|
|
460
|
+
\`\`\`ts
|
|
461
|
+
import type { Context } from "hono";
|
|
462
|
+
import { connection } from "@squadbase/vite-server/connectors/notion";
|
|
463
|
+
|
|
464
|
+
const notion = connection("<connectionId>");
|
|
465
|
+
|
|
466
|
+
export default async function handler(c: Context) {
|
|
467
|
+
const { databaseId, pageSize = 25 } = await c.req.json<{
|
|
468
|
+
databaseId: string;
|
|
469
|
+
pageSize?: number;
|
|
470
|
+
}>();
|
|
471
|
+
|
|
472
|
+
const { results } = await notion.queryDatabase(databaseId, {
|
|
473
|
+
page_size: pageSize,
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
return c.json({ records: results });
|
|
477
|
+
}
|
|
478
|
+
\`\`\`
|
|
479
|
+
|
|
480
|
+
### Notion REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
481
|
+
|
|
482
|
+
- \u30D9\u30FC\u30B9URL: \`https://api.notion.com/v1\`
|
|
483
|
+
- \u8A8D\u8A3C: Bearer\u30C8\u30FC\u30AF\u30F3\uFF08\u81EA\u52D5\u8A2D\u5B9A\uFF09
|
|
484
|
+
- Notion-Version: 2022-06-28\uFF08\u81EA\u52D5\u8A2D\u5B9A\uFF09
|
|
485
|
+
- \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3: \u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9\uFF08\`start_cursor\`, \`page_size\`\uFF08\u6700\u5927100\uFF09, \`has_more\`, \`next_cursor\`\uFF09
|
|
486
|
+
|
|
487
|
+
#### \u4E3B\u8981\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
|
|
488
|
+
- POST \`/search\` \u2014 \u30DA\u30FC\u30B8\u3068\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30BF\u30A4\u30C8\u30EB\u3067\u691C\u7D22\u3002Body: \`{ query, filter: { property: "object", value: "page"|"database" }, sort, start_cursor, page_size }\`
|
|
489
|
+
- GET \`/databases/{id}\` \u2014 \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u53D6\u5F97\uFF08\u30B9\u30AD\u30FC\u30DE\u3001\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09
|
|
490
|
+
- POST \`/databases/{id}/query\` \u2014 \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u30AF\u30A8\u30EA\u3002Body: \`{ filter, sorts, start_cursor, page_size }\`
|
|
491
|
+
- GET \`/pages/{id}\` \u2014 \u30DA\u30FC\u30B8\u3092\u53D6\u5F97\uFF08\u30D7\u30ED\u30D1\u30C6\u30A3\u3001\u30E1\u30BF\u30C7\u30FC\u30BF\uFF09
|
|
492
|
+
- GET \`/pages/{id}/properties/{property_id}\` \u2014 \u7279\u5B9A\u306E\u30DA\u30FC\u30B8\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u53D6\u5F97\uFF08\u5927\u304D\u306A\u30D7\u30ED\u30D1\u30C6\u30A3\u7528\uFF09
|
|
493
|
+
- GET \`/blocks/{id}/children\` \u2014 \u5B50\u30D6\u30ED\u30C3\u30AF\u3092\u4E00\u89A7\u8868\u793A\uFF08\u30DA\u30FC\u30B8\u30B3\u30F3\u30C6\u30F3\u30C4\uFF09\u3002Query: \`start_cursor\`, \`page_size\`
|
|
494
|
+
- GET \`/blocks/{id}\` \u2014 \u5358\u4E00\u30D6\u30ED\u30C3\u30AF\u3092\u53D6\u5F97
|
|
495
|
+
- PATCH \`/blocks/{id}/children\` \u2014 \u5B50\u30D6\u30ED\u30C3\u30AF\u3092\u8FFD\u52A0
|
|
496
|
+
- GET \`/users\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u30E6\u30FC\u30B6\u30FC\u3092\u4E00\u89A7\u8868\u793A\u3002Query: \`start_cursor\`, \`page_size\`
|
|
497
|
+
- GET \`/users/{id}\` \u2014 \u30E6\u30FC\u30B6\u30FC\u3092\u53D6\u5F97
|
|
498
|
+
- GET \`/users/me\` \u2014 \u30DC\u30C3\u30C8\u30E6\u30FC\u30B6\u30FC\u3092\u53D6\u5F97
|
|
499
|
+
- POST \`/pages\` \u2014 \u30DA\u30FC\u30B8\u3092\u4F5C\u6210\uFF08\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u5185\u307E\u305F\u306F\u30DA\u30FC\u30B8\u306E\u5B50\u3068\u3057\u3066\uFF09
|
|
500
|
+
- PATCH \`/pages/{id}\` \u2014 \u30DA\u30FC\u30B8\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u66F4\u65B0
|
|
501
|
+
- POST \`/databases\` \u2014 \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u4F5C\u6210
|
|
502
|
+
- PATCH \`/databases/{id}\` \u2014 \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u66F4\u65B0
|
|
503
|
+
- PATCH \`/blocks/{id}\` \u2014 \u30D6\u30ED\u30C3\u30AF\u3092\u66F4\u65B0
|
|
504
|
+
- DELETE \`/blocks/{id}\` \u2014 \u30D6\u30ED\u30C3\u30AF\u3092\u524A\u9664
|
|
505
|
+
- GET \`/comments?block_id={id}\` \u2014 \u30D6\u30ED\u30C3\u30AF\u307E\u305F\u306F\u30DA\u30FC\u30B8\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u53D6\u5F97
|
|
506
|
+
- POST \`/comments\` \u2014 \u30B3\u30E1\u30F3\u30C8\u3092\u4F5C\u6210
|
|
507
|
+
|
|
508
|
+
#### \u30D2\u30F3\u30C8
|
|
509
|
+
- POST /search \u3092\u4F7F\u7528\u3057\u3066\u30A4\u30F3\u30C6\u30B0\u30EC\u30FC\u30B7\u30E7\u30F3\u3068\u5171\u6709\u3055\u308C\u305F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3084\u30DA\u30FC\u30B8\u3092\u691C\u51FA\u3057\u307E\u3059
|
|
510
|
+
- \u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30AF\u30A8\u30EA\u306F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30B9\u30AD\u30FC\u30DE\u306B\u4E00\u81F4\u3059\u308B\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u6301\u3064\u30DA\u30FC\u30B8\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3092\u8FD4\u3057\u307E\u3059
|
|
511
|
+
- \u30D6\u30ED\u30C3\u30AF\u306E\u5B50\u306F\u6700\u521D\u306E\u30EC\u30D9\u30EB\u306E\u307F\u3067\u3059\u3002\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30B3\u30F3\u30C6\u30F3\u30C4\u306B\u306F\u518D\u5E30\u304C\u5FC5\u8981\u3067\u3059
|
|
512
|
+
- 25\u4EF6\u4EE5\u4E0A\u306E\u30A2\u30A4\u30C6\u30E0\u3092\u6301\u3064\u30D7\u30ED\u30D1\u30C6\u30A3\uFF08people\u3001relation\u306A\u3069\uFF09\u306F\u5B8C\u5168\u306A\u30C7\u30FC\u30BF\u53D6\u5F97\u306B\u30D7\u30ED\u30D1\u30C6\u30A3\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u304C\u5FC5\u8981\u3067\u3059`
|
|
513
|
+
},
|
|
514
|
+
tools
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// src/connectors/create-connector-sdk.ts
|
|
518
|
+
import { readFileSync } from "fs";
|
|
519
|
+
import path from "path";
|
|
520
|
+
|
|
521
|
+
// src/connector-client/env.ts
|
|
522
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
523
|
+
const envVarName = entry.envVars[key];
|
|
524
|
+
if (!envVarName) {
|
|
525
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
526
|
+
}
|
|
527
|
+
const value = process.env[envVarName];
|
|
528
|
+
if (!value) {
|
|
529
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
530
|
+
}
|
|
531
|
+
return value;
|
|
532
|
+
}
|
|
533
|
+
function resolveEnvVarOptional(entry, key) {
|
|
534
|
+
const envVarName = entry.envVars[key];
|
|
535
|
+
if (!envVarName) return void 0;
|
|
536
|
+
return process.env[envVarName] || void 0;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/connectors/create-connector-sdk.ts
|
|
540
|
+
function loadConnectionsSync() {
|
|
541
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
542
|
+
try {
|
|
543
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
544
|
+
return JSON.parse(raw);
|
|
545
|
+
} catch {
|
|
546
|
+
return {};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
550
|
+
return (connectionId) => {
|
|
551
|
+
const connections = loadConnectionsSync();
|
|
552
|
+
const entry = connections[connectionId];
|
|
553
|
+
if (!entry) {
|
|
554
|
+
throw new Error(
|
|
555
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
559
|
+
throw new Error(
|
|
560
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
const params = {};
|
|
564
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
565
|
+
if (param.required) {
|
|
566
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
567
|
+
} else {
|
|
568
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
569
|
+
if (val !== void 0) params[param.slug] = val;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return createClient2(params);
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// src/connectors/entries/notion.ts
|
|
577
|
+
var connection = createConnectorSdk(notionConnector, createClient);
|
|
578
|
+
export {
|
|
579
|
+
connection
|
|
580
|
+
};
|
|
@@ -285,7 +285,7 @@ var zendeskOauthConnector = new ConnectorPlugin({
|
|
|
285
285
|
authType: AUTH_TYPES.OAUTH,
|
|
286
286
|
name: "Zendesk (OAuth)",
|
|
287
287
|
description: "Connect to Zendesk Support for tickets, users, organizations, and customer service data using OAuth.",
|
|
288
|
-
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/
|
|
288
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7e9Q7PwV6MJRJMj543m2gl/55385fae903ccfa1599e35be9d3516aa/zendesk-icon.svg",
|
|
289
289
|
parameters,
|
|
290
290
|
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
291
291
|
onboarding: zendeskOauthOnboarding,
|
|
@@ -384,7 +384,7 @@ var zendeskConnector = new ConnectorPlugin({
|
|
|
384
384
|
authType: null,
|
|
385
385
|
name: "Zendesk",
|
|
386
386
|
description: "Connect to Zendesk Support for tickets, users, organizations, and customer service data using an API token.",
|
|
387
|
-
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/
|
|
387
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7e9Q7PwV6MJRJMj543m2gl/55385fae903ccfa1599e35be9d3516aa/zendesk-icon.svg",
|
|
388
388
|
parameters,
|
|
389
389
|
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
390
390
|
onboarding: zendeskOnboarding,
|