@squadbase/vite-server 0.1.3-dev.8 → 0.1.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 +14229 -29321
- package/dist/connectors/airtable-oauth.js +43 -6
- package/dist/connectors/airtable.js +43 -6
- package/dist/connectors/amplitude.js +43 -6
- package/dist/connectors/anthropic.js +43 -6
- package/dist/connectors/asana.js +43 -6
- package/dist/connectors/attio.js +43 -6
- package/dist/connectors/{google-ads-oauth.d.ts → backlog-api-key.d.ts} +1 -1
- package/dist/connectors/backlog-api-key.js +629 -0
- package/dist/connectors/customerio.js +43 -6
- package/dist/connectors/dbt.js +43 -6
- package/dist/connectors/{google-sheets-oauth.d.ts → gamma.d.ts} +1 -1
- package/dist/connectors/gamma.js +866 -0
- package/dist/connectors/gemini.js +43 -6
- package/dist/connectors/gmail-oauth.js +65 -8
- package/dist/connectors/gmail.js +104 -44
- package/dist/connectors/google-ads.d.ts +1 -1
- package/dist/connectors/google-ads.js +410 -332
- package/dist/connectors/google-analytics-oauth.js +61 -8
- package/dist/connectors/google-analytics.js +107 -292
- package/dist/connectors/google-calendar-oauth.js +61 -8
- package/dist/connectors/google-calendar.js +111 -58
- package/dist/connectors/{linkedin-ads-oauth.d.ts → google-docs.d.ts} +1 -1
- package/dist/connectors/google-docs.js +631 -0
- package/dist/connectors/google-drive.d.ts +5 -0
- package/dist/connectors/google-drive.js +875 -0
- package/dist/connectors/google-sheets.d.ts +1 -1
- package/dist/connectors/google-sheets.js +267 -285
- package/dist/connectors/google-slides.d.ts +5 -0
- package/dist/connectors/google-slides.js +663 -0
- package/dist/connectors/grafana.js +43 -6
- package/dist/connectors/hubspot-oauth.js +43 -6
- package/dist/connectors/hubspot.js +43 -6
- package/dist/connectors/intercom-oauth.js +43 -6
- package/dist/connectors/intercom.js +43 -6
- package/dist/connectors/jira-api-key.js +43 -6
- package/dist/connectors/kintone-api-token.js +256 -82
- package/dist/connectors/kintone.js +43 -6
- package/dist/connectors/linkedin-ads.js +188 -168
- package/dist/connectors/mailchimp-oauth.js +43 -6
- package/dist/connectors/mailchimp.js +43 -6
- package/dist/connectors/mixpanel.d.ts +5 -0
- package/dist/connectors/mixpanel.js +779 -0
- package/dist/connectors/notion-oauth.js +43 -6
- package/dist/connectors/notion.js +43 -6
- package/dist/connectors/openai.js +43 -6
- package/dist/connectors/sentry.d.ts +5 -0
- package/dist/connectors/sentry.js +761 -0
- package/dist/connectors/shopify-oauth.js +43 -6
- package/dist/connectors/shopify.js +43 -6
- package/dist/connectors/stripe-api-key.js +46 -7
- package/dist/connectors/stripe-oauth.js +43 -6
- package/dist/connectors/wix-store.js +43 -6
- package/dist/connectors/zendesk-oauth.js +43 -6
- package/dist/connectors/zendesk.js +43 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4419 -3855
- package/dist/main.js +5481 -4918
- package/dist/vite-plugin.js +4474 -3948
- package/package.json +30 -12
- package/dist/connectors/google-ads-oauth.js +0 -890
- package/dist/connectors/google-sheets-oauth.js +0 -718
- package/dist/connectors/linkedin-ads-oauth.js +0 -848
|
@@ -0,0 +1,779 @@
|
|
|
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/mixpanel/parameters.ts
|
|
46
|
+
var parameters = {
|
|
47
|
+
serviceAccountUsername: new ParameterDefinition({
|
|
48
|
+
slug: "service-account-username",
|
|
49
|
+
name: "Service Account Username",
|
|
50
|
+
description: "The Mixpanel service account username for authentication.",
|
|
51
|
+
envVarBaseKey: "MIXPANEL_SERVICE_ACCOUNT_USERNAME",
|
|
52
|
+
type: "text",
|
|
53
|
+
secret: true,
|
|
54
|
+
required: true
|
|
55
|
+
}),
|
|
56
|
+
serviceAccountSecret: new ParameterDefinition({
|
|
57
|
+
slug: "service-account-secret",
|
|
58
|
+
name: "Service Account Secret",
|
|
59
|
+
description: "The Mixpanel service account secret for authentication.",
|
|
60
|
+
envVarBaseKey: "MIXPANEL_SERVICE_ACCOUNT_SECRET",
|
|
61
|
+
type: "text",
|
|
62
|
+
secret: true,
|
|
63
|
+
required: true
|
|
64
|
+
}),
|
|
65
|
+
projectId: new ParameterDefinition({
|
|
66
|
+
slug: "project-id",
|
|
67
|
+
name: "Project ID",
|
|
68
|
+
description: "The Mixpanel project ID. Required for service account authentication. Found in Project Settings.",
|
|
69
|
+
envVarBaseKey: "MIXPANEL_PROJECT_ID",
|
|
70
|
+
type: "text",
|
|
71
|
+
secret: false,
|
|
72
|
+
required: true
|
|
73
|
+
}),
|
|
74
|
+
region: new ParameterDefinition({
|
|
75
|
+
slug: "region",
|
|
76
|
+
name: "Region",
|
|
77
|
+
description: 'Mixpanel data residency region. Set to "eu" for EU, "in" for India. Leave empty for US (default).',
|
|
78
|
+
envVarBaseKey: "MIXPANEL_REGION",
|
|
79
|
+
type: "text",
|
|
80
|
+
secret: false,
|
|
81
|
+
required: false
|
|
82
|
+
})
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// ../connectors/src/connectors/mixpanel/sdk/index.ts
|
|
86
|
+
function createClient(params) {
|
|
87
|
+
const username = params[parameters.serviceAccountUsername.slug];
|
|
88
|
+
const secret = params[parameters.serviceAccountSecret.slug];
|
|
89
|
+
const projectId = params[parameters.projectId.slug];
|
|
90
|
+
const region = params[parameters.region.slug] ?? "us";
|
|
91
|
+
if (!username) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`mixpanel: missing required parameter: ${parameters.serviceAccountUsername.slug}`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!secret) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`mixpanel: missing required parameter: ${parameters.serviceAccountSecret.slug}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (!projectId) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`mixpanel: missing required parameter: ${parameters.projectId.slug}`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const queryBase = region === "eu" ? "https://eu.mixpanel.com/api/query" : region === "in" ? "https://in.mixpanel.com/api/query" : "https://mixpanel.com/api/query";
|
|
107
|
+
const exportBase = region === "eu" ? "https://data-eu.mixpanel.com/api/2.0/export" : region === "in" ? "https://data-in.mixpanel.com/api/2.0/export" : "https://data.mixpanel.com/api/2.0/export";
|
|
108
|
+
const authToken = btoa(`${username}:${secret}`);
|
|
109
|
+
function authHeaders(extra) {
|
|
110
|
+
const headers = new Headers(extra);
|
|
111
|
+
headers.set("Authorization", `Basic ${authToken}`);
|
|
112
|
+
headers.set("Accept", "application/json");
|
|
113
|
+
return headers;
|
|
114
|
+
}
|
|
115
|
+
async function assertOk(res, label) {
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
const body = await res.text().catch(() => "(unreadable body)");
|
|
118
|
+
throw new Error(
|
|
119
|
+
`mixpanel ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function withProjectId(url) {
|
|
124
|
+
if (!url.searchParams.has("project_id")) {
|
|
125
|
+
url.searchParams.set("project_id", projectId);
|
|
126
|
+
}
|
|
127
|
+
return url;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
request(url, init) {
|
|
131
|
+
const parsedUrl = withProjectId(new URL(url));
|
|
132
|
+
const headers = new Headers(init?.headers);
|
|
133
|
+
headers.set("Authorization", `Basic ${authToken}`);
|
|
134
|
+
headers.set("Accept", "application/json");
|
|
135
|
+
return fetch(parsedUrl.toString(), { ...init, headers });
|
|
136
|
+
},
|
|
137
|
+
async exportEvents(options) {
|
|
138
|
+
const url = new URL(exportBase);
|
|
139
|
+
url.searchParams.set("project_id", projectId);
|
|
140
|
+
url.searchParams.set("from_date", options.fromDate);
|
|
141
|
+
url.searchParams.set("to_date", options.toDate);
|
|
142
|
+
if (options.event) {
|
|
143
|
+
url.searchParams.set("event", JSON.stringify(options.event));
|
|
144
|
+
}
|
|
145
|
+
if (options.where) {
|
|
146
|
+
url.searchParams.set("where", options.where);
|
|
147
|
+
}
|
|
148
|
+
if (options.limit !== void 0) {
|
|
149
|
+
url.searchParams.set("limit", String(options.limit));
|
|
150
|
+
}
|
|
151
|
+
const res = await fetch(url.toString(), {
|
|
152
|
+
method: "GET",
|
|
153
|
+
headers: authHeaders()
|
|
154
|
+
});
|
|
155
|
+
await assertOk(res, "exportEvents");
|
|
156
|
+
const text = await res.text();
|
|
157
|
+
const lines = text.split("\n").filter((line) => line.trim().length > 0);
|
|
158
|
+
return lines.map(
|
|
159
|
+
(line) => JSON.parse(line)
|
|
160
|
+
);
|
|
161
|
+
},
|
|
162
|
+
async queryInsights(bookmarkId) {
|
|
163
|
+
const url = withProjectId(new URL(`${queryBase}/insights`));
|
|
164
|
+
url.searchParams.set("bookmark_id", String(bookmarkId));
|
|
165
|
+
const res = await fetch(url.toString(), {
|
|
166
|
+
method: "GET",
|
|
167
|
+
headers: authHeaders()
|
|
168
|
+
});
|
|
169
|
+
await assertOk(res, "queryInsights");
|
|
170
|
+
return await res.json();
|
|
171
|
+
},
|
|
172
|
+
async queryFunnels(options) {
|
|
173
|
+
const url = withProjectId(new URL(`${queryBase}/funnels`));
|
|
174
|
+
url.searchParams.set("funnel_id", String(options.funnelId));
|
|
175
|
+
url.searchParams.set("from_date", options.fromDate);
|
|
176
|
+
url.searchParams.set("to_date", options.toDate);
|
|
177
|
+
if (options.unit) url.searchParams.set("unit", options.unit);
|
|
178
|
+
if (options.interval !== void 0) {
|
|
179
|
+
url.searchParams.set("interval", String(options.interval));
|
|
180
|
+
}
|
|
181
|
+
const res = await fetch(url.toString(), {
|
|
182
|
+
method: "GET",
|
|
183
|
+
headers: authHeaders()
|
|
184
|
+
});
|
|
185
|
+
await assertOk(res, "queryFunnels");
|
|
186
|
+
return await res.json();
|
|
187
|
+
},
|
|
188
|
+
async queryProfiles(options) {
|
|
189
|
+
const url = withProjectId(new URL(`${queryBase}/engage`));
|
|
190
|
+
const bodyParams = new URLSearchParams();
|
|
191
|
+
if (options?.where) bodyParams.set("where", options.where);
|
|
192
|
+
if (options?.outputProperties) {
|
|
193
|
+
bodyParams.set(
|
|
194
|
+
"output_properties",
|
|
195
|
+
JSON.stringify(options.outputProperties)
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
if (options?.page !== void 0) {
|
|
199
|
+
bodyParams.set("page", String(options.page));
|
|
200
|
+
}
|
|
201
|
+
if (options?.sessionId) {
|
|
202
|
+
bodyParams.set("session_id", options.sessionId);
|
|
203
|
+
}
|
|
204
|
+
const res = await fetch(url.toString(), {
|
|
205
|
+
method: "POST",
|
|
206
|
+
headers: authHeaders({
|
|
207
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
208
|
+
}),
|
|
209
|
+
body: bodyParams.toString()
|
|
210
|
+
});
|
|
211
|
+
await assertOk(res, "queryProfiles");
|
|
212
|
+
return await res.json();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ../connectors/src/connector-onboarding.ts
|
|
218
|
+
var ConnectorOnboarding = class {
|
|
219
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
220
|
+
connectionSetupInstructions;
|
|
221
|
+
/** Phase 2: Data overview instructions */
|
|
222
|
+
dataOverviewInstructions;
|
|
223
|
+
constructor(config) {
|
|
224
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
225
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
226
|
+
}
|
|
227
|
+
getConnectionSetupPrompt(language) {
|
|
228
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
229
|
+
}
|
|
230
|
+
getDataOverviewInstructions(language) {
|
|
231
|
+
return this.dataOverviewInstructions[language];
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// ../connectors/src/connector-tool.ts
|
|
236
|
+
var ConnectorTool = class {
|
|
237
|
+
name;
|
|
238
|
+
description;
|
|
239
|
+
inputSchema;
|
|
240
|
+
outputSchema;
|
|
241
|
+
_execute;
|
|
242
|
+
constructor(config) {
|
|
243
|
+
this.name = config.name;
|
|
244
|
+
this.description = config.description;
|
|
245
|
+
this.inputSchema = config.inputSchema;
|
|
246
|
+
this.outputSchema = config.outputSchema;
|
|
247
|
+
this._execute = config.execute;
|
|
248
|
+
}
|
|
249
|
+
createTool(connections, config) {
|
|
250
|
+
return {
|
|
251
|
+
description: this.description,
|
|
252
|
+
inputSchema: this.inputSchema,
|
|
253
|
+
outputSchema: this.outputSchema,
|
|
254
|
+
execute: (input) => this._execute(input, connections, config)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// ../connectors/src/connector-plugin.ts
|
|
260
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
261
|
+
slug;
|
|
262
|
+
authType;
|
|
263
|
+
name;
|
|
264
|
+
description;
|
|
265
|
+
iconUrl;
|
|
266
|
+
parameters;
|
|
267
|
+
releaseFlag;
|
|
268
|
+
proxyPolicy;
|
|
269
|
+
experimentalAttributes;
|
|
270
|
+
onboarding;
|
|
271
|
+
systemPrompt;
|
|
272
|
+
tools;
|
|
273
|
+
query;
|
|
274
|
+
checkConnection;
|
|
275
|
+
constructor(config) {
|
|
276
|
+
this.slug = config.slug;
|
|
277
|
+
this.authType = config.authType;
|
|
278
|
+
this.name = config.name;
|
|
279
|
+
this.description = config.description;
|
|
280
|
+
this.iconUrl = config.iconUrl;
|
|
281
|
+
this.parameters = config.parameters;
|
|
282
|
+
this.releaseFlag = config.releaseFlag;
|
|
283
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
284
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
285
|
+
this.onboarding = config.onboarding;
|
|
286
|
+
this.systemPrompt = config.systemPrompt;
|
|
287
|
+
this.tools = config.tools;
|
|
288
|
+
this.query = config.query;
|
|
289
|
+
this.checkConnection = config.checkConnection;
|
|
290
|
+
}
|
|
291
|
+
get connectorKey() {
|
|
292
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Create tools for connections that belong to this connector.
|
|
296
|
+
* Filters connections by connectorKey internally.
|
|
297
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
298
|
+
*/
|
|
299
|
+
createTools(connections, config, opts) {
|
|
300
|
+
const myConnections = connections.filter(
|
|
301
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
302
|
+
);
|
|
303
|
+
const result = {};
|
|
304
|
+
for (const t of Object.values(this.tools)) {
|
|
305
|
+
const tool = t.createTool(myConnections, config);
|
|
306
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
307
|
+
result[`${this.connectorKey}_${t.name}`] = {
|
|
308
|
+
...tool,
|
|
309
|
+
toModelOutput: async (options) => {
|
|
310
|
+
if (!originalToModelOutput) {
|
|
311
|
+
return opts.truncateOutput(options.output);
|
|
312
|
+
}
|
|
313
|
+
const modelOutput = await originalToModelOutput(options);
|
|
314
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
315
|
+
return opts.truncateOutput(modelOutput.value);
|
|
316
|
+
}
|
|
317
|
+
return modelOutput;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
static deriveKey(slug, authType) {
|
|
324
|
+
if (authType) return `${slug}-${authType}`;
|
|
325
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
326
|
+
// user-password
|
|
327
|
+
"postgresql": "user-password",
|
|
328
|
+
"mysql": "user-password",
|
|
329
|
+
"clickhouse": "user-password",
|
|
330
|
+
"kintone": "user-password",
|
|
331
|
+
"squadbase-db": "user-password",
|
|
332
|
+
// service-account
|
|
333
|
+
"snowflake": "service-account",
|
|
334
|
+
"bigquery": "service-account",
|
|
335
|
+
"google-analytics": "service-account",
|
|
336
|
+
"google-calendar": "service-account",
|
|
337
|
+
"aws-athena": "service-account",
|
|
338
|
+
"redshift": "service-account",
|
|
339
|
+
// api-key
|
|
340
|
+
"databricks": "api-key",
|
|
341
|
+
"dbt": "api-key",
|
|
342
|
+
"airtable": "api-key",
|
|
343
|
+
"openai": "api-key",
|
|
344
|
+
"gemini": "api-key",
|
|
345
|
+
"anthropic": "api-key",
|
|
346
|
+
"wix-store": "api-key"
|
|
347
|
+
};
|
|
348
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
349
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
350
|
+
return slug;
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// ../connectors/src/auth-types.ts
|
|
355
|
+
var AUTH_TYPES = {
|
|
356
|
+
OAUTH: "oauth",
|
|
357
|
+
API_KEY: "api-key",
|
|
358
|
+
JWT: "jwt",
|
|
359
|
+
SERVICE_ACCOUNT: "service-account",
|
|
360
|
+
PAT: "pat",
|
|
361
|
+
USER_PASSWORD: "user-password"
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
// ../connectors/src/connectors/mixpanel/setup.ts
|
|
365
|
+
var mixpanelOnboarding = new ConnectorOnboarding({
|
|
366
|
+
dataOverviewInstructions: {
|
|
367
|
+
en: `1. Check the connection's region parameter to determine the base URL:
|
|
368
|
+
- US (default): https://mixpanel.com/api/query (Query API), https://data.mixpanel.com/api/2.0/export (Export API)
|
|
369
|
+
- EU: https://eu.mixpanel.com/api/query, https://data-eu.mixpanel.com/api/2.0/export
|
|
370
|
+
- India: https://in.mixpanel.com/api/query, https://data-in.mixpanel.com/api/2.0/export
|
|
371
|
+
2. Call mixpanel_request with GET {exportBase}?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD (use a short recent date range, e.g. 1-2 days) to export raw events and discover available event types and properties
|
|
372
|
+
3. Call mixpanel_request with POST {queryBase}/engage to query user profiles and understand user properties
|
|
373
|
+
NOTE: The Query API endpoints (insights, funnels, retention) require a bookmark_id or funnel_id from existing reports in Mixpanel. Use the Export API to retrieve raw events and aggregate in code if you need ad-hoc analysis.`,
|
|
374
|
+
ja: `1. \u63A5\u7D9A\u306Eregion\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u78BA\u8A8D\u3057\u3066\u30D9\u30FC\u30B9URL\u3092\u6C7A\u5B9A\uFF1A
|
|
375
|
+
- US\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\uFF09: https://mixpanel.com/api/query\uFF08Query API\uFF09\u3001https://data.mixpanel.com/api/2.0/export\uFF08Export API\uFF09
|
|
376
|
+
- EU: https://eu.mixpanel.com/api/query\u3001https://data-eu.mixpanel.com/api/2.0/export
|
|
377
|
+
- India: https://in.mixpanel.com/api/query\u3001https://data-in.mixpanel.com/api/2.0/export
|
|
378
|
+
2. mixpanel_request \u3067 GET {exportBase}?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD \u3092\u547C\u3073\u51FA\u3057\uFF08\u76F4\u8FD11-2\u65E5\u306E\u77ED\u3044\u671F\u9593\u3092\u4F7F\u7528\uFF09\u3001\u751F\u30A4\u30D9\u30F3\u30C8\u3092\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3057\u3066\u5229\u7528\u53EF\u80FD\u306A\u30A4\u30D9\u30F3\u30C8\u30BF\u30A4\u30D7\u3068\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u78BA\u8A8D
|
|
379
|
+
3. mixpanel_request \u3067 POST {queryBase}/engage \u3092\u547C\u3073\u51FA\u3057\u3001\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3092\u7167\u4F1A\u3057\u3066\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u628A\u63E1
|
|
380
|
+
\u6CE8\u610F: Query API\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\uFF08insights\u3001funnels\u3001retention\uFF09\u306FMixpanel\u5185\u306E\u65E2\u5B58\u30EC\u30DD\u30FC\u30C8\u306Ebookmark_id\u307E\u305F\u306Ffunnel_id\u304C\u5FC5\u8981\u3067\u3059\u3002\u30A2\u30C9\u30DB\u30C3\u30AF\u5206\u6790\u304C\u5FC5\u8981\u306A\u5834\u5408\u306F\u3001Export API\u3067\u751F\u30A4\u30D9\u30F3\u30C8\u3092\u53D6\u5F97\u3057\u3001\u30B3\u30FC\u30C9\u4E0A\u3067\u96C6\u8A08\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// ../connectors/src/connectors/mixpanel/tools/request.ts
|
|
385
|
+
import { z } from "zod";
|
|
386
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
387
|
+
var inputSchema = z.object({
|
|
388
|
+
toolUseIntent: z.string().optional().describe(
|
|
389
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
390
|
+
),
|
|
391
|
+
connectionId: z.string().describe("ID of the Mixpanel connection to use"),
|
|
392
|
+
method: z.enum(["GET", "POST"]).describe(
|
|
393
|
+
"HTTP method. GET for most Query API and Export endpoints. POST for Engage (profile query) endpoint."
|
|
394
|
+
),
|
|
395
|
+
url: z.string().describe(
|
|
396
|
+
"Full URL including query parameters (e.g., 'https://mixpanel.com/api/query/insights?project_id=12345&bookmark_id=67890'). The project_id query parameter is added automatically if not present."
|
|
397
|
+
),
|
|
398
|
+
body: z.string().optional().describe(
|
|
399
|
+
"Request body for POST requests. Use application/x-www-form-urlencoded format for the Engage endpoint, or JSON string for other POST endpoints."
|
|
400
|
+
),
|
|
401
|
+
contentType: z.enum(["application/json", "application/x-www-form-urlencoded"]).optional().describe(
|
|
402
|
+
"Content-Type header. Defaults to application/json. Use application/x-www-form-urlencoded for the Engage endpoint."
|
|
403
|
+
)
|
|
404
|
+
});
|
|
405
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
406
|
+
z.object({
|
|
407
|
+
success: z.literal(true),
|
|
408
|
+
status: z.number(),
|
|
409
|
+
data: z.unknown()
|
|
410
|
+
}),
|
|
411
|
+
z.object({
|
|
412
|
+
success: z.literal(false),
|
|
413
|
+
error: z.string()
|
|
414
|
+
})
|
|
415
|
+
]);
|
|
416
|
+
var requestTool = new ConnectorTool({
|
|
417
|
+
name: "request",
|
|
418
|
+
description: `Send authenticated requests to the Mixpanel REST API.
|
|
419
|
+
Authentication is handled automatically using Basic auth (Service Account username + secret).
|
|
420
|
+
Provide the full URL including any query parameters. The project_id query parameter is appended automatically if not present in the URL.
|
|
421
|
+
|
|
422
|
+
Base URLs by region and endpoint type:
|
|
423
|
+
- Query API: US \u2192 https://mixpanel.com/api/query, EU \u2192 https://eu.mixpanel.com/api/query, India \u2192 https://in.mixpanel.com/api/query
|
|
424
|
+
- Export API: US \u2192 https://data.mixpanel.com/api/2.0/export, EU \u2192 https://data-eu.mixpanel.com/api/2.0/export, India \u2192 https://data-in.mixpanel.com/api/2.0/export
|
|
425
|
+
|
|
426
|
+
Key endpoints:
|
|
427
|
+
- GET {queryBase}/insights?project_id=ID&bookmark_id=ID \u2014 Insights report (requires bookmark_id)
|
|
428
|
+
- GET {queryBase}/funnels?project_id=ID&funnel_id=ID&from_date=YYYY-MM-DD&to_date=YYYY-MM-DD \u2014 Funnel analysis
|
|
429
|
+
- GET {queryBase}/retention?project_id=ID&from_date=YYYY-MM-DD&to_date=YYYY-MM-DD \u2014 Retention analysis
|
|
430
|
+
- POST {queryBase}/engage?project_id=ID \u2014 Query user/group profiles
|
|
431
|
+
- GET {exportBase}?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD \u2014 Export raw events (JSONL)
|
|
432
|
+
|
|
433
|
+
Rate limit: 60 queries/hour, 5 concurrent queries for Query API.`,
|
|
434
|
+
inputSchema,
|
|
435
|
+
outputSchema,
|
|
436
|
+
async execute({ connectionId, method, url, body, contentType }, connections) {
|
|
437
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
438
|
+
if (!connection2) {
|
|
439
|
+
return {
|
|
440
|
+
success: false,
|
|
441
|
+
error: `Connection ${connectionId} not found`
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
console.log(
|
|
445
|
+
`[connector-request] mixpanel/${connection2.name}: ${method} ${url}`
|
|
446
|
+
);
|
|
447
|
+
try {
|
|
448
|
+
const username = parameters.serviceAccountUsername.getValue(connection2);
|
|
449
|
+
const secret = parameters.serviceAccountSecret.getValue(connection2);
|
|
450
|
+
const projectId = parameters.projectId.getValue(connection2);
|
|
451
|
+
const authToken = btoa(`${username}:${secret}`);
|
|
452
|
+
let finalUrl = url;
|
|
453
|
+
const urlObj = new URL(url);
|
|
454
|
+
if (!urlObj.searchParams.has("project_id")) {
|
|
455
|
+
urlObj.searchParams.set("project_id", projectId);
|
|
456
|
+
finalUrl = urlObj.toString();
|
|
457
|
+
}
|
|
458
|
+
const controller = new AbortController();
|
|
459
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
460
|
+
try {
|
|
461
|
+
const headers = {
|
|
462
|
+
Authorization: `Basic ${authToken}`,
|
|
463
|
+
Accept: "application/json"
|
|
464
|
+
};
|
|
465
|
+
const effectiveContentType = contentType ?? "application/json";
|
|
466
|
+
if (body) {
|
|
467
|
+
headers["Content-Type"] = effectiveContentType;
|
|
468
|
+
}
|
|
469
|
+
const response = await fetch(finalUrl, {
|
|
470
|
+
method,
|
|
471
|
+
headers,
|
|
472
|
+
body: body ?? void 0,
|
|
473
|
+
signal: controller.signal
|
|
474
|
+
});
|
|
475
|
+
const responseContentType = response.headers.get("content-type") ?? "";
|
|
476
|
+
let data;
|
|
477
|
+
if (responseContentType.includes("application/json")) {
|
|
478
|
+
data = await response.json();
|
|
479
|
+
} else {
|
|
480
|
+
const text = await response.text();
|
|
481
|
+
const lines = text.split("\n").filter((line) => line.trim().length > 0);
|
|
482
|
+
if (lines.length > 0) {
|
|
483
|
+
try {
|
|
484
|
+
data = lines.map(
|
|
485
|
+
(line) => JSON.parse(line)
|
|
486
|
+
);
|
|
487
|
+
} catch {
|
|
488
|
+
data = { raw: text };
|
|
489
|
+
}
|
|
490
|
+
} else {
|
|
491
|
+
data = { raw: text };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (!response.ok) {
|
|
495
|
+
const errorMessage = typeof data?.error === "string" ? data.error : typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`;
|
|
496
|
+
return { success: false, error: errorMessage };
|
|
497
|
+
}
|
|
498
|
+
return { success: true, status: response.status, data };
|
|
499
|
+
} finally {
|
|
500
|
+
clearTimeout(timeout);
|
|
501
|
+
}
|
|
502
|
+
} catch (err) {
|
|
503
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
504
|
+
return { success: false, error: msg };
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// ../connectors/src/connectors/mixpanel/index.ts
|
|
510
|
+
var tools = { request: requestTool };
|
|
511
|
+
var mixpanelConnector = new ConnectorPlugin({
|
|
512
|
+
slug: "mixpanel",
|
|
513
|
+
authType: AUTH_TYPES.API_KEY,
|
|
514
|
+
name: "Mixpanel",
|
|
515
|
+
description: "Connect to Mixpanel for product analytics, event tracking, and user behavior analysis.",
|
|
516
|
+
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/7ykz0vNRjMqvTVrxS8wsj1/b2cd795be5b373877dee77cc6147c758/images__3_.png",
|
|
517
|
+
parameters,
|
|
518
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
519
|
+
onboarding: mixpanelOnboarding,
|
|
520
|
+
systemPrompt: {
|
|
521
|
+
en: `### Tools
|
|
522
|
+
|
|
523
|
+
- \`mixpanel_request\`: The only way to call the Mixpanel REST API. Use it for exporting raw events, querying insights/funnels/retention reports, and querying user profiles. Authentication (Basic auth with Service Account username + secret) is configured automatically. The project_id query parameter is appended automatically. Provide the full URL including query parameters \u2014 the base URL varies by region and endpoint type.
|
|
524
|
+
|
|
525
|
+
### Business Logic
|
|
526
|
+
|
|
527
|
+
The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
|
|
528
|
+
|
|
529
|
+
SDK methods (client created via \`connection(connectionId)\`):
|
|
530
|
+
- \`client.request(url, init?)\` \u2014 low-level authenticated fetch (provide full URL; project_id is added automatically)
|
|
531
|
+
- \`client.exportEvents(options)\` \u2014 export raw events (fromDate, toDate, event?, where?, limit?)
|
|
532
|
+
- \`client.queryInsights(bookmarkId)\` \u2014 query an Insights report by bookmark ID
|
|
533
|
+
- \`client.queryFunnels(options)\` \u2014 query a Funnel report (funnelId, fromDate, toDate, unit?, interval?)
|
|
534
|
+
- \`client.queryProfiles(options?)\` \u2014 query user/group profiles (where?, outputProperties?, page?, sessionId?)
|
|
535
|
+
|
|
536
|
+
\`\`\`ts
|
|
537
|
+
import type { Context } from "hono";
|
|
538
|
+
import { connection } from "@squadbase/vite-server/connectors/mixpanel";
|
|
539
|
+
|
|
540
|
+
const mp = connection("<connectionId>");
|
|
541
|
+
|
|
542
|
+
export default async function handler(c: Context) {
|
|
543
|
+
const { fromDate, toDate } = await c.req.json<{
|
|
544
|
+
fromDate: string;
|
|
545
|
+
toDate: string;
|
|
546
|
+
}>();
|
|
547
|
+
|
|
548
|
+
const events = await mp.exportEvents({ fromDate, toDate, limit: 1000 });
|
|
549
|
+
|
|
550
|
+
return c.json(events);
|
|
551
|
+
}
|
|
552
|
+
\`\`\`
|
|
553
|
+
|
|
554
|
+
### Mixpanel REST API Reference
|
|
555
|
+
|
|
556
|
+
- Authentication: Basic auth (Service Account username:secret, handled automatically)
|
|
557
|
+
- project_id is always appended automatically to all requests
|
|
558
|
+
|
|
559
|
+
#### Base URLs by Region
|
|
560
|
+
|
|
561
|
+
| Region | Query API | Export API |
|
|
562
|
+
|--------|-----------|------------|
|
|
563
|
+
| US (default) | https://mixpanel.com/api/query | https://data.mixpanel.com/api/2.0/export |
|
|
564
|
+
| EU | https://eu.mixpanel.com/api/query | https://data-eu.mixpanel.com/api/2.0/export |
|
|
565
|
+
| India | https://in.mixpanel.com/api/query | https://data-in.mixpanel.com/api/2.0/export |
|
|
566
|
+
|
|
567
|
+
#### Export API (Raw Events)
|
|
568
|
+
- GET \`{exportBase}?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD\` \u2014 Export raw events (JSONL format)
|
|
569
|
+
- Optional: \`event\` (JSON array of event names), \`where\` (filter expression), \`limit\` (max 100,000)
|
|
570
|
+
- Rate limit: 60 queries/hour, 3 queries/second, 100 concurrent max
|
|
571
|
+
|
|
572
|
+
#### Query API (Reports)
|
|
573
|
+
- GET \`{queryBase}/insights?bookmark_id=ID\` \u2014 Insights report (requires bookmark_id from Mixpanel UI)
|
|
574
|
+
- GET \`{queryBase}/funnels?funnel_id=ID&from_date=YYYY-MM-DD&to_date=YYYY-MM-DD\` \u2014 Funnel analysis
|
|
575
|
+
- GET \`{queryBase}/retention?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD\` \u2014 Retention analysis
|
|
576
|
+
- POST \`{queryBase}/engage\` \u2014 Query user/group profiles (application/x-www-form-urlencoded body)
|
|
577
|
+
- Rate limit: 60 queries/hour, 5 concurrent max
|
|
578
|
+
|
|
579
|
+
IMPORTANT: The Insights endpoint requires a bookmark_id from an existing report in the Mixpanel UI. For ad-hoc event analysis, use the Export API to retrieve raw events and aggregate them in code. The Export API is the most flexible and universally accessible endpoint.`,
|
|
580
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
581
|
+
|
|
582
|
+
- \`mixpanel_request\`: Mixpanel REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u751F\u30A4\u30D9\u30F3\u30C8\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3001\u30A4\u30F3\u30B5\u30A4\u30C8/\u30D5\u30A1\u30CD\u30EB/\u30EA\u30C6\u30F3\u30B7\u30E7\u30F3\u30EC\u30DD\u30FC\u30C8\u306E\u7167\u4F1A\u3001\u30E6\u30FC\u30B6\u30FC\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u7167\u4F1A\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08Service Account\u306E\u30E6\u30FC\u30B6\u30FC\u540D+\u30B7\u30FC\u30AF\u30EC\u30C3\u30C8\u306B\u3088\u308BBasic\u8A8D\u8A3C\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002project_id\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u306F\u81EA\u52D5\u7684\u306B\u4ED8\u52A0\u3055\u308C\u307E\u3059\u3002\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u542B\u3080\u5B8C\u5168\u306AURL\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044 \u2014 \u30D9\u30FC\u30B9URL\u306F\u30EA\u30FC\u30B8\u30E7\u30F3\u3068\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u30BF\u30A4\u30D7\u306B\u3088\u3063\u3066\u7570\u306A\u308A\u307E\u3059\u3002
|
|
583
|
+
|
|
584
|
+
### Business Logic
|
|
585
|
+
|
|
586
|
+
\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
|
|
587
|
+
|
|
588
|
+
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
589
|
+
- \`client.request(url, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch\uFF08\u5B8C\u5168\u306AURL\u3092\u6307\u5B9A\u3001project_id\u306F\u81EA\u52D5\u4ED8\u52A0\uFF09
|
|
590
|
+
- \`client.exportEvents(options)\` \u2014 \u751F\u30A4\u30D9\u30F3\u30C8\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\uFF08fromDate, toDate, event?, where?, limit?\uFF09
|
|
591
|
+
- \`client.queryInsights(bookmarkId)\` \u2014 \u30D6\u30C3\u30AF\u30DE\u30FC\u30AFID\u3067Insights\u30EC\u30DD\u30FC\u30C8\u3092\u7167\u4F1A
|
|
592
|
+
- \`client.queryFunnels(options)\` \u2014 \u30D5\u30A1\u30CD\u30EB\u30EC\u30DD\u30FC\u30C8\u306E\u7167\u4F1A\uFF08funnelId, fromDate, toDate, unit?, interval?\uFF09
|
|
593
|
+
- \`client.queryProfiles(options?)\` \u2014 \u30E6\u30FC\u30B6\u30FC/\u30B0\u30EB\u30FC\u30D7\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u7167\u4F1A\uFF08where?, outputProperties?, page?, sessionId?\uFF09
|
|
594
|
+
|
|
595
|
+
\`\`\`ts
|
|
596
|
+
import type { Context } from "hono";
|
|
597
|
+
import { connection } from "@squadbase/vite-server/connectors/mixpanel";
|
|
598
|
+
|
|
599
|
+
const mp = connection("<connectionId>");
|
|
600
|
+
|
|
601
|
+
export default async function handler(c: Context) {
|
|
602
|
+
const { fromDate, toDate } = await c.req.json<{
|
|
603
|
+
fromDate: string;
|
|
604
|
+
toDate: string;
|
|
605
|
+
}>();
|
|
606
|
+
|
|
607
|
+
const events = await mp.exportEvents({ fromDate, toDate, limit: 1000 });
|
|
608
|
+
|
|
609
|
+
return c.json(events);
|
|
610
|
+
}
|
|
611
|
+
\`\`\`
|
|
612
|
+
|
|
613
|
+
### Mixpanel REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
614
|
+
|
|
615
|
+
- \u8A8D\u8A3C: Basic\u8A8D\u8A3C\uFF08Service Account\u306E\u30E6\u30FC\u30B6\u30FC\u540D:\u30B7\u30FC\u30AF\u30EC\u30C3\u30C8\u3001\u81EA\u52D5\u8A2D\u5B9A\uFF09
|
|
616
|
+
- project_id\u306F\u3059\u3079\u3066\u306E\u30EA\u30AF\u30A8\u30B9\u30C8\u306B\u81EA\u52D5\u7684\u306B\u4ED8\u52A0\u3055\u308C\u307E\u3059
|
|
617
|
+
|
|
618
|
+
#### \u30EA\u30FC\u30B8\u30E7\u30F3\u5225\u30D9\u30FC\u30B9URL
|
|
619
|
+
|
|
620
|
+
| \u30EA\u30FC\u30B8\u30E7\u30F3 | Query API | Export API |
|
|
621
|
+
|-----------|-----------|------------|
|
|
622
|
+
| US\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\uFF09 | https://mixpanel.com/api/query | https://data.mixpanel.com/api/2.0/export |
|
|
623
|
+
| EU | https://eu.mixpanel.com/api/query | https://data-eu.mixpanel.com/api/2.0/export |
|
|
624
|
+
| India | https://in.mixpanel.com/api/query | https://data-in.mixpanel.com/api/2.0/export |
|
|
625
|
+
|
|
626
|
+
#### Export API\uFF08\u751F\u30A4\u30D9\u30F3\u30C8\uFF09
|
|
627
|
+
- GET \`{exportBase}?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD\` \u2014 \u751F\u30A4\u30D9\u30F3\u30C8\u306E\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\uFF08JSONL\u5F62\u5F0F\uFF09
|
|
628
|
+
- \u30AA\u30D7\u30B7\u30E7\u30F3: \`event\`\uFF08\u30A4\u30D9\u30F3\u30C8\u540D\u306EJSON\u914D\u5217\uFF09\u3001\`where\`\uFF08\u30D5\u30A3\u30EB\u30BF\u5F0F\uFF09\u3001\`limit\`\uFF08\u6700\u5927100,000\uFF09
|
|
629
|
+
- \u30EC\u30FC\u30C8\u5236\u9650: 60\u30AF\u30A8\u30EA/\u6642\u30013\u30AF\u30A8\u30EA/\u79D2\u3001\u6700\u5927100\u540C\u6642\u63A5\u7D9A
|
|
630
|
+
|
|
631
|
+
#### Query API\uFF08\u30EC\u30DD\u30FC\u30C8\uFF09
|
|
632
|
+
- GET \`{queryBase}/insights?bookmark_id=ID\` \u2014 Insights\u30EC\u30DD\u30FC\u30C8\uFF08Mixpanel UI\u304B\u3089\u306Ebookmark_id\u304C\u5FC5\u8981\uFF09
|
|
633
|
+
- GET \`{queryBase}/funnels?funnel_id=ID&from_date=YYYY-MM-DD&to_date=YYYY-MM-DD\` \u2014 \u30D5\u30A1\u30CD\u30EB\u5206\u6790
|
|
634
|
+
- GET \`{queryBase}/retention?from_date=YYYY-MM-DD&to_date=YYYY-MM-DD\` \u2014 \u30EA\u30C6\u30F3\u30B7\u30E7\u30F3\u5206\u6790
|
|
635
|
+
- POST \`{queryBase}/engage\` \u2014 \u30E6\u30FC\u30B6\u30FC/\u30B0\u30EB\u30FC\u30D7\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u7167\u4F1A\uFF08application/x-www-form-urlencoded\u306Ebody\uFF09
|
|
636
|
+
- \u30EC\u30FC\u30C8\u5236\u9650: 60\u30AF\u30A8\u30EA/\u6642\u3001\u6700\u59275\u540C\u6642\u63A5\u7D9A
|
|
637
|
+
|
|
638
|
+
\u91CD\u8981: Insights\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306F\u3001Mixpanel UI\u306E\u65E2\u5B58\u30EC\u30DD\u30FC\u30C8\u306Ebookmark_id\u304C\u5FC5\u8981\u3067\u3059\u3002\u30A2\u30C9\u30DB\u30C3\u30AF\u306A\u30A4\u30D9\u30F3\u30C8\u5206\u6790\u306B\u306F\u3001Export API\u3067\u751F\u30A4\u30D9\u30F3\u30C8\u3092\u53D6\u5F97\u3057\u3001\u30B3\u30FC\u30C9\u4E0A\u3067\u96C6\u8A08\u3057\u3066\u304F\u3060\u3055\u3044\u3002Export API\u304C\u6700\u3082\u67D4\u8EDF\u3067\u5E83\u304F\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u306A\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3067\u3059\u3002`
|
|
639
|
+
},
|
|
640
|
+
tools
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// src/connectors/create-connector-sdk.ts
|
|
644
|
+
import { readFileSync } from "fs";
|
|
645
|
+
import path from "path";
|
|
646
|
+
|
|
647
|
+
// src/connector-client/env.ts
|
|
648
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
649
|
+
const envVarName = entry.envVars[key];
|
|
650
|
+
if (!envVarName) {
|
|
651
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
652
|
+
}
|
|
653
|
+
const value = process.env[envVarName];
|
|
654
|
+
if (!value) {
|
|
655
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
656
|
+
}
|
|
657
|
+
return value;
|
|
658
|
+
}
|
|
659
|
+
function resolveEnvVarOptional(entry, key) {
|
|
660
|
+
const envVarName = entry.envVars[key];
|
|
661
|
+
if (!envVarName) return void 0;
|
|
662
|
+
return process.env[envVarName] || void 0;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// src/connector-client/proxy-fetch.ts
|
|
666
|
+
import { getContext } from "hono/context-storage";
|
|
667
|
+
import { getCookie } from "hono/cookie";
|
|
668
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
669
|
+
function createSandboxProxyFetch(connectionId) {
|
|
670
|
+
return async (input, init) => {
|
|
671
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
672
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
673
|
+
if (!token || !sandboxId) {
|
|
674
|
+
throw new Error(
|
|
675
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
679
|
+
const originalMethod = init?.method ?? "GET";
|
|
680
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
681
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
682
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
683
|
+
return fetch(proxyUrl, {
|
|
684
|
+
method: "POST",
|
|
685
|
+
headers: {
|
|
686
|
+
"Content-Type": "application/json",
|
|
687
|
+
Authorization: `Bearer ${token}`
|
|
688
|
+
},
|
|
689
|
+
body: JSON.stringify({
|
|
690
|
+
url: originalUrl,
|
|
691
|
+
method: originalMethod,
|
|
692
|
+
body: originalBody
|
|
693
|
+
})
|
|
694
|
+
});
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
698
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
699
|
+
if (!projectId) {
|
|
700
|
+
throw new Error(
|
|
701
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
705
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
706
|
+
return async (input, init) => {
|
|
707
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
708
|
+
const originalMethod = init?.method ?? "GET";
|
|
709
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
710
|
+
const c = getContext();
|
|
711
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
712
|
+
if (!appSession) {
|
|
713
|
+
throw new Error(
|
|
714
|
+
"No authentication method available for connection proxy."
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
return fetch(proxyUrl, {
|
|
718
|
+
method: "POST",
|
|
719
|
+
headers: {
|
|
720
|
+
"Content-Type": "application/json",
|
|
721
|
+
Authorization: `Bearer ${appSession}`
|
|
722
|
+
},
|
|
723
|
+
body: JSON.stringify({
|
|
724
|
+
url: originalUrl,
|
|
725
|
+
method: originalMethod,
|
|
726
|
+
body: originalBody
|
|
727
|
+
})
|
|
728
|
+
});
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
function createProxyFetch(connectionId) {
|
|
732
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
733
|
+
return createSandboxProxyFetch(connectionId);
|
|
734
|
+
}
|
|
735
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// src/connectors/create-connector-sdk.ts
|
|
739
|
+
function loadConnectionsSync() {
|
|
740
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
741
|
+
try {
|
|
742
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
743
|
+
return JSON.parse(raw);
|
|
744
|
+
} catch {
|
|
745
|
+
return {};
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
749
|
+
return (connectionId) => {
|
|
750
|
+
const connections = loadConnectionsSync();
|
|
751
|
+
const entry = connections[connectionId];
|
|
752
|
+
if (!entry) {
|
|
753
|
+
throw new Error(
|
|
754
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
758
|
+
throw new Error(
|
|
759
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
const params = {};
|
|
763
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
764
|
+
if (param.required) {
|
|
765
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
766
|
+
} else {
|
|
767
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
768
|
+
if (val !== void 0) params[param.slug] = val;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/connectors/entries/mixpanel.ts
|
|
776
|
+
var connection = createConnectorSdk(mixpanelConnector, createClient);
|
|
777
|
+
export {
|
|
778
|
+
connection
|
|
779
|
+
};
|