@squadbase/vite-server 0.1.3-dev.0 → 0.1.3-dev.1

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.
Files changed (34) hide show
  1. package/dist/cli/index.js +13282 -4299
  2. package/dist/connectors/asana.d.ts +5 -0
  3. package/dist/connectors/asana.js +661 -0
  4. package/dist/connectors/customerio.d.ts +5 -0
  5. package/dist/connectors/customerio.js +633 -0
  6. package/dist/connectors/gmail-oauth.d.ts +5 -0
  7. package/dist/connectors/gmail-oauth.js +639 -0
  8. package/dist/connectors/google-ads.d.ts +5 -0
  9. package/dist/connectors/google-ads.js +784 -0
  10. package/dist/connectors/google-sheets.d.ts +5 -0
  11. package/dist/connectors/google-sheets.js +598 -0
  12. package/dist/connectors/hubspot.js +14 -5
  13. package/dist/connectors/intercom-oauth.d.ts +5 -0
  14. package/dist/connectors/intercom-oauth.js +510 -0
  15. package/dist/connectors/intercom.d.ts +5 -0
  16. package/dist/connectors/intercom.js +627 -0
  17. package/dist/connectors/jira-api-key.d.ts +5 -0
  18. package/dist/connectors/jira-api-key.js +523 -0
  19. package/dist/connectors/linkedin-ads-oauth.d.ts +5 -0
  20. package/dist/connectors/linkedin-ads-oauth.js +774 -0
  21. package/dist/connectors/linkedin-ads.d.ts +5 -0
  22. package/dist/connectors/linkedin-ads.js +782 -0
  23. package/dist/connectors/mailchimp-oauth.d.ts +5 -0
  24. package/dist/connectors/mailchimp-oauth.js +539 -0
  25. package/dist/connectors/mailchimp.d.ts +5 -0
  26. package/dist/connectors/mailchimp.js +646 -0
  27. package/dist/connectors/zendesk-oauth.d.ts +5 -0
  28. package/dist/connectors/zendesk-oauth.js +505 -0
  29. package/dist/connectors/zendesk.d.ts +5 -0
  30. package/dist/connectors/zendesk.js +631 -0
  31. package/dist/index.js +13238 -4255
  32. package/dist/main.js +13240 -4257
  33. package/dist/vite-plugin.js +13240 -4257
  34. package/package.json +42 -2
@@ -0,0 +1,5 @@
1
+ import * as _squadbase_connectors_sdk from '@squadbase/connectors/sdk';
2
+
3
+ declare const connection: (connectionId: string) => _squadbase_connectors_sdk.AsanaConnectorSdk;
4
+
5
+ export { connection };
@@ -0,0 +1,661 @@
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/asana/parameters.ts
46
+ var parameters = {
47
+ personalAccessToken: new ParameterDefinition({
48
+ slug: "personal-access-token",
49
+ name: "Asana Personal Access Token",
50
+ description: "Personal Access Token for Asana API authentication. Generate one at https://app.asana.com/0/my-apps",
51
+ envVarBaseKey: "ASANA_PERSONAL_ACCESS_TOKEN",
52
+ type: "text",
53
+ secret: true,
54
+ required: true
55
+ })
56
+ };
57
+
58
+ // ../connectors/src/connectors/asana/sdk/index.ts
59
+ var BASE_URL = "https://app.asana.com/api/1.0";
60
+ function createClient(params) {
61
+ const token = params[parameters.personalAccessToken.slug];
62
+ if (!token) {
63
+ throw new Error(
64
+ `asana: missing required parameter: ${parameters.personalAccessToken.slug}`
65
+ );
66
+ }
67
+ function authHeaders(extra) {
68
+ const headers = new Headers(extra);
69
+ headers.set("Authorization", `Bearer ${token}`);
70
+ headers.set("Content-Type", "application/json");
71
+ headers.set("Accept", "application/json");
72
+ return headers;
73
+ }
74
+ async function assertOk(res, label) {
75
+ if (!res.ok) {
76
+ const body = await res.text().catch(() => "(unreadable body)");
77
+ throw new Error(
78
+ `asana ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
79
+ );
80
+ }
81
+ }
82
+ function buildQuery(base, opt_fields) {
83
+ const params2 = new URLSearchParams();
84
+ for (const [key, value] of Object.entries(base)) {
85
+ if (value !== void 0) params2.set(key, String(value));
86
+ }
87
+ if (opt_fields && opt_fields.length > 0) {
88
+ params2.set("opt_fields", opt_fields.join(","));
89
+ }
90
+ const qs = params2.toString();
91
+ return qs ? `?${qs}` : "";
92
+ }
93
+ return {
94
+ request(path2, init) {
95
+ const url = `${BASE_URL}${path2}`;
96
+ const headers = new Headers(init?.headers);
97
+ headers.set("Authorization", `Bearer ${token}`);
98
+ headers.set("Content-Type", "application/json");
99
+ headers.set("Accept", "application/json");
100
+ return fetch(url, { ...init, headers });
101
+ },
102
+ async listWorkspaces(options) {
103
+ const qs = buildQuery(
104
+ { limit: options?.limit, offset: options?.offset },
105
+ options?.opt_fields
106
+ );
107
+ const res = await fetch(`${BASE_URL}/workspaces${qs}`, {
108
+ method: "GET",
109
+ headers: authHeaders()
110
+ });
111
+ await assertOk(res, "listWorkspaces");
112
+ return await res.json();
113
+ },
114
+ async listProjects(workspaceGid, options) {
115
+ const qs = buildQuery(
116
+ {
117
+ workspace: workspaceGid,
118
+ archived: options?.archived,
119
+ limit: options?.limit,
120
+ offset: options?.offset
121
+ },
122
+ options?.opt_fields
123
+ );
124
+ const res = await fetch(`${BASE_URL}/projects${qs}`, {
125
+ method: "GET",
126
+ headers: authHeaders()
127
+ });
128
+ await assertOk(res, "listProjects");
129
+ return await res.json();
130
+ },
131
+ async listTasks(projectGid, options) {
132
+ const qs = buildQuery(
133
+ {
134
+ project: projectGid,
135
+ completed_since: options?.completed_since,
136
+ limit: options?.limit,
137
+ offset: options?.offset
138
+ },
139
+ options?.opt_fields
140
+ );
141
+ const res = await fetch(`${BASE_URL}/tasks${qs}`, {
142
+ method: "GET",
143
+ headers: authHeaders()
144
+ });
145
+ await assertOk(res, "listTasks");
146
+ return await res.json();
147
+ },
148
+ async getTask(taskGid, options) {
149
+ const qs = buildQuery({}, options?.opt_fields);
150
+ const res = await fetch(
151
+ `${BASE_URL}/tasks/${encodeURIComponent(taskGid)}${qs}`,
152
+ { method: "GET", headers: authHeaders() }
153
+ );
154
+ await assertOk(res, "getTask");
155
+ return await res.json();
156
+ },
157
+ async createTask(taskData) {
158
+ const res = await fetch(`${BASE_URL}/tasks`, {
159
+ method: "POST",
160
+ headers: authHeaders(),
161
+ body: JSON.stringify({ data: taskData })
162
+ });
163
+ await assertOk(res, "createTask");
164
+ return await res.json();
165
+ },
166
+ async updateTask(taskGid, taskData) {
167
+ const res = await fetch(
168
+ `${BASE_URL}/tasks/${encodeURIComponent(taskGid)}`,
169
+ {
170
+ method: "PUT",
171
+ headers: authHeaders(),
172
+ body: JSON.stringify({ data: taskData })
173
+ }
174
+ );
175
+ await assertOk(res, "updateTask");
176
+ return await res.json();
177
+ },
178
+ async listUsers(workspaceGid, options) {
179
+ const qs = buildQuery(
180
+ {
181
+ workspace: workspaceGid,
182
+ limit: options?.limit,
183
+ offset: options?.offset
184
+ },
185
+ options?.opt_fields
186
+ );
187
+ const res = await fetch(`${BASE_URL}/users${qs}`, {
188
+ method: "GET",
189
+ headers: authHeaders()
190
+ });
191
+ await assertOk(res, "listUsers");
192
+ return await res.json();
193
+ }
194
+ };
195
+ }
196
+
197
+ // ../connectors/src/connector-onboarding.ts
198
+ var ConnectorOnboarding = class {
199
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
200
+ connectionSetupInstructions;
201
+ /** Phase 2: Data overview instructions */
202
+ dataOverviewInstructions;
203
+ constructor(config) {
204
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
205
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
206
+ }
207
+ getConnectionSetupPrompt(language) {
208
+ return this.connectionSetupInstructions?.[language] ?? null;
209
+ }
210
+ getDataOverviewInstructions(language) {
211
+ return this.dataOverviewInstructions[language];
212
+ }
213
+ };
214
+
215
+ // ../connectors/src/connector-tool.ts
216
+ var ConnectorTool = class {
217
+ name;
218
+ description;
219
+ inputSchema;
220
+ outputSchema;
221
+ _execute;
222
+ constructor(config) {
223
+ this.name = config.name;
224
+ this.description = config.description;
225
+ this.inputSchema = config.inputSchema;
226
+ this.outputSchema = config.outputSchema;
227
+ this._execute = config.execute;
228
+ }
229
+ createTool(connections, config) {
230
+ return {
231
+ description: this.description,
232
+ inputSchema: this.inputSchema,
233
+ outputSchema: this.outputSchema,
234
+ execute: (input) => this._execute(input, connections, config)
235
+ };
236
+ }
237
+ };
238
+
239
+ // ../connectors/src/connector-plugin.ts
240
+ var ConnectorPlugin = class _ConnectorPlugin {
241
+ slug;
242
+ authType;
243
+ name;
244
+ description;
245
+ iconUrl;
246
+ parameters;
247
+ releaseFlag;
248
+ proxyPolicy;
249
+ experimentalAttributes;
250
+ onboarding;
251
+ systemPrompt;
252
+ tools;
253
+ query;
254
+ checkConnection;
255
+ constructor(config) {
256
+ this.slug = config.slug;
257
+ this.authType = config.authType;
258
+ this.name = config.name;
259
+ this.description = config.description;
260
+ this.iconUrl = config.iconUrl;
261
+ this.parameters = config.parameters;
262
+ this.releaseFlag = config.releaseFlag;
263
+ this.proxyPolicy = config.proxyPolicy;
264
+ this.experimentalAttributes = config.experimentalAttributes;
265
+ this.onboarding = config.onboarding;
266
+ this.systemPrompt = config.systemPrompt;
267
+ this.tools = config.tools;
268
+ this.query = config.query;
269
+ this.checkConnection = config.checkConnection;
270
+ }
271
+ get connectorKey() {
272
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
273
+ }
274
+ /**
275
+ * Create tools for connections that belong to this connector.
276
+ * Filters connections by connectorKey internally.
277
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
278
+ */
279
+ createTools(connections, config) {
280
+ const myConnections = connections.filter(
281
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
282
+ );
283
+ const result = {};
284
+ for (const t of Object.values(this.tools)) {
285
+ result[`${this.connectorKey}_${t.name}`] = t.createTool(
286
+ myConnections,
287
+ config
288
+ );
289
+ }
290
+ return result;
291
+ }
292
+ static deriveKey(slug, authType) {
293
+ return authType ? `${slug}-${authType}` : slug;
294
+ }
295
+ };
296
+
297
+ // ../connectors/src/connectors/asana/setup.ts
298
+ var asanaOnboarding = new ConnectorOnboarding({
299
+ dataOverviewInstructions: {
300
+ en: `1. Call asana_request with GET /workspaces to list all available workspaces
301
+ 2. Pick the first workspace and call asana_request with GET /projects?workspace=WORKSPACE_GID&opt_fields=name,archived,created_at to list projects
302
+ 3. Pick one project and call asana_request with GET /tasks?project=PROJECT_GID&opt_fields=name,completed,assignee.name,due_on,created_at&limit=10 to sample tasks
303
+ 4. Explore sections via GET /sections?project=PROJECT_GID if the project uses board or section-based workflows`,
304
+ ja: `1. asana_request \u3067 GET /workspaces \u3092\u547C\u3073\u51FA\u3057\u3001\u5229\u7528\u53EF\u80FD\u306A\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u4E00\u89A7\u3092\u53D6\u5F97
305
+ 2. \u6700\u521D\u306E\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3092\u9078\u3073\u3001asana_request \u3067 GET /projects?workspace=WORKSPACE_GID&opt_fields=name,archived,created_at \u3092\u547C\u3073\u51FA\u3057\u3066\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7\u3092\u53D6\u5F97
306
+ 3. \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30921\u3064\u9078\u3073\u3001asana_request \u3067 GET /tasks?project=PROJECT_GID&opt_fields=name,completed,assignee.name,due_on,created_at&limit=10 \u3092\u547C\u3073\u51FA\u3057\u3066\u30BF\u30B9\u30AF\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0
307
+ 4. \u30DC\u30FC\u30C9\u3084\u30BB\u30AF\u30B7\u30E7\u30F3\u30D9\u30FC\u30B9\u306E\u30EF\u30FC\u30AF\u30D5\u30ED\u30FC\u306E\u5834\u5408\u306F GET /sections?project=PROJECT_GID \u3067\u30BB\u30AF\u30B7\u30E7\u30F3\u3092\u78BA\u8A8D`
308
+ }
309
+ });
310
+
311
+ // ../connectors/src/connectors/asana/tools/request.ts
312
+ import { z } from "zod";
313
+ var BASE_URL2 = "https://app.asana.com/api/1.0";
314
+ var REQUEST_TIMEOUT_MS = 6e4;
315
+ var inputSchema = z.object({
316
+ toolUseIntent: z.string().optional().describe(
317
+ "Brief description of what you intend to accomplish with this tool call"
318
+ ),
319
+ connectionId: z.string().describe("ID of the Asana connection to use"),
320
+ method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe(
321
+ "HTTP method. GET for reading resources, POST for creating, PUT for updating, DELETE for removing."
322
+ ),
323
+ path: z.string().describe(
324
+ "API path (e.g., '/workspaces', '/projects', '/tasks', '/tasks/{task_gid}'). Query parameters can be appended (e.g., '/tasks?project=PROJECT_GID&opt_fields=name,completed')."
325
+ ),
326
+ body: z.record(z.string(), z.unknown()).optional().describe(
327
+ 'Request body (JSON) for POST/PUT requests. Wrap payload in a "data" key (e.g., { "data": { "name": "My Task", "workspace": "WORKSPACE_GID" } }).'
328
+ )
329
+ });
330
+ var outputSchema = z.discriminatedUnion("success", [
331
+ z.object({
332
+ success: z.literal(true),
333
+ status: z.number(),
334
+ data: z.record(z.string(), z.unknown())
335
+ }),
336
+ z.object({
337
+ success: z.literal(false),
338
+ error: z.string()
339
+ })
340
+ ]);
341
+ var requestTool = new ConnectorTool({
342
+ name: "request",
343
+ description: `Send authenticated requests to the Asana REST API.
344
+ Authentication is handled automatically using the Personal Access Token (Bearer token).
345
+ Provide the API path relative to the base URL (https://app.asana.com/api/1.0).
346
+ Use opt_fields query parameter to request specific fields and reduce response size.
347
+
348
+ Common endpoints:
349
+ - GET /workspaces \u2014 List workspaces
350
+ - GET /projects?workspace=WORKSPACE_GID \u2014 List projects in a workspace
351
+ - GET /tasks?project=PROJECT_GID \u2014 List tasks in a project
352
+ - GET /tasks/{task_gid} \u2014 Get a single task
353
+ - POST /tasks \u2014 Create a task (body: { "data": { "name": "...", "workspace": "..." } })
354
+ - PUT /tasks/{task_gid} \u2014 Update a task
355
+ - GET /users?workspace=WORKSPACE_GID \u2014 List users in a workspace
356
+ - GET /sections?project=PROJECT_GID \u2014 List sections in a project
357
+ - GET /tags?workspace=WORKSPACE_GID \u2014 List tags
358
+ - POST /tasks/{task_gid}/subtasks \u2014 Create a subtask
359
+ - GET /tasks/{task_gid}/stories \u2014 Get task comments/stories
360
+
361
+ Pagination: Use limit (1-100) and offset query parameters. The response includes next_page.offset for the next page.`,
362
+ inputSchema,
363
+ outputSchema,
364
+ async execute({ connectionId, method, path: path2, body }, connections) {
365
+ const connection2 = connections.find((c) => c.id === connectionId);
366
+ if (!connection2) {
367
+ return {
368
+ success: false,
369
+ error: `Connection ${connectionId} not found`
370
+ };
371
+ }
372
+ console.log(
373
+ `[connector-request] asana/${connection2.name}: ${method} ${path2}`
374
+ );
375
+ try {
376
+ const token = parameters.personalAccessToken.getValue(connection2);
377
+ const url = `${BASE_URL2}${path2}`;
378
+ const controller = new AbortController();
379
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
380
+ try {
381
+ const response = await fetch(url, {
382
+ method,
383
+ headers: {
384
+ Authorization: `Bearer ${token}`,
385
+ "Content-Type": "application/json",
386
+ Accept: "application/json"
387
+ },
388
+ body: body ? JSON.stringify(body) : void 0,
389
+ signal: controller.signal
390
+ });
391
+ const data = await response.json();
392
+ if (!response.ok) {
393
+ const errors = data?.errors;
394
+ const errorMessage = Array.isArray(errors) && errors.length > 0 ? errors[0]?.message ?? `HTTP ${response.status} ${response.statusText}` : `HTTP ${response.status} ${response.statusText}`;
395
+ return { success: false, error: String(errorMessage) };
396
+ }
397
+ return { success: true, status: response.status, data };
398
+ } finally {
399
+ clearTimeout(timeout);
400
+ }
401
+ } catch (err) {
402
+ const msg = err instanceof Error ? err.message : String(err);
403
+ return { success: false, error: msg };
404
+ }
405
+ }
406
+ });
407
+
408
+ // ../connectors/src/connectors/asana/index.ts
409
+ var tools = { request: requestTool };
410
+ var asanaConnector = new ConnectorPlugin({
411
+ slug: "asana",
412
+ authType: null,
413
+ name: "Asana",
414
+ description: "Connect to Asana for project management, task tracking, and team collaboration data.",
415
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6gCkEDWO6kSYSiCe0K2cY4/e7f89b90c0c0e7db72c3f8a9b92e5752/asana.svg",
416
+ parameters,
417
+ releaseFlag: { dev1: true, dev2: false, prod: false },
418
+ onboarding: asanaOnboarding,
419
+ systemPrompt: {
420
+ en: `### Tools
421
+
422
+ - \`asana_request\`: The only way to call the Asana REST API. Use it to list workspaces, projects, tasks, users, sections, tags, and more. Authentication (Bearer token with Personal Access Token) is configured automatically. Provide the API path and optionally append query parameters like opt_fields for field selection.
423
+
424
+ ### Business Logic
425
+
426
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
427
+
428
+ SDK methods (client created via \`connection(connectionId)\`):
429
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch (provide path relative to base URL)
430
+ - \`client.listWorkspaces(options?)\` \u2014 list all workspaces
431
+ - \`client.listProjects(workspaceGid, options?)\` \u2014 list projects in a workspace
432
+ - \`client.listTasks(projectGid, options?)\` \u2014 list tasks in a project
433
+ - \`client.getTask(taskGid, options?)\` \u2014 get a single task
434
+ - \`client.createTask(taskData)\` \u2014 create a new task
435
+ - \`client.updateTask(taskGid, taskData)\` \u2014 update an existing task
436
+ - \`client.listUsers(workspaceGid, options?)\` \u2014 list users in a workspace
437
+
438
+ \`\`\`ts
439
+ import type { Context } from "hono";
440
+ import { connection } from "@squadbase/vite-server/connectors/asana";
441
+
442
+ const asana = connection("<connectionId>");
443
+
444
+ export default async function handler(c: Context) {
445
+ const { projectGid } = await c.req.json<{ projectGid: string }>();
446
+
447
+ const { data: tasks } = await asana.listTasks(projectGid, {
448
+ opt_fields: ["name", "completed", "assignee.name", "due_on"],
449
+ limit: 50,
450
+ });
451
+
452
+ return c.json({ tasks });
453
+ }
454
+ \`\`\`
455
+
456
+ ### Asana REST API Reference
457
+
458
+ - Base URL: \`https://app.asana.com/api/1.0\`
459
+ - Authentication: Bearer token (Personal Access Token, handled automatically)
460
+ - All write requests wrap the payload in a \`data\` key: \`{ "data": { ... } }\`
461
+ - Use \`opt_fields\` query parameter to select specific fields and reduce response size
462
+ - Pagination: offset-based with \`limit\` (1-100) and \`offset\` query parameters; response includes \`next_page.offset\`
463
+
464
+ #### Resource Endpoints
465
+
466
+ **Workspaces**
467
+ - GET \`/workspaces\` \u2014 List all workspaces
468
+
469
+ **Projects**
470
+ - GET \`/projects?workspace=WORKSPACE_GID\` \u2014 List projects in a workspace
471
+ - GET \`/projects/{project_gid}\` \u2014 Get a project
472
+ - POST \`/projects\` \u2014 Create a project
473
+ - PUT \`/projects/{project_gid}\` \u2014 Update a project
474
+
475
+ **Tasks**
476
+ - GET \`/tasks?project=PROJECT_GID\` \u2014 List tasks in a project (requires project, or assignee+workspace)
477
+ - GET \`/tasks/{task_gid}\` \u2014 Get a task
478
+ - POST \`/tasks\` \u2014 Create a task (requires workspace or projects in body)
479
+ - PUT \`/tasks/{task_gid}\` \u2014 Update a task
480
+ - DELETE \`/tasks/{task_gid}\` \u2014 Delete a task
481
+ - POST \`/tasks/{task_gid}/subtasks\` \u2014 Create a subtask
482
+ - GET \`/tasks/{task_gid}/subtasks\` \u2014 List subtasks
483
+
484
+ **Sections**
485
+ - GET \`/sections?project=PROJECT_GID\` \u2014 List sections in a project
486
+ - POST \`/sections/{section_gid}/addTask\` \u2014 Add a task to a section
487
+
488
+ **Users**
489
+ - GET \`/users?workspace=WORKSPACE_GID\` \u2014 List users in a workspace
490
+ - GET \`/users/me\` \u2014 Get the authenticated user
491
+ - GET \`/users/{user_gid}\` \u2014 Get a user
492
+
493
+ **Tags**
494
+ - GET \`/tags?workspace=WORKSPACE_GID\` \u2014 List tags in a workspace
495
+
496
+ **Stories (comments)**
497
+ - GET \`/tasks/{task_gid}/stories\` \u2014 List comments/stories on a task
498
+ - POST \`/tasks/{task_gid}/stories\` \u2014 Add a comment to a task
499
+
500
+ **Search**
501
+ - GET \`/workspaces/{workspace_gid}/tasks/search?text=QUERY\` \u2014 Search tasks in a workspace
502
+
503
+ #### Common opt_fields
504
+ - Tasks: name, completed, assignee, assignee.name, due_on, due_at, created_at, modified_at, notes, projects, projects.name, tags, tags.name, parent, parent.name, memberships, memberships.section, memberships.section.name, custom_fields
505
+ - Projects: name, archived, created_at, modified_at, owner, owner.name, team, team.name, members
506
+ - Users: name, email, photo`,
507
+ ja: `### \u30C4\u30FC\u30EB
508
+
509
+ - \`asana_request\`: Asana REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u3001\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3001\u30BF\u30B9\u30AF\u3001\u30E6\u30FC\u30B6\u30FC\u3001\u30BB\u30AF\u30B7\u30E7\u30F3\u3001\u30BF\u30B0\u306A\u3069\u306E\u4E00\u89A7\u53D6\u5F97\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08Personal Access Token\u3092\u4F7F\u7528\u3057\u305FBearer\u30C8\u30FC\u30AF\u30F3\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002API\u30D1\u30B9\u3092\u6307\u5B9A\u3057\u3001\u5FC5\u8981\u306B\u5FDC\u3058\u3066opt_fields\u306A\u3069\u306E\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u4ED8\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002
510
+
511
+ ### Business Logic
512
+
513
+ \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
514
+
515
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
516
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch\uFF08\u30D9\u30FC\u30B9URL\u304B\u3089\u306E\u76F8\u5BFE\u30D1\u30B9\u3092\u6307\u5B9A\uFF09
517
+ - \`client.listWorkspaces(options?)\` \u2014 \u5168\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306E\u4E00\u89A7
518
+ - \`client.listProjects(workspaceGid, options?)\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u5185\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7
519
+ - \`client.listTasks(projectGid, options?)\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u5185\u306E\u30BF\u30B9\u30AF\u4E00\u89A7
520
+ - \`client.getTask(taskGid, options?)\` \u2014 \u5358\u4E00\u30BF\u30B9\u30AF\u306E\u53D6\u5F97
521
+ - \`client.createTask(taskData)\` \u2014 \u65B0\u898F\u30BF\u30B9\u30AF\u306E\u4F5C\u6210
522
+ - \`client.updateTask(taskGid, taskData)\` \u2014 \u65E2\u5B58\u30BF\u30B9\u30AF\u306E\u66F4\u65B0
523
+ - \`client.listUsers(workspaceGid, options?)\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u5185\u306E\u30E6\u30FC\u30B6\u30FC\u4E00\u89A7
524
+
525
+ \`\`\`ts
526
+ import type { Context } from "hono";
527
+ import { connection } from "@squadbase/vite-server/connectors/asana";
528
+
529
+ const asana = connection("<connectionId>");
530
+
531
+ export default async function handler(c: Context) {
532
+ const { projectGid } = await c.req.json<{ projectGid: string }>();
533
+
534
+ const { data: tasks } = await asana.listTasks(projectGid, {
535
+ opt_fields: ["name", "completed", "assignee.name", "due_on"],
536
+ limit: 50,
537
+ });
538
+
539
+ return c.json({ tasks });
540
+ }
541
+ \`\`\`
542
+
543
+ ### Asana REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
544
+
545
+ - \u30D9\u30FC\u30B9URL: \`https://app.asana.com/api/1.0\`
546
+ - \u8A8D\u8A3C: Bearer\u30C8\u30FC\u30AF\u30F3\uFF08Personal Access Token\u3001\u81EA\u52D5\u8A2D\u5B9A\uFF09
547
+ - \u66F8\u304D\u8FBC\u307F\u30EA\u30AF\u30A8\u30B9\u30C8\u306F\u30DA\u30A4\u30ED\u30FC\u30C9\u3092 \`data\` \u30AD\u30FC\u3067\u56F2\u3080: \`{ "data": { ... } }\`
548
+ - \`opt_fields\` \u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u7279\u5B9A\u306E\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u6307\u5B9A\u3057\u3066\u30EC\u30B9\u30DD\u30F3\u30B9\u30B5\u30A4\u30BA\u3092\u524A\u6E1B\u53EF\u80FD
549
+ - \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3: \`limit\`\uFF081-100\uFF09\u3068 \`offset\` \u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u3088\u308B\u30AA\u30D5\u30BB\u30C3\u30C8\u30D9\u30FC\u30B9\u3001\u30EC\u30B9\u30DD\u30F3\u30B9\u306B \`next_page.offset\` \u304C\u542B\u307E\u308C\u308B
550
+
551
+ #### \u30EA\u30BD\u30FC\u30B9\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
552
+
553
+ **\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9**
554
+ - GET \`/workspaces\` \u2014 \u5168\u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u306E\u4E00\u89A7
555
+
556
+ **\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8**
557
+ - GET \`/projects?workspace=WORKSPACE_GID\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u5185\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u4E00\u89A7
558
+ - GET \`/projects/{project_gid}\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u53D6\u5F97
559
+ - POST \`/projects\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u4F5C\u6210
560
+ - PUT \`/projects/{project_gid}\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u66F4\u65B0
561
+
562
+ **\u30BF\u30B9\u30AF**
563
+ - GET \`/tasks?project=PROJECT_GID\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u5185\u306E\u30BF\u30B9\u30AF\u4E00\u89A7\uFF08project\u3001\u307E\u305F\u306Fassignee+workspace\u304C\u5FC5\u8981\uFF09
564
+ - GET \`/tasks/{task_gid}\` \u2014 \u30BF\u30B9\u30AF\u306E\u53D6\u5F97
565
+ - POST \`/tasks\` \u2014 \u30BF\u30B9\u30AF\u306E\u4F5C\u6210\uFF08body\u306Bworkspace\u307E\u305F\u306Fprojects\u304C\u5FC5\u8981\uFF09
566
+ - PUT \`/tasks/{task_gid}\` \u2014 \u30BF\u30B9\u30AF\u306E\u66F4\u65B0
567
+ - DELETE \`/tasks/{task_gid}\` \u2014 \u30BF\u30B9\u30AF\u306E\u524A\u9664
568
+ - POST \`/tasks/{task_gid}/subtasks\` \u2014 \u30B5\u30D6\u30BF\u30B9\u30AF\u306E\u4F5C\u6210
569
+ - GET \`/tasks/{task_gid}/subtasks\` \u2014 \u30B5\u30D6\u30BF\u30B9\u30AF\u306E\u4E00\u89A7
570
+
571
+ **\u30BB\u30AF\u30B7\u30E7\u30F3**
572
+ - GET \`/sections?project=PROJECT_GID\` \u2014 \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u5185\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u4E00\u89A7
573
+ - POST \`/sections/{section_gid}/addTask\` \u2014 \u30BB\u30AF\u30B7\u30E7\u30F3\u306B\u30BF\u30B9\u30AF\u3092\u8FFD\u52A0
574
+
575
+ **\u30E6\u30FC\u30B6\u30FC**
576
+ - GET \`/users?workspace=WORKSPACE_GID\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u5185\u306E\u30E6\u30FC\u30B6\u30FC\u4E00\u89A7
577
+ - GET \`/users/me\` \u2014 \u8A8D\u8A3C\u30E6\u30FC\u30B6\u30FC\u306E\u53D6\u5F97
578
+ - GET \`/users/{user_gid}\` \u2014 \u30E6\u30FC\u30B6\u30FC\u306E\u53D6\u5F97
579
+
580
+ **\u30BF\u30B0**
581
+ - GET \`/tags?workspace=WORKSPACE_GID\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u5185\u306E\u30BF\u30B0\u4E00\u89A7
582
+
583
+ **\u30B9\u30C8\u30FC\u30EA\u30FC\uFF08\u30B3\u30E1\u30F3\u30C8\uFF09**
584
+ - GET \`/tasks/{task_gid}/stories\` \u2014 \u30BF\u30B9\u30AF\u306E\u30B3\u30E1\u30F3\u30C8/\u30B9\u30C8\u30FC\u30EA\u30FC\u4E00\u89A7
585
+ - POST \`/tasks/{task_gid}/stories\` \u2014 \u30BF\u30B9\u30AF\u306B\u30B3\u30E1\u30F3\u30C8\u3092\u8FFD\u52A0
586
+
587
+ **\u691C\u7D22**
588
+ - GET \`/workspaces/{workspace_gid}/tasks/search?text=QUERY\` \u2014 \u30EF\u30FC\u30AF\u30B9\u30DA\u30FC\u30B9\u5185\u306E\u30BF\u30B9\u30AF\u691C\u7D22
589
+
590
+ #### \u3088\u304F\u4F7F\u3046opt_fields
591
+ - \u30BF\u30B9\u30AF: name, completed, assignee, assignee.name, due_on, due_at, created_at, modified_at, notes, projects, projects.name, tags, tags.name, parent, parent.name, memberships, memberships.section, memberships.section.name, custom_fields
592
+ - \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8: name, archived, created_at, modified_at, owner, owner.name, team, team.name, members
593
+ - \u30E6\u30FC\u30B6\u30FC: name, email, photo`
594
+ },
595
+ tools
596
+ });
597
+
598
+ // src/connectors/create-connector-sdk.ts
599
+ import { readFileSync } from "fs";
600
+ import path from "path";
601
+
602
+ // src/connector-client/env.ts
603
+ function resolveEnvVar(entry, key, connectionId) {
604
+ const envVarName = entry.envVars[key];
605
+ if (!envVarName) {
606
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
607
+ }
608
+ const value = process.env[envVarName];
609
+ if (!value) {
610
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
611
+ }
612
+ return value;
613
+ }
614
+ function resolveEnvVarOptional(entry, key) {
615
+ const envVarName = entry.envVars[key];
616
+ if (!envVarName) return void 0;
617
+ return process.env[envVarName] || void 0;
618
+ }
619
+
620
+ // src/connectors/create-connector-sdk.ts
621
+ function loadConnectionsSync() {
622
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
623
+ try {
624
+ const raw = readFileSync(filePath, "utf-8");
625
+ return JSON.parse(raw);
626
+ } catch {
627
+ return {};
628
+ }
629
+ }
630
+ function createConnectorSdk(plugin, createClient2) {
631
+ return (connectionId) => {
632
+ const connections = loadConnectionsSync();
633
+ const entry = connections[connectionId];
634
+ if (!entry) {
635
+ throw new Error(
636
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
637
+ );
638
+ }
639
+ if (entry.connector.slug !== plugin.slug) {
640
+ throw new Error(
641
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
642
+ );
643
+ }
644
+ const params = {};
645
+ for (const param of Object.values(plugin.parameters)) {
646
+ if (param.required) {
647
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
648
+ } else {
649
+ const val = resolveEnvVarOptional(entry, param.slug);
650
+ if (val !== void 0) params[param.slug] = val;
651
+ }
652
+ }
653
+ return createClient2(params);
654
+ };
655
+ }
656
+
657
+ // src/connectors/entries/asana.ts
658
+ var connection = createConnectorSdk(asanaConnector, createClient);
659
+ export {
660
+ connection
661
+ };
@@ -0,0 +1,5 @@
1
+ import * as _squadbase_connectors_sdk from '@squadbase/connectors/sdk';
2
+
3
+ declare const connection: (connectionId: string) => _squadbase_connectors_sdk.CustomerioConnectorSdk;
4
+
5
+ export { connection };