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

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 (70) hide show
  1. package/dist/cli/index.js +82859 -9645
  2. package/dist/connectors/airtable-oauth.js +77 -3
  3. package/dist/connectors/airtable.js +85 -2
  4. package/dist/connectors/amplitude.js +85 -2
  5. package/dist/connectors/anthropic.js +85 -2
  6. package/dist/connectors/{slack.d.ts → asana.d.ts} +1 -1
  7. package/dist/connectors/asana.js +744 -0
  8. package/dist/connectors/attio.js +85 -2
  9. package/dist/connectors/{microsoft-teams-oauth.d.ts → customerio.d.ts} +1 -1
  10. package/dist/connectors/customerio.js +716 -0
  11. package/dist/connectors/dbt.js +85 -2
  12. package/dist/connectors/gemini.js +86 -3
  13. package/dist/connectors/{microsoft-teams.d.ts → gmail-oauth.d.ts} +1 -1
  14. package/dist/connectors/gmail-oauth.js +713 -0
  15. package/dist/connectors/gmail.d.ts +5 -0
  16. package/dist/connectors/gmail.js +875 -0
  17. package/dist/connectors/google-ads-oauth.js +78 -4
  18. package/dist/connectors/google-ads.d.ts +5 -0
  19. package/dist/connectors/google-ads.js +867 -0
  20. package/dist/connectors/google-analytics-oauth.js +90 -8
  21. package/dist/connectors/google-analytics.js +85 -2
  22. package/dist/connectors/google-calendar-oauth.d.ts +5 -0
  23. package/dist/connectors/google-calendar-oauth.js +817 -0
  24. package/dist/connectors/google-calendar.d.ts +5 -0
  25. package/dist/connectors/google-calendar.js +991 -0
  26. package/dist/connectors/google-sheets-oauth.js +144 -33
  27. package/dist/connectors/google-sheets.d.ts +5 -0
  28. package/dist/connectors/google-sheets.js +707 -0
  29. package/dist/connectors/grafana.d.ts +5 -0
  30. package/dist/connectors/grafana.js +638 -0
  31. package/dist/connectors/hubspot-oauth.js +77 -3
  32. package/dist/connectors/hubspot.js +89 -6
  33. package/dist/connectors/intercom-oauth.d.ts +5 -0
  34. package/dist/connectors/intercom-oauth.js +584 -0
  35. package/dist/connectors/intercom.d.ts +5 -0
  36. package/dist/connectors/intercom.js +710 -0
  37. package/dist/connectors/jira-api-key.d.ts +5 -0
  38. package/dist/connectors/jira-api-key.js +598 -0
  39. package/dist/connectors/kintone-api-token.js +77 -3
  40. package/dist/connectors/kintone.js +86 -3
  41. package/dist/connectors/linkedin-ads-oauth.d.ts +5 -0
  42. package/dist/connectors/linkedin-ads-oauth.js +848 -0
  43. package/dist/connectors/linkedin-ads.d.ts +5 -0
  44. package/dist/connectors/linkedin-ads.js +865 -0
  45. package/dist/connectors/mailchimp-oauth.d.ts +5 -0
  46. package/dist/connectors/mailchimp-oauth.js +613 -0
  47. package/dist/connectors/mailchimp.d.ts +5 -0
  48. package/dist/connectors/mailchimp.js +729 -0
  49. package/dist/connectors/notion-oauth.d.ts +5 -0
  50. package/dist/connectors/notion-oauth.js +567 -0
  51. package/dist/connectors/notion.d.ts +5 -0
  52. package/dist/connectors/notion.js +663 -0
  53. package/dist/connectors/openai.js +85 -2
  54. package/dist/connectors/shopify-oauth.js +77 -3
  55. package/dist/connectors/shopify.js +85 -2
  56. package/dist/connectors/stripe-api-key.d.ts +5 -0
  57. package/dist/connectors/stripe-api-key.js +600 -0
  58. package/dist/connectors/stripe-oauth.js +77 -3
  59. package/dist/connectors/wix-store.js +85 -2
  60. package/dist/connectors/zendesk-oauth.d.ts +5 -0
  61. package/dist/connectors/zendesk-oauth.js +579 -0
  62. package/dist/connectors/zendesk.d.ts +5 -0
  63. package/dist/connectors/zendesk.js +714 -0
  64. package/dist/index.js +83024 -7099
  65. package/dist/main.js +82988 -7063
  66. package/dist/vite-plugin.js +82862 -6974
  67. package/package.json +86 -2
  68. package/dist/connectors/microsoft-teams-oauth.js +0 -479
  69. package/dist/connectors/microsoft-teams.js +0 -381
  70. package/dist/connectors/slack.js +0 -362
@@ -0,0 +1,729 @@
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/mailchimp/parameters.ts
46
+ var parameters = {
47
+ apiKey: new ParameterDefinition({
48
+ slug: "api-key",
49
+ name: "Mailchimp API Key",
50
+ description: "Your Mailchimp API key. The key includes the datacenter suffix (e.g., xxxxxxxxxxxxxxxx-us6).",
51
+ envVarBaseKey: "MAILCHIMP_API_KEY",
52
+ type: "text",
53
+ secret: true,
54
+ required: true
55
+ })
56
+ };
57
+
58
+ // ../connectors/src/connectors/mailchimp/sdk/index.ts
59
+ function extractDatacenter(apiKey) {
60
+ const parts = apiKey.split("-");
61
+ const dc = parts[parts.length - 1];
62
+ if (!dc) {
63
+ throw new Error(
64
+ "Invalid Mailchimp API key format. Expected format: xxxxxxxxxxxxxxxx-us6"
65
+ );
66
+ }
67
+ return dc;
68
+ }
69
+ function createClient(params) {
70
+ const apiKey = params[parameters.apiKey.slug];
71
+ if (!apiKey) {
72
+ throw new Error(
73
+ `mailchimp: missing required parameter: ${parameters.apiKey.slug}`
74
+ );
75
+ }
76
+ const dc = extractDatacenter(apiKey);
77
+ const baseUrl = `https://${dc}.api.mailchimp.com/3.0`;
78
+ const authHeader = `Basic ${btoa(`anystring:${apiKey}`)}`;
79
+ function authHeaders(extra) {
80
+ const headers = new Headers(extra);
81
+ headers.set("Authorization", authHeader);
82
+ headers.set("Content-Type", "application/json");
83
+ return headers;
84
+ }
85
+ async function assertOk(res, label) {
86
+ if (!res.ok) {
87
+ const body = await res.text().catch(() => "(unreadable body)");
88
+ throw new Error(
89
+ `mailchimp ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
90
+ );
91
+ }
92
+ }
93
+ function buildQuery(params2) {
94
+ if (!params2) return "";
95
+ const entries = Object.entries(params2).filter(
96
+ ([, v]) => v !== void 0
97
+ );
98
+ if (entries.length === 0) return "";
99
+ const sp = new URLSearchParams();
100
+ for (const [k, v] of entries) sp.set(k, String(v));
101
+ return `?${sp.toString()}`;
102
+ }
103
+ return {
104
+ request(path2, init) {
105
+ const url = `${baseUrl}${path2.startsWith("/") ? "" : "/"}${path2}`;
106
+ const headers = new Headers(init?.headers);
107
+ headers.set("Authorization", authHeader);
108
+ headers.set("Content-Type", "application/json");
109
+ return fetch(url, { ...init, headers });
110
+ },
111
+ async getLists(options) {
112
+ const qs = buildQuery({
113
+ count: options?.count,
114
+ offset: options?.offset
115
+ });
116
+ const res = await fetch(`${baseUrl}/lists${qs}`, {
117
+ method: "GET",
118
+ headers: authHeaders()
119
+ });
120
+ await assertOk(res, "getLists");
121
+ return await res.json();
122
+ },
123
+ async getListMembers(listId, options) {
124
+ const qs = buildQuery({
125
+ count: options?.count,
126
+ offset: options?.offset,
127
+ status: options?.status
128
+ });
129
+ const res = await fetch(
130
+ `${baseUrl}/lists/${encodeURIComponent(listId)}/members${qs}`,
131
+ { method: "GET", headers: authHeaders() }
132
+ );
133
+ await assertOk(res, "getListMembers");
134
+ return await res.json();
135
+ },
136
+ async getCampaigns(options) {
137
+ const qs = buildQuery({
138
+ count: options?.count,
139
+ offset: options?.offset,
140
+ status: options?.status,
141
+ type: options?.type
142
+ });
143
+ const res = await fetch(`${baseUrl}/campaigns${qs}`, {
144
+ method: "GET",
145
+ headers: authHeaders()
146
+ });
147
+ await assertOk(res, "getCampaigns");
148
+ return await res.json();
149
+ },
150
+ async getReports(options) {
151
+ const qs = buildQuery({
152
+ count: options?.count,
153
+ offset: options?.offset
154
+ });
155
+ const res = await fetch(`${baseUrl}/reports${qs}`, {
156
+ method: "GET",
157
+ headers: authHeaders()
158
+ });
159
+ await assertOk(res, "getReports");
160
+ return await res.json();
161
+ }
162
+ };
163
+ }
164
+
165
+ // ../connectors/src/connector-onboarding.ts
166
+ var ConnectorOnboarding = class {
167
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
168
+ connectionSetupInstructions;
169
+ /** Phase 2: Data overview instructions */
170
+ dataOverviewInstructions;
171
+ constructor(config) {
172
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
173
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
174
+ }
175
+ getConnectionSetupPrompt(language) {
176
+ return this.connectionSetupInstructions?.[language] ?? null;
177
+ }
178
+ getDataOverviewInstructions(language) {
179
+ return this.dataOverviewInstructions[language];
180
+ }
181
+ };
182
+
183
+ // ../connectors/src/connector-tool.ts
184
+ var ConnectorTool = class {
185
+ name;
186
+ description;
187
+ inputSchema;
188
+ outputSchema;
189
+ _execute;
190
+ constructor(config) {
191
+ this.name = config.name;
192
+ this.description = config.description;
193
+ this.inputSchema = config.inputSchema;
194
+ this.outputSchema = config.outputSchema;
195
+ this._execute = config.execute;
196
+ }
197
+ createTool(connections, config) {
198
+ return {
199
+ description: this.description,
200
+ inputSchema: this.inputSchema,
201
+ outputSchema: this.outputSchema,
202
+ execute: (input) => this._execute(input, connections, config)
203
+ };
204
+ }
205
+ };
206
+
207
+ // ../connectors/src/connector-plugin.ts
208
+ var ConnectorPlugin = class _ConnectorPlugin {
209
+ slug;
210
+ authType;
211
+ name;
212
+ description;
213
+ iconUrl;
214
+ parameters;
215
+ releaseFlag;
216
+ proxyPolicy;
217
+ experimentalAttributes;
218
+ onboarding;
219
+ systemPrompt;
220
+ tools;
221
+ query;
222
+ checkConnection;
223
+ constructor(config) {
224
+ this.slug = config.slug;
225
+ this.authType = config.authType;
226
+ this.name = config.name;
227
+ this.description = config.description;
228
+ this.iconUrl = config.iconUrl;
229
+ this.parameters = config.parameters;
230
+ this.releaseFlag = config.releaseFlag;
231
+ this.proxyPolicy = config.proxyPolicy;
232
+ this.experimentalAttributes = config.experimentalAttributes;
233
+ this.onboarding = config.onboarding;
234
+ this.systemPrompt = config.systemPrompt;
235
+ this.tools = config.tools;
236
+ this.query = config.query;
237
+ this.checkConnection = config.checkConnection;
238
+ }
239
+ get connectorKey() {
240
+ return _ConnectorPlugin.deriveKey(this.slug, this.authType);
241
+ }
242
+ /**
243
+ * Create tools for connections that belong to this connector.
244
+ * Filters connections by connectorKey internally.
245
+ * Returns tools keyed as `${connectorKey}_${toolName}`.
246
+ */
247
+ createTools(connections, config) {
248
+ const myConnections = connections.filter(
249
+ (c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
250
+ );
251
+ const result = {};
252
+ for (const t of Object.values(this.tools)) {
253
+ result[`${this.connectorKey}_${t.name}`] = t.createTool(
254
+ myConnections,
255
+ config
256
+ );
257
+ }
258
+ return result;
259
+ }
260
+ static deriveKey(slug, authType) {
261
+ return authType ? `${slug}-${authType}` : slug;
262
+ }
263
+ };
264
+
265
+ // ../connectors/src/auth-types.ts
266
+ var AUTH_TYPES = {
267
+ OAUTH: "oauth",
268
+ API_KEY: "api-key",
269
+ JWT: "jwt",
270
+ SERVICE_ACCOUNT: "service-account",
271
+ PAT: "pat",
272
+ USER_PASSWORD: "user-password"
273
+ };
274
+
275
+ // ../connectors/src/connectors/mailchimp/setup.ts
276
+ var mailchimpOnboarding = new ConnectorOnboarding({
277
+ dataOverviewInstructions: {
278
+ en: `1. Call mailchimp_request with GET /lists to list all audiences
279
+ 2. Pick an audience and call GET /lists/{list_id}/members?count=5 to sample members
280
+ 3. Call GET /campaigns?count=5 to list recent campaigns
281
+ 4. Call GET /reports?count=5 to view campaign reports`,
282
+ ja: `1. mailchimp_request \u3067 GET /lists \u3092\u547C\u3073\u51FA\u3057\u3001\u5168\u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u4E00\u89A7\u3092\u53D6\u5F97
283
+ 2. \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u3092\u9078\u629E\u3057 GET /lists/{list_id}/members?count=5 \u3067\u30E1\u30F3\u30D0\u30FC\u3092\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0
284
+ 3. GET /campaigns?count=5 \u3067\u6700\u8FD1\u306E\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u4E00\u89A7\u3092\u53D6\u5F97
285
+ 4. GET /reports?count=5 \u3067\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30EC\u30DD\u30FC\u30C8\u3092\u8868\u793A`
286
+ }
287
+ });
288
+
289
+ // ../connectors/src/connectors/mailchimp/tools/request.ts
290
+ import { z } from "zod";
291
+ var REQUEST_TIMEOUT_MS = 6e4;
292
+ function extractDatacenter2(apiKey) {
293
+ const parts = apiKey.split("-");
294
+ const dc = parts[parts.length - 1];
295
+ if (!dc) {
296
+ throw new Error(
297
+ "Invalid Mailchimp API key format. Expected format: xxxxxxxxxxxxxxxx-us6"
298
+ );
299
+ }
300
+ return dc;
301
+ }
302
+ var inputSchema = z.object({
303
+ toolUseIntent: z.string().optional().describe(
304
+ "Brief description of what you intend to accomplish with this tool call"
305
+ ),
306
+ connectionId: z.string().describe("ID of the Mailchimp connection to use"),
307
+ method: z.enum(["GET", "POST", "PATCH", "PUT", "DELETE"]).describe(
308
+ "HTTP method. GET for reading, POST for creating, PATCH/PUT for updating, DELETE for removing."
309
+ ),
310
+ path: z.string().describe(
311
+ "API path appended to the base URL (e.g., '/lists', '/campaigns', '/lists/{list_id}/members')"
312
+ ),
313
+ queryParams: z.record(z.string(), z.string()).optional().describe("Query parameters to append to the URL (e.g., count, offset)"),
314
+ body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST/PATCH/PUT requests")
315
+ });
316
+ var outputSchema = z.discriminatedUnion("success", [
317
+ z.object({
318
+ success: z.literal(true),
319
+ status: z.number(),
320
+ data: z.record(z.string(), z.unknown())
321
+ }),
322
+ z.object({
323
+ success: z.literal(false),
324
+ error: z.string()
325
+ })
326
+ ]);
327
+ var requestTool = new ConnectorTool({
328
+ name: "request",
329
+ description: `Send authenticated requests to the Mailchimp Marketing API v3.
330
+ Authentication is handled automatically using the API Key (Basic Auth).
331
+ Use this tool for all Mailchimp API interactions: managing audiences/lists, campaigns, members/subscribers, templates, automations, and reports.
332
+ The datacenter is automatically extracted from the API key suffix.`,
333
+ inputSchema,
334
+ outputSchema,
335
+ async execute({ connectionId, method, path: path2, queryParams, body }, connections) {
336
+ const connection2 = connections.find((c) => c.id === connectionId);
337
+ if (!connection2) {
338
+ return {
339
+ success: false,
340
+ error: `Connection ${connectionId} not found`
341
+ };
342
+ }
343
+ console.log(
344
+ `[connector-request] mailchimp/${connection2.name}: ${method} ${path2}`
345
+ );
346
+ try {
347
+ const apiKey = parameters.apiKey.getValue(connection2);
348
+ const dc = extractDatacenter2(apiKey);
349
+ const baseUrl = `https://${dc}.api.mailchimp.com/3.0`;
350
+ let url = `${baseUrl}${path2.startsWith("/") ? "" : "/"}${path2}`;
351
+ if (queryParams) {
352
+ const searchParams = new URLSearchParams(queryParams);
353
+ url += `?${searchParams.toString()}`;
354
+ }
355
+ const controller = new AbortController();
356
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
357
+ try {
358
+ const response = await fetch(url, {
359
+ method,
360
+ headers: {
361
+ Authorization: `Basic ${btoa(`anystring:${apiKey}`)}`,
362
+ "Content-Type": "application/json"
363
+ },
364
+ body: body ? JSON.stringify(body) : void 0,
365
+ signal: controller.signal
366
+ });
367
+ const data = await response.json();
368
+ if (!response.ok) {
369
+ const errorMessage = typeof data?.detail === "string" ? data.detail : typeof data?.title === "string" ? data.title : `HTTP ${response.status} ${response.statusText}`;
370
+ return { success: false, error: errorMessage };
371
+ }
372
+ return { success: true, status: response.status, data };
373
+ } finally {
374
+ clearTimeout(timeout);
375
+ }
376
+ } catch (err) {
377
+ const msg = err instanceof Error ? err.message : String(err);
378
+ return { success: false, error: msg };
379
+ }
380
+ }
381
+ });
382
+
383
+ // ../connectors/src/connectors/mailchimp/index.ts
384
+ var tools = { request: requestTool };
385
+ var mailchimpConnector = new ConnectorPlugin({
386
+ slug: "mailchimp",
387
+ authType: AUTH_TYPES.API_KEY,
388
+ name: "Mailchimp",
389
+ description: "Connect to Mailchimp for email marketing, audiences, campaigns, and analytics.",
390
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/19Rac6B8eGiLpQb4lKMbG3/10f567f85572aeb16f2ee6aaa6602987/mailchimp.png",
391
+ parameters,
392
+ releaseFlag: { dev1: true, dev2: false, prod: false },
393
+ onboarding: mailchimpOnboarding,
394
+ systemPrompt: {
395
+ en: `### Tools
396
+
397
+ - \`mailchimp_request\`: The only way to call the Mailchimp Marketing API v3. Use it to manage audiences/lists, subscribers/members, campaigns, templates, automations, and reports. Authentication (Basic Auth with API key) is configured automatically. The datacenter is extracted from the API key suffix.
398
+
399
+ ### Business Logic
400
+
401
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
402
+
403
+ SDK methods (client created via \`connection(connectionId)\`):
404
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
405
+ - \`client.getLists(options?)\` \u2014 list all audiences/lists
406
+ - \`client.getListMembers(listId, options?)\` \u2014 get members of a list
407
+ - \`client.getCampaigns(options?)\` \u2014 list all campaigns
408
+ - \`client.getReports(options?)\` \u2014 get campaign reports
409
+
410
+ \`\`\`ts
411
+ import type { Context } from "hono";
412
+ import { connection } from "@squadbase/vite-server/connectors/mailchimp";
413
+
414
+ const mailchimp = connection("<connectionId>");
415
+
416
+ export default async function handler(c: Context) {
417
+ const { count = 10, offset = 0 } = await c.req.json<{
418
+ count?: number;
419
+ offset?: number;
420
+ }>();
421
+
422
+ const { lists, total_items } = await mailchimp.getLists({ count, offset });
423
+
424
+ return c.json({ lists, total_items });
425
+ }
426
+ \`\`\`
427
+
428
+ ### Mailchimp Marketing API v3 Reference
429
+
430
+ - Base URL: \`https://{dc}.api.mailchimp.com/3.0\` (datacenter auto-detected from API key)
431
+ - Authentication: Basic Auth (\`anystring:{apiKey}\`)
432
+ - Pagination: offset-based with \`count\` (default 10, max 1000) and \`offset\` parameters
433
+
434
+ #### Audiences / Lists
435
+ - GET \`/lists\` \u2014 List all audiences
436
+ - GET \`/lists/{list_id}\` \u2014 Get audience details
437
+ - POST \`/lists\` \u2014 Create an audience
438
+ - PATCH \`/lists/{list_id}\` \u2014 Update an audience
439
+ - DELETE \`/lists/{list_id}\` \u2014 Delete an audience
440
+
441
+ #### Members / Subscribers
442
+ - GET \`/lists/{list_id}/members\` \u2014 List members in an audience
443
+ - GET \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 Get member details (subscriber_hash = MD5 of lowercase email)
444
+ - POST \`/lists/{list_id}/members\` \u2014 Add a member
445
+ - PUT \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 Add or update a member
446
+ - PATCH \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 Update a member
447
+ - DELETE \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 Archive a member
448
+
449
+ #### Campaigns
450
+ - GET \`/campaigns\` \u2014 List campaigns
451
+ - GET \`/campaigns/{campaign_id}\` \u2014 Get campaign details
452
+ - POST \`/campaigns\` \u2014 Create a campaign
453
+ - PATCH \`/campaigns/{campaign_id}\` \u2014 Update a campaign
454
+ - DELETE \`/campaigns/{campaign_id}\` \u2014 Delete a campaign
455
+ - POST \`/campaigns/{campaign_id}/actions/send\` \u2014 Send a campaign
456
+ - GET \`/campaigns/{campaign_id}/content\` \u2014 Get campaign content
457
+
458
+ #### Templates
459
+ - GET \`/templates\` \u2014 List templates
460
+ - GET \`/templates/{template_id}\` \u2014 Get template details
461
+ - POST \`/templates\` \u2014 Create a template
462
+ - PATCH \`/templates/{template_id}\` \u2014 Update a template
463
+ - DELETE \`/templates/{template_id}\` \u2014 Delete a template
464
+
465
+ #### Automations
466
+ - GET \`/automations\` \u2014 List automations
467
+ - GET \`/automations/{workflow_id}\` \u2014 Get automation details
468
+ - GET \`/automations/{workflow_id}/emails\` \u2014 List automation emails
469
+ - POST \`/automations/{workflow_id}/actions/pause-all-emails\` \u2014 Pause automation
470
+ - POST \`/automations/{workflow_id}/actions/start-all-emails\` \u2014 Start automation
471
+
472
+ #### Reports
473
+ - GET \`/reports\` \u2014 List campaign reports
474
+ - GET \`/reports/{campaign_id}\` \u2014 Get a campaign report
475
+ - GET \`/reports/{campaign_id}/click-details\` \u2014 Get click details
476
+ - GET \`/reports/{campaign_id}/open-details\` \u2014 Get open details
477
+ - GET \`/reports/{campaign_id}/sent-to\` \u2014 Get sent-to details
478
+ - GET \`/reports/{campaign_id}/unsubscribed\` \u2014 List unsubscribed members
479
+
480
+ #### Search
481
+ - GET \`/search-members?query={query}\` \u2014 Search members across all audiences
482
+
483
+ #### Batch Operations
484
+ - POST \`/batches\` \u2014 Start a batch operation
485
+ - GET \`/batches\` \u2014 List batch operations
486
+ - GET \`/batches/{batch_id}\` \u2014 Get batch status
487
+
488
+ ### Tips
489
+ - Use \`fields\` and \`exclude_fields\` query params to filter response fields
490
+ - The subscriber_hash is the MD5 hash of the lowercase email address
491
+ - Errors return \`type\`, \`title\`, \`status\`, \`detail\`, and \`instance\` fields`,
492
+ ja: `### \u30C4\u30FC\u30EB
493
+
494
+ - \`mailchimp_request\`: Mailchimp Marketing API v3\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9/\u30EA\u30B9\u30C8\u3001\u30B5\u30D6\u30B9\u30AF\u30E9\u30A4\u30D0\u30FC/\u30E1\u30F3\u30D0\u30FC\u3001\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u3001\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3001\u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3\u3001\u30EC\u30DD\u30FC\u30C8\u306E\u7BA1\u7406\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08API\u30AD\u30FC\u306B\u3088\u308BBasic Auth\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002\u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC\u306FAPI\u30AD\u30FC\u306E\u30B5\u30D5\u30A3\u30C3\u30AF\u30B9\u304B\u3089\u81EA\u52D5\u691C\u51FA\u3055\u308C\u307E\u3059\u3002
495
+
496
+ ### Business Logic
497
+
498
+ \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
499
+
500
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
501
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
502
+ - \`client.getLists(options?)\` \u2014 \u5168\u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9/\u30EA\u30B9\u30C8\u306E\u4E00\u89A7
503
+ - \`client.getListMembers(listId, options?)\` \u2014 \u30EA\u30B9\u30C8\u306E\u30E1\u30F3\u30D0\u30FC\u53D6\u5F97
504
+ - \`client.getCampaigns(options?)\` \u2014 \u5168\u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u306E\u4E00\u89A7
505
+ - \`client.getReports(options?)\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30EC\u30DD\u30FC\u30C8\u306E\u53D6\u5F97
506
+
507
+ \`\`\`ts
508
+ import type { Context } from "hono";
509
+ import { connection } from "@squadbase/vite-server/connectors/mailchimp";
510
+
511
+ const mailchimp = connection("<connectionId>");
512
+
513
+ export default async function handler(c: Context) {
514
+ const { count = 10, offset = 0 } = await c.req.json<{
515
+ count?: number;
516
+ offset?: number;
517
+ }>();
518
+
519
+ const { lists, total_items } = await mailchimp.getLists({ count, offset });
520
+
521
+ return c.json({ lists, total_items });
522
+ }
523
+ \`\`\`
524
+
525
+ ### Mailchimp Marketing API v3 \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
526
+
527
+ - \u30D9\u30FC\u30B9URL: \`https://{dc}.api.mailchimp.com/3.0\`\uFF08\u30C7\u30FC\u30BF\u30BB\u30F3\u30BF\u30FC\u306FAPI\u30AD\u30FC\u304B\u3089\u81EA\u52D5\u691C\u51FA\uFF09
528
+ - \u8A8D\u8A3C: Basic Auth (\`anystring:{apiKey}\`)
529
+ - \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3: \`count\`\uFF08\u30C7\u30D5\u30A9\u30EB\u30C810\u3001\u6700\u59271000\uFF09\u3068\`offset\`\u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u3088\u308B\u30AA\u30D5\u30BB\u30C3\u30C8\u30D9\u30FC\u30B9
530
+
531
+ #### \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9 / \u30EA\u30B9\u30C8
532
+ - GET \`/lists\` \u2014 \u5168\u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u4E00\u89A7
533
+ - GET \`/lists/{list_id}\` \u2014 \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u8A73\u7D30
534
+ - POST \`/lists\` \u2014 \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u4F5C\u6210
535
+ - PATCH \`/lists/{list_id}\` \u2014 \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u66F4\u65B0
536
+ - DELETE \`/lists/{list_id}\` \u2014 \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u524A\u9664
537
+
538
+ #### \u30E1\u30F3\u30D0\u30FC / \u30B5\u30D6\u30B9\u30AF\u30E9\u30A4\u30D0\u30FC
539
+ - GET \`/lists/{list_id}/members\` \u2014 \u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7
540
+ - GET \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 \u30E1\u30F3\u30D0\u30FC\u306E\u8A73\u7D30\uFF08subscriber_hash = \u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u5C0F\u6587\u5B57\u306EMD5\uFF09
541
+ - POST \`/lists/{list_id}/members\` \u2014 \u30E1\u30F3\u30D0\u30FC\u306E\u8FFD\u52A0
542
+ - PUT \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 \u30E1\u30F3\u30D0\u30FC\u306E\u8FFD\u52A0\u307E\u305F\u306F\u66F4\u65B0
543
+ - PATCH \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 \u30E1\u30F3\u30D0\u30FC\u306E\u66F4\u65B0
544
+ - DELETE \`/lists/{list_id}/members/{subscriber_hash}\` \u2014 \u30E1\u30F3\u30D0\u30FC\u306E\u30A2\u30FC\u30AB\u30A4\u30D6
545
+
546
+ #### \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3
547
+ - GET \`/campaigns\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u4E00\u89A7
548
+ - GET \`/campaigns/{campaign_id}\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u306E\u8A73\u7D30
549
+ - POST \`/campaigns\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u306E\u4F5C\u6210
550
+ - PATCH \`/campaigns/{campaign_id}\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u306E\u66F4\u65B0
551
+ - DELETE \`/campaigns/{campaign_id}\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u306E\u524A\u9664
552
+ - POST \`/campaigns/{campaign_id}/actions/send\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u306E\u9001\u4FE1
553
+ - GET \`/campaigns/{campaign_id}/content\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u53D6\u5F97
554
+
555
+ #### \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8
556
+ - GET \`/templates\` \u2014 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u4E00\u89A7
557
+ - GET \`/templates/{template_id}\` \u2014 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u8A73\u7D30
558
+ - POST \`/templates\` \u2014 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u4F5C\u6210
559
+ - PATCH \`/templates/{template_id}\` \u2014 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u66F4\u65B0
560
+ - DELETE \`/templates/{template_id}\` \u2014 \u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u524A\u9664
561
+
562
+ #### \u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3
563
+ - GET \`/automations\` \u2014 \u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3\u4E00\u89A7
564
+ - GET \`/automations/{workflow_id}\` \u2014 \u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3\u306E\u8A73\u7D30
565
+ - GET \`/automations/{workflow_id}/emails\` \u2014 \u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3\u30E1\u30FC\u30EB\u4E00\u89A7
566
+ - POST \`/automations/{workflow_id}/actions/pause-all-emails\` \u2014 \u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3\u306E\u4E00\u6642\u505C\u6B62
567
+ - POST \`/automations/{workflow_id}/actions/start-all-emails\` \u2014 \u30AA\u30FC\u30C8\u30E1\u30FC\u30B7\u30E7\u30F3\u306E\u958B\u59CB
568
+
569
+ #### \u30EC\u30DD\u30FC\u30C8
570
+ - GET \`/reports\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30EC\u30DD\u30FC\u30C8\u4E00\u89A7
571
+ - GET \`/reports/{campaign_id}\` \u2014 \u30AD\u30E3\u30F3\u30DA\u30FC\u30F3\u30EC\u30DD\u30FC\u30C8\u306E\u53D6\u5F97
572
+ - GET \`/reports/{campaign_id}/click-details\` \u2014 \u30AF\u30EA\u30C3\u30AF\u8A73\u7D30
573
+ - GET \`/reports/{campaign_id}/open-details\` \u2014 \u958B\u5C01\u8A73\u7D30
574
+ - GET \`/reports/{campaign_id}/sent-to\` \u2014 \u9001\u4FE1\u5148\u8A73\u7D30
575
+ - GET \`/reports/{campaign_id}/unsubscribed\` \u2014 \u914D\u4FE1\u505C\u6B62\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7
576
+
577
+ #### \u691C\u7D22
578
+ - GET \`/search-members?query={query}\` \u2014 \u5168\u30AA\u30FC\u30C7\u30A3\u30A8\u30F3\u30B9\u306E\u30E1\u30F3\u30D0\u30FC\u691C\u7D22
579
+
580
+ #### \u30D0\u30C3\u30C1\u64CD\u4F5C
581
+ - POST \`/batches\` \u2014 \u30D0\u30C3\u30C1\u64CD\u4F5C\u306E\u958B\u59CB
582
+ - GET \`/batches\` \u2014 \u30D0\u30C3\u30C1\u64CD\u4F5C\u4E00\u89A7
583
+ - GET \`/batches/{batch_id}\` \u2014 \u30D0\u30C3\u30C1\u72B6\u614B\u306E\u53D6\u5F97
584
+
585
+ ### \u30D2\u30F3\u30C8
586
+ - \`fields\`\u3068\`exclude_fields\`\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u30EC\u30B9\u30DD\u30F3\u30B9\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u30D5\u30A3\u30EB\u30BF\u53EF\u80FD
587
+ - subscriber_hash\u306F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u306E\u5C0F\u6587\u5B57\u306EMD5\u30CF\u30C3\u30B7\u30E5
588
+ - \u30A8\u30E9\u30FC\u306F\`type\`, \`title\`, \`status\`, \`detail\`, \`instance\`\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u8FD4\u5374`
589
+ },
590
+ tools
591
+ });
592
+
593
+ // src/connectors/create-connector-sdk.ts
594
+ import { readFileSync } from "fs";
595
+ import path from "path";
596
+
597
+ // src/connector-client/env.ts
598
+ function resolveEnvVar(entry, key, connectionId) {
599
+ const envVarName = entry.envVars[key];
600
+ if (!envVarName) {
601
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
602
+ }
603
+ const value = process.env[envVarName];
604
+ if (!value) {
605
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
606
+ }
607
+ return value;
608
+ }
609
+ function resolveEnvVarOptional(entry, key) {
610
+ const envVarName = entry.envVars[key];
611
+ if (!envVarName) return void 0;
612
+ return process.env[envVarName] || void 0;
613
+ }
614
+
615
+ // src/connector-client/proxy-fetch.ts
616
+ import { getContext } from "hono/context-storage";
617
+ import { getCookie } from "hono/cookie";
618
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
619
+ function createSandboxProxyFetch(connectionId) {
620
+ return async (input, init) => {
621
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
622
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
623
+ if (!token || !sandboxId) {
624
+ throw new Error(
625
+ "Connection proxy is not configured. Please check your deployment settings."
626
+ );
627
+ }
628
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
629
+ const originalMethod = init?.method ?? "GET";
630
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
631
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
632
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
633
+ return fetch(proxyUrl, {
634
+ method: "POST",
635
+ headers: {
636
+ "Content-Type": "application/json",
637
+ Authorization: `Bearer ${token}`
638
+ },
639
+ body: JSON.stringify({
640
+ url: originalUrl,
641
+ method: originalMethod,
642
+ body: originalBody
643
+ })
644
+ });
645
+ };
646
+ }
647
+ function createDeployedAppProxyFetch(connectionId) {
648
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
649
+ if (!projectId) {
650
+ throw new Error(
651
+ "Connection proxy is not configured. Please check your deployment settings."
652
+ );
653
+ }
654
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
655
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
656
+ return async (input, init) => {
657
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
658
+ const originalMethod = init?.method ?? "GET";
659
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
660
+ const c = getContext();
661
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
662
+ if (!appSession) {
663
+ throw new Error(
664
+ "No authentication method available for connection proxy."
665
+ );
666
+ }
667
+ return fetch(proxyUrl, {
668
+ method: "POST",
669
+ headers: {
670
+ "Content-Type": "application/json",
671
+ Authorization: `Bearer ${appSession}`
672
+ },
673
+ body: JSON.stringify({
674
+ url: originalUrl,
675
+ method: originalMethod,
676
+ body: originalBody
677
+ })
678
+ });
679
+ };
680
+ }
681
+ function createProxyFetch(connectionId) {
682
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
683
+ return createSandboxProxyFetch(connectionId);
684
+ }
685
+ return createDeployedAppProxyFetch(connectionId);
686
+ }
687
+
688
+ // src/connectors/create-connector-sdk.ts
689
+ function loadConnectionsSync() {
690
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
691
+ try {
692
+ const raw = readFileSync(filePath, "utf-8");
693
+ return JSON.parse(raw);
694
+ } catch {
695
+ return {};
696
+ }
697
+ }
698
+ function createConnectorSdk(plugin, createClient2) {
699
+ return (connectionId) => {
700
+ const connections = loadConnectionsSync();
701
+ const entry = connections[connectionId];
702
+ if (!entry) {
703
+ throw new Error(
704
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
705
+ );
706
+ }
707
+ if (entry.connector.slug !== plugin.slug) {
708
+ throw new Error(
709
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
710
+ );
711
+ }
712
+ const params = {};
713
+ for (const param of Object.values(plugin.parameters)) {
714
+ if (param.required) {
715
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
716
+ } else {
717
+ const val = resolveEnvVarOptional(entry, param.slug);
718
+ if (val !== void 0) params[param.slug] = val;
719
+ }
720
+ }
721
+ return createClient2(params, createProxyFetch(connectionId));
722
+ };
723
+ }
724
+
725
+ // src/connectors/entries/mailchimp.ts
726
+ var connection = createConnectorSdk(mailchimpConnector, createClient);
727
+ export {
728
+ connection
729
+ };