@squadbase/vite-server 0.1.8 → 0.1.9-dev.87dd3f7
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 +1055 -520
- package/dist/connectors/airtable-oauth.js +3 -0
- package/dist/connectors/airtable.js +3 -0
- package/dist/connectors/amplitude.js +3 -0
- package/dist/connectors/anthropic.js +3 -0
- package/dist/connectors/asana.js +3 -0
- package/dist/connectors/attio.js +3 -0
- package/dist/connectors/backlog-api-key.js +3 -0
- package/dist/connectors/customerio.js +3 -0
- package/dist/connectors/dbt.js +3 -0
- package/dist/connectors/gamma.js +3 -0
- package/dist/connectors/gemini.js +3 -0
- package/dist/connectors/gmail-oauth.js +3 -0
- package/dist/connectors/gmail.js +11 -2
- package/dist/connectors/google-ads.js +3 -0
- package/dist/connectors/google-analytics-oauth.js +3 -0
- package/dist/connectors/google-analytics.js +3 -0
- package/dist/connectors/google-audit-log.d.ts +5 -0
- package/dist/connectors/google-audit-log.js +802 -0
- package/dist/connectors/google-calendar-oauth.js +3 -0
- package/dist/connectors/google-calendar.js +102 -49
- package/dist/connectors/google-docs.js +3 -0
- package/dist/connectors/google-drive.js +3 -0
- package/dist/connectors/google-sheets.js +3 -0
- package/dist/connectors/google-slides.js +3 -0
- package/dist/connectors/grafana.js +3 -0
- package/dist/connectors/hubspot-oauth.js +3 -0
- package/dist/connectors/hubspot.js +3 -0
- package/dist/connectors/influxdb.js +3 -0
- package/dist/connectors/intercom-oauth.js +3 -0
- package/dist/connectors/intercom.js +3 -0
- package/dist/connectors/jira-api-key.js +3 -0
- package/dist/connectors/kintone-api-token.js +3 -0
- package/dist/connectors/kintone.js +3 -0
- package/dist/connectors/linear.js +3 -0
- package/dist/connectors/linkedin-ads.js +3 -0
- package/dist/connectors/mailchimp-oauth.js +3 -0
- package/dist/connectors/mailchimp.js +3 -0
- package/dist/connectors/meta-ads-oauth.js +3 -0
- package/dist/connectors/meta-ads.js +3 -0
- package/dist/connectors/mixpanel.js +3 -0
- package/dist/connectors/notion-oauth.js +3 -0
- package/dist/connectors/notion.js +3 -0
- package/dist/connectors/openai.js +3 -0
- package/dist/connectors/salesforce.js +3 -0
- package/dist/connectors/sentry.js +3 -0
- package/dist/connectors/shopify-oauth.js +3 -0
- package/dist/connectors/shopify.js +3 -0
- package/dist/connectors/stripe-api-key.js +3 -0
- package/dist/connectors/stripe-oauth.js +3 -0
- package/dist/connectors/tiktok-ads.js +3 -0
- package/dist/connectors/wix-store.js +3 -0
- package/dist/connectors/zendesk-oauth.js +3 -0
- package/dist/connectors/zendesk.js +3 -0
- package/dist/index.js +1055 -520
- package/dist/main.js +1055 -520
- package/dist/vite-plugin.js +1055 -520
- package/package.json +5 -1
|
@@ -0,0 +1,802 @@
|
|
|
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/google-audit-log/parameters.ts
|
|
46
|
+
var parameters = {
|
|
47
|
+
serviceAccountKeyJsonBase64: new ParameterDefinition({
|
|
48
|
+
slug: "service-account-key-json-base64",
|
|
49
|
+
name: "Google Cloud Service Account JSON",
|
|
50
|
+
description: "The service account JSON key. Domain-wide Delegation must be authorized in the Google Workspace admin console for the Admin SDK Reports API scopes (admin.reports.audit.readonly, admin.reports.usage.readonly). The Workspace admin user to impersonate is supplied per call as the `subject` argument.",
|
|
51
|
+
envVarBaseKey: "GOOGLE_AUDIT_LOG_SERVICE_ACCOUNT_JSON_BASE64",
|
|
52
|
+
type: "base64EncodedJson",
|
|
53
|
+
secret: true,
|
|
54
|
+
required: true
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ../connectors/src/connectors/google-audit-log/sdk/index.ts
|
|
59
|
+
var BASE_URL = "https://admin.googleapis.com/admin/reports/v1";
|
|
60
|
+
function createClient(params) {
|
|
61
|
+
const serviceAccountKeyJsonBase64 = params[parameters.serviceAccountKeyJsonBase64.slug];
|
|
62
|
+
if (!serviceAccountKeyJsonBase64) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`google-audit-log: missing required parameter: ${parameters.serviceAccountKeyJsonBase64.slug}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
let serviceAccountKey;
|
|
68
|
+
try {
|
|
69
|
+
const decoded = Buffer.from(
|
|
70
|
+
serviceAccountKeyJsonBase64,
|
|
71
|
+
"base64"
|
|
72
|
+
).toString("utf-8");
|
|
73
|
+
serviceAccountKey = JSON.parse(decoded);
|
|
74
|
+
} catch {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"google-audit-log: failed to decode service account key JSON from base64"
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (!serviceAccountKey.client_email || !serviceAccountKey.private_key) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
"google-audit-log: service account key JSON must contain client_email and private_key"
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
async requestWithDelegation(path2, { subject, scopes, init }) {
|
|
86
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
87
|
+
const auth = new GoogleAuth({
|
|
88
|
+
credentials: {
|
|
89
|
+
client_email: serviceAccountKey.client_email,
|
|
90
|
+
private_key: serviceAccountKey.private_key
|
|
91
|
+
},
|
|
92
|
+
scopes,
|
|
93
|
+
clientOptions: { subject }
|
|
94
|
+
});
|
|
95
|
+
const token = await auth.getAccessToken();
|
|
96
|
+
if (!token) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`google-audit-log: failed to obtain access token for ${subject}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
const url = `${BASE_URL}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
102
|
+
const headers = new Headers(init?.headers);
|
|
103
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
104
|
+
return fetch(url, { ...init, headers });
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ../connectors/src/connector-onboarding.ts
|
|
110
|
+
var ConnectorOnboarding = class {
|
|
111
|
+
/** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
|
|
112
|
+
connectionSetupInstructions;
|
|
113
|
+
/** Phase 2: Data overview instructions */
|
|
114
|
+
dataOverviewInstructions;
|
|
115
|
+
constructor(config) {
|
|
116
|
+
this.connectionSetupInstructions = config.connectionSetupInstructions;
|
|
117
|
+
this.dataOverviewInstructions = config.dataOverviewInstructions;
|
|
118
|
+
}
|
|
119
|
+
getConnectionSetupPrompt(language) {
|
|
120
|
+
return this.connectionSetupInstructions?.[language] ?? null;
|
|
121
|
+
}
|
|
122
|
+
getDataOverviewInstructions(language) {
|
|
123
|
+
return this.dataOverviewInstructions[language];
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// ../connectors/src/connector-tool.ts
|
|
128
|
+
var ConnectorTool = class {
|
|
129
|
+
name;
|
|
130
|
+
description;
|
|
131
|
+
inputSchema;
|
|
132
|
+
outputSchema;
|
|
133
|
+
_execute;
|
|
134
|
+
constructor(config) {
|
|
135
|
+
this.name = config.name;
|
|
136
|
+
this.description = config.description;
|
|
137
|
+
this.inputSchema = config.inputSchema;
|
|
138
|
+
this.outputSchema = config.outputSchema;
|
|
139
|
+
this._execute = config.execute;
|
|
140
|
+
}
|
|
141
|
+
createTool(connections, config) {
|
|
142
|
+
return {
|
|
143
|
+
description: this.description,
|
|
144
|
+
inputSchema: this.inputSchema,
|
|
145
|
+
outputSchema: this.outputSchema,
|
|
146
|
+
execute: (input) => this._execute(input, connections, config)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// ../connectors/src/connector-plugin.ts
|
|
152
|
+
var ConnectorPlugin = class _ConnectorPlugin {
|
|
153
|
+
slug;
|
|
154
|
+
authType;
|
|
155
|
+
name;
|
|
156
|
+
description;
|
|
157
|
+
iconUrl;
|
|
158
|
+
parameters;
|
|
159
|
+
releaseFlag;
|
|
160
|
+
proxyPolicy;
|
|
161
|
+
experimentalAttributes;
|
|
162
|
+
categories;
|
|
163
|
+
onboarding;
|
|
164
|
+
systemPrompt;
|
|
165
|
+
tools;
|
|
166
|
+
query;
|
|
167
|
+
checkConnection;
|
|
168
|
+
constructor(config) {
|
|
169
|
+
this.slug = config.slug;
|
|
170
|
+
this.authType = config.authType;
|
|
171
|
+
this.name = config.name;
|
|
172
|
+
this.description = config.description;
|
|
173
|
+
this.iconUrl = config.iconUrl;
|
|
174
|
+
this.parameters = config.parameters;
|
|
175
|
+
this.releaseFlag = config.releaseFlag;
|
|
176
|
+
this.proxyPolicy = config.proxyPolicy;
|
|
177
|
+
this.experimentalAttributes = config.experimentalAttributes;
|
|
178
|
+
this.categories = config.categories ?? [];
|
|
179
|
+
this.onboarding = config.onboarding;
|
|
180
|
+
this.systemPrompt = config.systemPrompt;
|
|
181
|
+
this.tools = config.tools;
|
|
182
|
+
this.query = config.query;
|
|
183
|
+
this.checkConnection = config.checkConnection;
|
|
184
|
+
}
|
|
185
|
+
get connectorKey() {
|
|
186
|
+
return _ConnectorPlugin.deriveKey(this.slug, this.authType);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Create tools for connections that belong to this connector.
|
|
190
|
+
* Filters connections by connectorKey internally.
|
|
191
|
+
* Returns tools keyed as `${connectorKey}_${toolName}`.
|
|
192
|
+
*/
|
|
193
|
+
createTools(connections, config, opts) {
|
|
194
|
+
const myConnections = connections.filter(
|
|
195
|
+
(c) => _ConnectorPlugin.deriveKey(c.connector.slug, c.connector.authType) === this.connectorKey
|
|
196
|
+
);
|
|
197
|
+
const result = {};
|
|
198
|
+
for (const t of Object.values(this.tools)) {
|
|
199
|
+
const tool = t.createTool(myConnections, config);
|
|
200
|
+
const originalToModelOutput = tool.toModelOutput;
|
|
201
|
+
result[`${this.connectorKey}_${t.name}`] = {
|
|
202
|
+
...tool,
|
|
203
|
+
toModelOutput: async (options) => {
|
|
204
|
+
if (!originalToModelOutput) {
|
|
205
|
+
return opts.truncateOutput(options.output);
|
|
206
|
+
}
|
|
207
|
+
const modelOutput = await originalToModelOutput(options);
|
|
208
|
+
if (modelOutput.type === "text" || modelOutput.type === "json") {
|
|
209
|
+
return opts.truncateOutput(modelOutput.value);
|
|
210
|
+
}
|
|
211
|
+
return modelOutput;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
static deriveKey(slug, authType) {
|
|
218
|
+
if (authType) return `${slug}-${authType}`;
|
|
219
|
+
const LEGACY_NULL_AUTH_TYPE_MAP = {
|
|
220
|
+
// user-password
|
|
221
|
+
"postgresql": "user-password",
|
|
222
|
+
"mysql": "user-password",
|
|
223
|
+
"clickhouse": "user-password",
|
|
224
|
+
"kintone": "user-password",
|
|
225
|
+
"squadbase-db": "user-password",
|
|
226
|
+
// service-account
|
|
227
|
+
"snowflake": "service-account",
|
|
228
|
+
"bigquery": "service-account",
|
|
229
|
+
"google-analytics": "service-account",
|
|
230
|
+
"google-calendar": "service-account",
|
|
231
|
+
"aws-athena": "service-account",
|
|
232
|
+
"redshift": "service-account",
|
|
233
|
+
// api-key
|
|
234
|
+
"databricks": "api-key",
|
|
235
|
+
"dbt": "api-key",
|
|
236
|
+
"airtable": "api-key",
|
|
237
|
+
"openai": "api-key",
|
|
238
|
+
"gemini": "api-key",
|
|
239
|
+
"anthropic": "api-key",
|
|
240
|
+
"wix-store": "api-key"
|
|
241
|
+
};
|
|
242
|
+
const fallbackAuthType = LEGACY_NULL_AUTH_TYPE_MAP[slug];
|
|
243
|
+
if (fallbackAuthType) return `${slug}-${fallbackAuthType}`;
|
|
244
|
+
return slug;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// ../connectors/src/auth-types.ts
|
|
249
|
+
var AUTH_TYPES = {
|
|
250
|
+
OAUTH: "oauth",
|
|
251
|
+
API_KEY: "api-key",
|
|
252
|
+
JWT: "jwt",
|
|
253
|
+
SERVICE_ACCOUNT: "service-account",
|
|
254
|
+
PAT: "pat",
|
|
255
|
+
USER_PASSWORD: "user-password"
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// ../connectors/src/connectors/google-audit-log/tools/request-with-delegation.ts
|
|
259
|
+
import { z } from "zod";
|
|
260
|
+
var BASE_URL2 = "https://admin.googleapis.com/admin/reports/v1";
|
|
261
|
+
var REQUEST_TIMEOUT_MS = 6e4;
|
|
262
|
+
function decodeServiceAccount(keyJsonBase64) {
|
|
263
|
+
const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
|
|
264
|
+
return JSON.parse(decoded);
|
|
265
|
+
}
|
|
266
|
+
var inputSchema = z.object({
|
|
267
|
+
toolUseIntent: z.string().optional().describe(
|
|
268
|
+
"Brief description of what you intend to accomplish with this tool call"
|
|
269
|
+
),
|
|
270
|
+
connectionId: z.string().describe(
|
|
271
|
+
"ID of the Google Audit Log (Admin SDK Reports) service account connection to use"
|
|
272
|
+
),
|
|
273
|
+
method: z.enum(["GET"]).describe("HTTP method. Reports API is read-only."),
|
|
274
|
+
path: z.string().describe(
|
|
275
|
+
"API path appended to https://admin.googleapis.com/admin/reports/v1. Examples: '/activity/users/all/applications/login', '/activity/users/{userKey}/applications/drive', '/usage/users/all/dates/2025-04-01', '/usage/dates/2025-04-01'."
|
|
276
|
+
),
|
|
277
|
+
subject: z.string().describe(
|
|
278
|
+
"Email of the Google Workspace admin user to impersonate via Domain-wide Delegation. The Reports API requires the impersonated user to have admin privileges in the Workspace."
|
|
279
|
+
),
|
|
280
|
+
scopes: z.array(z.string()).describe(
|
|
281
|
+
"OAuth scopes the token must include. This connector is read-only \u2014 pass one or both of: ['https://www.googleapis.com/auth/admin.reports.audit.readonly'] (audit activities), ['https://www.googleapis.com/auth/admin.reports.usage.readonly'] (usage reports). For maximum coverage you can pass both."
|
|
282
|
+
),
|
|
283
|
+
queryParams: z.record(z.string(), z.string()).optional().describe(
|
|
284
|
+
"Query parameters to append to the URL (e.g., { startTime: '2025-04-01T00:00:00Z', endTime: '2025-04-30T23:59:59Z', maxResults: '100', pageToken: '...', eventName: 'login_success', filters: 'doc_type==document', parameters: 'accounts:num_users' })"
|
|
285
|
+
)
|
|
286
|
+
});
|
|
287
|
+
var outputSchema = z.discriminatedUnion("success", [
|
|
288
|
+
z.object({
|
|
289
|
+
success: z.literal(true),
|
|
290
|
+
status: z.number(),
|
|
291
|
+
data: z.record(z.string(), z.unknown()),
|
|
292
|
+
serviceAccountEmail: z.string()
|
|
293
|
+
}),
|
|
294
|
+
z.object({
|
|
295
|
+
success: z.literal(false),
|
|
296
|
+
error: z.string(),
|
|
297
|
+
serviceAccountEmail: z.string().optional()
|
|
298
|
+
})
|
|
299
|
+
]);
|
|
300
|
+
var requestWithDelegationTool = new ConnectorTool({
|
|
301
|
+
name: "request_with_delegation",
|
|
302
|
+
description: "Call the Google Workspace Admin SDK Reports API on behalf of the specified Workspace admin via Domain-wide Delegation. Read-only operations only. Pass `subject` as the admin user email and `scopes` as one or both of ['https://www.googleapis.com/auth/admin.reports.audit.readonly', 'https://www.googleapis.com/auth/admin.reports.usage.readonly']. Paths are relative to https://admin.googleapis.com/admin/reports/v1 (e.g., '/activity/users/all/applications/login', '/usage/users/all/dates/2025-04-01'). Requires Domain-wide Delegation to be authorized for the service account in the Workspace admin console.",
|
|
303
|
+
inputSchema,
|
|
304
|
+
outputSchema,
|
|
305
|
+
async execute({ connectionId, method, path: path2, subject, scopes, queryParams }, connections) {
|
|
306
|
+
const connection2 = connections.find((c) => c.id === connectionId);
|
|
307
|
+
if (!connection2) {
|
|
308
|
+
return {
|
|
309
|
+
success: false,
|
|
310
|
+
error: `Connection ${connectionId} not found`
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
|
|
314
|
+
let serviceAccount;
|
|
315
|
+
try {
|
|
316
|
+
serviceAccount = decodeServiceAccount(keyJsonBase64);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
319
|
+
return {
|
|
320
|
+
success: false,
|
|
321
|
+
error: `Failed to decode service account key: ${msg}`
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const serviceAccountEmail = serviceAccount.client_email;
|
|
325
|
+
console.log(
|
|
326
|
+
`[connector-request] google-audit-log/${connection2.name}: ${method} ${path2} subject=${subject}`
|
|
327
|
+
);
|
|
328
|
+
try {
|
|
329
|
+
const { GoogleAuth } = await import("google-auth-library");
|
|
330
|
+
const auth = new GoogleAuth({
|
|
331
|
+
credentials: {
|
|
332
|
+
client_email: serviceAccount.client_email,
|
|
333
|
+
private_key: serviceAccount.private_key
|
|
334
|
+
},
|
|
335
|
+
scopes,
|
|
336
|
+
clientOptions: { subject }
|
|
337
|
+
});
|
|
338
|
+
const token = await auth.getAccessToken();
|
|
339
|
+
if (!token) {
|
|
340
|
+
return {
|
|
341
|
+
success: false,
|
|
342
|
+
error: "Failed to obtain access token",
|
|
343
|
+
serviceAccountEmail
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
let url = `${BASE_URL2}${path2.startsWith("/") ? "" : "/"}${path2}`;
|
|
347
|
+
if (queryParams) {
|
|
348
|
+
const searchParams = new URLSearchParams(queryParams);
|
|
349
|
+
url += `?${searchParams.toString()}`;
|
|
350
|
+
}
|
|
351
|
+
const controller = new AbortController();
|
|
352
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
353
|
+
try {
|
|
354
|
+
const response = await fetch(url, {
|
|
355
|
+
method,
|
|
356
|
+
headers: {
|
|
357
|
+
Authorization: `Bearer ${token}`,
|
|
358
|
+
"Content-Type": "application/json"
|
|
359
|
+
},
|
|
360
|
+
signal: controller.signal
|
|
361
|
+
});
|
|
362
|
+
const data = await response.json().catch(() => ({}));
|
|
363
|
+
if (!response.ok) {
|
|
364
|
+
const errorObj = data?.error;
|
|
365
|
+
const errorMessage = errorObj?.message ?? (typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`);
|
|
366
|
+
return {
|
|
367
|
+
success: false,
|
|
368
|
+
error: errorMessage,
|
|
369
|
+
serviceAccountEmail
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
success: true,
|
|
374
|
+
status: response.status,
|
|
375
|
+
data,
|
|
376
|
+
serviceAccountEmail
|
|
377
|
+
};
|
|
378
|
+
} finally {
|
|
379
|
+
clearTimeout(timeout);
|
|
380
|
+
}
|
|
381
|
+
} catch (err) {
|
|
382
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
383
|
+
return {
|
|
384
|
+
success: false,
|
|
385
|
+
error: msg,
|
|
386
|
+
serviceAccountEmail
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// ../connectors/src/connectors/google-audit-log/setup.ts
|
|
393
|
+
var requestWithDelegationToolName = `google-audit-log-service-account_${requestWithDelegationTool.name}`;
|
|
394
|
+
var READONLY_SCOPES = '["https://www.googleapis.com/auth/admin.reports.audit.readonly", "https://www.googleapis.com/auth/admin.reports.usage.readonly"]';
|
|
395
|
+
var googleAuditLogOnboarding = new ConnectorOnboarding({
|
|
396
|
+
connectionSetupInstructions: {
|
|
397
|
+
ja: `Google Audit Log\uFF08\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\uFF09\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u3092\u884C\u3044\u307E\u3059\u3002Reports API \u306F Workspace \u7BA1\u7406\u8005\u6A29\u9650\u3092\u6301\u3064\u30E6\u30FC\u30B6\u30FC\u306B\u306A\u308A\u3059\u307E\u3057\u3066\u547C\u3073\u51FA\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u30A2\u30AF\u30BB\u30B9\u306B\u4F7F\u3046\u7BA1\u7406\u8005\u30E6\u30FC\u30B6\u30FC\u3092\u30E6\u30FC\u30B6\u30FC\u304B\u3089\u805E\u304D\u3001Project Knowledge \u306B\u8A18\u9332\u3057\u307E\u3059\u3002
|
|
398
|
+
|
|
399
|
+
1. \`askUserQuestion\` \u3067\u5BFE\u8C61\u306E Workspace \u7BA1\u7406\u8005\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u805E\u304F:
|
|
400
|
+
- \`type\`: \`"freeText"\`
|
|
401
|
+
- \`question\`: \u300CAudit Log / Usage Report \u306E\u53D6\u5F97\u306B\u4F7F\u3046 Google Workspace \u7BA1\u7406\u8005\u30E6\u30FC\u30B6\u30FC\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u8907\u6570\u53EF\u3001\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09\u3002Reports API \u3078\u306E\u6A29\u9650\u3092\u6301\u3064\u30A2\u30AB\u30A6\u30F3\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u300D
|
|
402
|
+
- \`placeholder\`: \`"admin@example.com"\`
|
|
403
|
+
|
|
404
|
+
2. \u30E6\u30FC\u30B6\u30FC\u304B\u3089\u53D7\u3051\u53D6\u3063\u305F\u6587\u5B57\u5217\u304B\u3089\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u62BD\u51FA\u3059\u308B\u3002\u5404 \`<email>\` \u306B\u3064\u3044\u3066 \`${requestWithDelegationToolName}\` \u3092\u4EE5\u4E0B\u306E\u5F15\u6570\u3067\u547C\u3073\u3001Domain-wide Delegation \u7D4C\u7531\u3067\u30A2\u30AF\u30BB\u30B9\u53EF\u80FD\u304B\u3092\u78BA\u8A8D\u3059\u308B:
|
|
405
|
+
- \`method\`: \`"GET"\`
|
|
406
|
+
- \`path\`: \`"/activity/users/all/applications/login"\`
|
|
407
|
+
- \`subject\`: \`<email>\`
|
|
408
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
409
|
+
- \`queryParams\`: \`{ "maxResults": "1" }\`
|
|
410
|
+
|
|
411
|
+
3. \u5931\u6557\u3057\u305F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u304C\u3042\u308C\u3070\u3001\u30A8\u30E9\u30FC\u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`serviceAccountEmail\` \u30D5\u30A3\u30FC\u30EB\u30C9\u304B\u3089\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u53D6\u308A\u51FA\u3057\u3001\`askUserQuestion\` \u3067\u6B21\u306E\u9078\u629E\u80A2\u3092\u63D0\u793A\u3059\u308B\u3002\`question\` \u306B\u306F\u6B21\u306E\u6848\u5185\u6587\u3092\u542B\u3081\u308B: \u300C\u6B21\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3067\u306F Reports API \u306B\u30A2\u30AF\u30BB\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F: {\u5931\u6557\u30A2\u30C9\u30EC\u30B9\u4E00\u89A7}\u3002\u30B5\u30FC\u30D3\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8 \`<serviceAccountEmail>\` \u306E Domain-wide Delegation \u304C Workspace \u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u3067\u627F\u8A8D\u3055\u308C\u3066\u304A\u308A\u3001\u5BFE\u8C61\u30B9\u30B3\u30FC\u30D7\uFF08\`admin.reports.audit.readonly\`, \`admin.reports.usage.readonly\`\uFF09\u304C\u6709\u52B9\u5316\u3055\u308C\u3066\u3044\u308B\u304B\u3001\u307E\u305F\u6307\u5B9A\u3057\u305F\u30E6\u30FC\u30B6\u30FC\u304C Workspace \u306E\u7BA1\u7406\u8005\u30ED\u30FC\u30EB\u3092\u6301\u3063\u3066\u3044\u308B\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\uFF08[\u8A2D\u5B9A\u30AC\u30A4\u30C9](https://support.google.com/a/answer/162106)\uFF09\u300D\u3002
|
|
412
|
+
- \`options\`: \`[{ label: "\u30C9\u30E1\u30A4\u30F3\u5168\u4F53\u306E\u59D4\u4EFB\u3092\u627F\u8A8D\u3057\u305F\u306E\u3067\u30EA\u30C8\u30E9\u30A4", value: "retry" }, { label: "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u76F4\u3059", value: "restart" }]\`
|
|
413
|
+
- \u300C\u30EA\u30C8\u30E9\u30A4\u300D: \u76F4\u524D\u306E\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u30EA\u30B9\u30C8\u3067\u30B9\u30C6\u30C3\u30D7 2 \u3092\u518D\u5B9F\u884C
|
|
414
|
+
- \u300C\u5165\u529B\u3057\u76F4\u3059\u300D: \u30B9\u30C6\u30C3\u30D7 1 \u304B\u3089\u518D\u5B9F\u884C
|
|
415
|
+
|
|
416
|
+
4. \u5168\u30A2\u30C9\u30EC\u30B9\u304C\u6210\u529F\u3057\u305F\u3089 \`finalizeSetup\` \u3092\u547C\u3076\u3002\`projectKnowledge\` \u306E \`#### \u30B9\u30B3\u30FC\u30D7\` \u7BC0\u306B\u5404\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 1 \u884C\u305A\u3064\u5217\u6319\u3059\u308B:
|
|
417
|
+
- \`- subject: admin@example.com\`
|
|
418
|
+
|
|
419
|
+
#### \u5236\u7D04
|
|
420
|
+
- \u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u4E2D\u306B\u53D6\u5F97\u3057\u305F\u76E3\u67FB\u30ED\u30B0\u672C\u6587\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3053\u3068\u3002\u8A31\u53EF\u3055\u308C\u3066\u3044\u308B\u306E\u306F\u30B9\u30C6\u30C3\u30D7 2 \u306E\u30A2\u30AF\u30BB\u30B9\u78BA\u8A8D\u306E\u307F
|
|
421
|
+
- \u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057\u306E\u9593\u306F 1 \u6587\u3060\u3051\u66F8\u3044\u3066\u5373\u6B21\u306E\u30C4\u30FC\u30EB\u547C\u3073\u51FA\u3057`,
|
|
422
|
+
en: `Set up the Google Audit Log (Service Account) connection. The Reports API requires impersonating a user with Workspace admin privileges. Ask the user which admin user(s) to access, verify each via Domain-wide Delegation, and record them in Project Knowledge.
|
|
423
|
+
|
|
424
|
+
1. Call \`askUserQuestion\` to collect target admin emails:
|
|
425
|
+
- \`type\`: \`"freeText"\`
|
|
426
|
+
- \`question\`: "Enter the Google Workspace admin user email(s) to use for Audit Log / Usage Report access (comma-separated for multiple). The account must have the necessary admin privileges for the Reports API."
|
|
427
|
+
- \`placeholder\`: \`"admin@example.com"\`
|
|
428
|
+
|
|
429
|
+
2. Extract individual emails from the response. For each \`<email>\`, verify Domain-wide Delegation access by calling \`${requestWithDelegationToolName}\`:
|
|
430
|
+
- \`method\`: \`"GET"\`
|
|
431
|
+
- \`path\`: \`"/activity/users/all/applications/login"\`
|
|
432
|
+
- \`subject\`: \`<email>\`
|
|
433
|
+
- \`scopes\`: \`${READONLY_SCOPES}\`
|
|
434
|
+
- \`queryParams\`: \`{ "maxResults": "1" }\`
|
|
435
|
+
|
|
436
|
+
3. For any failed email, take \`serviceAccountEmail\` from the error response and call \`askUserQuestion\`. Include this guidance in \`question\`: "Could not access the Reports API for {failed emails}. Verify that Domain-wide Delegation for service account \`<serviceAccountEmail>\` is authorized in the Workspace admin console with the scopes \`admin.reports.audit.readonly\` and \`admin.reports.usage.readonly\`, and that the impersonated user has a Workspace admin role ([setup guide](https://support.google.com/a/answer/162106))".
|
|
437
|
+
- \`options\`: \`[{ label: "Authorized Domain-wide Delegation \u2014 retry", value: "retry" }, { label: "Re-enter the email addresses", value: "restart" }]\`
|
|
438
|
+
- On "retry" \u2192 re-run step 2 with the previously entered email list
|
|
439
|
+
- On "Re-enter" \u2192 re-run step 1
|
|
440
|
+
|
|
441
|
+
4. Once every email succeeds, call \`finalizeSetup\`. Under \`#### \u30B9\u30B3\u30FC\u30D7\` in \`projectKnowledge\`, list each email on its own line:
|
|
442
|
+
- \`- subject: admin@example.com\`
|
|
443
|
+
|
|
444
|
+
#### Constraints
|
|
445
|
+
- Do NOT read audit log contents during setup. Only the access verification call in step 2 is permitted
|
|
446
|
+
- Write at most 1 sentence between tool calls`
|
|
447
|
+
},
|
|
448
|
+
dataOverviewInstructions: {
|
|
449
|
+
en: `Pick ONE admin email from \`#### \u30B9\u30B3\u30FC\u30D7\` (a \`- subject: <email>\` line) and use it as \`subject\` for every call below. Pass \`scopes: ${READONLY_SCOPES}\` every time.
|
|
450
|
+
|
|
451
|
+
1. \`method=GET\`, \`path=/activity/users/all/applications/login\`, \`queryParams={ maxResults: "10" }\` to verify recent login activity events are available.
|
|
452
|
+
2. \`method=GET\`, \`path=/activity/users/all/applications/admin\`, \`queryParams={ maxResults: "10" }\` to inspect recent admin console events.
|
|
453
|
+
3. \`method=GET\`, \`path=/usage/dates/{YYYY-MM-DD}\` (use yesterday's date) to fetch a customer-level usage report sample.`,
|
|
454
|
+
ja: `\`#### \u30B9\u30B3\u30FC\u30D7\` \u306E \`- subject: <email>\` \u884C\u304B\u3089 1 \u3064\u306E\u7BA1\u7406\u8005\u3092\u9078\u3073\u3001\u4EE5\u4E0B\u306E\u30B9\u30C6\u30C3\u30D7\u3067 \`subject\` \u5F15\u6570\u3068\u3057\u3066\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002\`scopes\` \u306F\u6BCE\u56DE \`${READONLY_SCOPES}\` \u3092\u6E21\u3057\u307E\u3059\u3002
|
|
455
|
+
|
|
456
|
+
1. \`method=GET\`\u3001\`path=/activity/users/all/applications/login\`\u3001\`queryParams={ maxResults: "10" }\` \u3067\u76F4\u8FD1\u306E\u30ED\u30B0\u30A4\u30F3\u30A2\u30AF\u30C6\u30A3\u30D3\u30C6\u30A3\u304C\u53D6\u5F97\u3067\u304D\u308B\u3053\u3068\u3092\u78BA\u8A8D
|
|
457
|
+
2. \`method=GET\`\u3001\`path=/activity/users/all/applications/admin\`\u3001\`queryParams={ maxResults: "10" }\` \u3067\u76F4\u8FD1\u306E\u7BA1\u7406\u30B3\u30F3\u30BD\u30FC\u30EB\u64CD\u4F5C\u3092\u78BA\u8A8D
|
|
458
|
+
3. \`method=GET\`\u3001\`path=/usage/dates/{YYYY-MM-DD}\`\uFF08\u524D\u65E5\u306E\u65E5\u4ED8\u3092\u4F7F\u7528\uFF09\u3067\u30AB\u30B9\u30BF\u30DE\u30FC\u5358\u4F4D\u306E\u5229\u7528\u30EC\u30DD\u30FC\u30C8\u30B5\u30F3\u30D7\u30EB\u3092\u53D6\u5F97`
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// ../connectors/src/connectors/google-audit-log/index.ts
|
|
463
|
+
var tools = { request_with_delegation: requestWithDelegationTool };
|
|
464
|
+
var googleAuditLogConnector = new ConnectorPlugin({
|
|
465
|
+
slug: "google-audit-log",
|
|
466
|
+
authType: AUTH_TYPES.SERVICE_ACCOUNT,
|
|
467
|
+
name: "Google Audit Log",
|
|
468
|
+
description: "Connect to the Google Workspace Admin SDK Reports API for audit activities and usage reports using a service account with domain-wide delegation. Read-only.",
|
|
469
|
+
iconUrl: "https://www.gstatic.com/images/branding/product/2x/admin_2020q4_48dp.png",
|
|
470
|
+
parameters,
|
|
471
|
+
releaseFlag: { dev1: true, dev2: false, prod: false },
|
|
472
|
+
categories: ["observability"],
|
|
473
|
+
onboarding: googleAuditLogOnboarding,
|
|
474
|
+
systemPrompt: {
|
|
475
|
+
en: `### Tools
|
|
476
|
+
|
|
477
|
+
- \`google-audit-log-service-account_request_with_delegation\`: Call the Google Workspace Admin SDK Reports API on behalf of a Workspace admin via Domain-wide Delegation. Pass \`subject\` as the admin email; the token will be issued as that user. The set of admins this connection works with is recorded in the project knowledge under "#### \u30B9\u30B3\u30FC\u30D7" as \`- subject: <email>\` lines \u2014 read those and pick a subject before calling. Always pass \`scopes\`.
|
|
478
|
+
|
|
479
|
+
### OAuth Scopes (pass as \`scopes\` argument)
|
|
480
|
+
|
|
481
|
+
This connector is read-only. Pass one or both:
|
|
482
|
+
|
|
483
|
+
- \`https://www.googleapis.com/auth/admin.reports.audit.readonly\` \u2014 audit activity events (Activities API)
|
|
484
|
+
- \`https://www.googleapis.com/auth/admin.reports.usage.readonly\` \u2014 usage reports (Customer/User Usage API)
|
|
485
|
+
|
|
486
|
+
The Workspace admin must have authorized these scopes for the service account in the Domain-wide Delegation settings, otherwise token issuance will fail with \`unauthorized_client\`. The impersonated \`subject\` user must also have an admin role with permission to view the relevant reports.
|
|
487
|
+
|
|
488
|
+
Per-endpoint reference: https://developers.google.com/admin-sdk/reports/v1/reference
|
|
489
|
+
|
|
490
|
+
### Reports API Reference
|
|
491
|
+
|
|
492
|
+
#### Activities (audit logs)
|
|
493
|
+
- GET \`/activity/users/all/applications/{applicationName}\` \u2014 list activity events across all users for an application
|
|
494
|
+
- GET \`/activity/users/{userKey}/applications/{applicationName}\` \u2014 list activity events for a specific user (\`userKey\` is the user's email or immutable ID)
|
|
495
|
+
- GET \`/activity/users/all/applications/{applicationName}/watch\` \u2014 (not supported here, push notifications)
|
|
496
|
+
|
|
497
|
+
\`applicationName\` values include: \`access_transparency\`, \`admin\`, \`calendar\`, \`chat\`, \`chrome\`, \`context_aware_access\`, \`data_studio\`, \`drive\`, \`gcp\`, \`gplus\`, \`groups\`, \`groups_enterprise\`, \`jamboard\`, \`keep\`, \`login\`, \`meet\`, \`mobile\`, \`rules\`, \`saml\`, \`token\`, \`user_accounts\`, \`vault\`.
|
|
498
|
+
|
|
499
|
+
Common Activities query parameters (pass via \`queryParams\`):
|
|
500
|
+
- \`startTime\` / \`endTime\` \u2014 ISO-8601 timestamps (e.g., \`2025-04-01T00:00:00Z\`)
|
|
501
|
+
- \`eventName\` \u2014 filter by a specific event (e.g., \`login_success\`, \`login_failure\`, \`document_open\`)
|
|
502
|
+
- \`filters\` \u2014 comma-separated event-parameter filters (e.g., \`doc_type==document\`)
|
|
503
|
+
- \`actorIpAddress\` \u2014 filter by IP
|
|
504
|
+
- \`maxResults\` \u2014 page size (default 1000)
|
|
505
|
+
- \`pageToken\` \u2014 pagination token from previous response's \`nextPageToken\`
|
|
506
|
+
|
|
507
|
+
#### Usage reports
|
|
508
|
+
- GET \`/usage/dates/{date}\` \u2014 customer-level usage on a specific date (\`YYYY-MM-DD\`)
|
|
509
|
+
- GET \`/usage/users/all/dates/{date}\` \u2014 per-user usage on a specific date
|
|
510
|
+
- GET \`/usage/users/{userKey}/dates/{date}\` \u2014 usage for a single user on a specific date
|
|
511
|
+
|
|
512
|
+
Common Usage query parameters:
|
|
513
|
+
- \`parameters\` \u2014 comma-separated metric names (e.g., \`accounts:num_users,gmail:num_emails_received\`). See https://developers.google.com/admin-sdk/reports/v1/reference/usage-ref-appendix-a for the full list.
|
|
514
|
+
- \`filters\` \u2014 filter expression on the same metric namespace
|
|
515
|
+
- \`maxResults\` / \`pageToken\` \u2014 pagination
|
|
516
|
+
|
|
517
|
+
### Business Logic
|
|
518
|
+
|
|
519
|
+
The business logic type for this connector is "typescript". Write handler code using the connector SDK shown below. Do NOT access credentials directly from environment variables.
|
|
520
|
+
|
|
521
|
+
SDK methods (client created via \`connection(connectionId)\`):
|
|
522
|
+
|
|
523
|
+
- \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 call the Reports API as the impersonated Workspace admin. Pass the minimum scopes required.
|
|
524
|
+
|
|
525
|
+
The method returns a standard \`Response\`. Read the body with \`.json()\`. Same path conventions as the tool.
|
|
526
|
+
|
|
527
|
+
#### Example
|
|
528
|
+
|
|
529
|
+
\`\`\`ts
|
|
530
|
+
import type { Context } from "hono";
|
|
531
|
+
import { connection } from "@squadbase/vite-server/connectors/google-audit-log";
|
|
532
|
+
|
|
533
|
+
const reports = connection("<connectionId>");
|
|
534
|
+
|
|
535
|
+
const SUBJECT = "admin@example.com"; // pick from "#### \u30B9\u30B3\u30FC\u30D7" in project knowledge
|
|
536
|
+
const AUDIT = ["https://www.googleapis.com/auth/admin.reports.audit.readonly"];
|
|
537
|
+
|
|
538
|
+
export default async function handler(c: Context) {
|
|
539
|
+
const { startTime, endTime } = await c.req.json<{
|
|
540
|
+
startTime: string;
|
|
541
|
+
endTime: string;
|
|
542
|
+
}>();
|
|
543
|
+
|
|
544
|
+
const params = new URLSearchParams({
|
|
545
|
+
startTime,
|
|
546
|
+
endTime,
|
|
547
|
+
maxResults: "100",
|
|
548
|
+
});
|
|
549
|
+
const res = await reports.requestWithDelegation(
|
|
550
|
+
\`/activity/users/all/applications/login?\${params}\`,
|
|
551
|
+
{ subject: SUBJECT, scopes: AUDIT },
|
|
552
|
+
);
|
|
553
|
+
const data = (await res.json()) as { items?: { id: { time: string }; events?: { name: string }[]; actor?: { email?: string } }[] };
|
|
554
|
+
|
|
555
|
+
return c.json(
|
|
556
|
+
(data.items ?? []).map((item) => ({
|
|
557
|
+
time: item.id.time,
|
|
558
|
+
actor: item.actor?.email,
|
|
559
|
+
event: item.events?.[0]?.name,
|
|
560
|
+
})),
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
\`\`\``,
|
|
564
|
+
ja: `### \u30C4\u30FC\u30EB
|
|
565
|
+
|
|
566
|
+
- \`google-audit-log-service-account_request_with_delegation\`: Domain-wide Delegation \u7D4C\u7531\u3067 Workspace \u7BA1\u7406\u8005\u306B\u306A\u308A\u3059\u307E\u3057\u3066 Google Workspace Admin SDK Reports API \u3092\u547C\u3073\u51FA\u3057\u307E\u3059\u3002\u4EE3\u7406\u5BFE\u8C61\u306E\u7BA1\u7406\u8005\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092 \`subject\` \u3068\u3057\u3066\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30C8\u30FC\u30AF\u30F3\u306F\u305D\u306E\u30E6\u30FC\u30B6\u30FC\u3068\u3057\u3066\u767A\u884C\u3055\u308C\u307E\u3059\u3002\u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u304C\u5BFE\u8C61\u3068\u3059\u308B\u7BA1\u7406\u8005\u306F Project Knowledge \u306E "#### \u30B9\u30B3\u30FC\u30D7" \u306B \`- subject: <email>\` \u5F62\u5F0F\u3067\u8A18\u9332\u3055\u308C\u3066\u3044\u308B\u305F\u3081\u3001\u547C\u3073\u51FA\u3057\u524D\u306B\u305D\u3053\u3092\u8AAD\u3093\u3067 subject \u3092\u6C7A\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\`scopes\` \u3082\u6BCE\u56DE\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
567
|
+
|
|
568
|
+
### OAuth \u30B9\u30B3\u30FC\u30D7 (\`scopes\` \u5F15\u6570\u3067\u6E21\u3059)
|
|
569
|
+
|
|
570
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u30FC\u306F\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u3059\u3002\u6B21\u306E\u3044\u305A\u308C\u304B\u3001\u307E\u305F\u306F\u4E21\u65B9\u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044:
|
|
571
|
+
|
|
572
|
+
- \`https://www.googleapis.com/auth/admin.reports.audit.readonly\` \u2014 \u76E3\u67FB\u30A2\u30AF\u30C6\u30A3\u30D3\u30C6\u30A3\u30A4\u30D9\u30F3\u30C8 (Activities API)
|
|
573
|
+
- \`https://www.googleapis.com/auth/admin.reports.usage.readonly\` \u2014 \u5229\u7528\u30EC\u30DD\u30FC\u30C8 (Customer/User Usage API)
|
|
574
|
+
|
|
575
|
+
\u8981\u6C42\u3059\u308B scope \u306F Workspace \u7BA1\u7406\u8005\u304C Domain-wide Delegation \u8A2D\u5B9A\u3067\u5F53\u8A72 Service Account \u306B\u5BFE\u3057\u3066\u627F\u8A8D\u3057\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002\u627F\u8A8D\u3055\u308C\u3066\u3044\u306A\u3044\u5834\u5408\u30C8\u30FC\u30AF\u30F3\u767A\u884C\u304C \`unauthorized_client\` \u3067\u5931\u6557\u3057\u307E\u3059\u3002\u307E\u305F\u4EE3\u7406\u5BFE\u8C61\u306E \`subject\` \u30E6\u30FC\u30B6\u30FC\u304C\u8A72\u5F53\u30EC\u30DD\u30FC\u30C8\u3092\u95B2\u89A7\u3067\u304D\u308B\u7BA1\u7406\u8005\u30ED\u30FC\u30EB\u3092\u6301\u3063\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002
|
|
576
|
+
|
|
577
|
+
\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u5225\u306E\u6B63\u78BA\u306A\u30EA\u30D5\u30A1\u30EC\u30F3\u30B9: https://developers.google.com/admin-sdk/reports/v1/reference
|
|
578
|
+
|
|
579
|
+
### Reports API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
|
|
580
|
+
|
|
581
|
+
#### Activities\uFF08\u76E3\u67FB\u30ED\u30B0\uFF09
|
|
582
|
+
- GET \`/activity/users/all/applications/{applicationName}\` \u2014 \u6307\u5B9A\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u306B\u3064\u3044\u3066\u5168\u30E6\u30FC\u30B6\u30FC\u306E\u30A2\u30AF\u30C6\u30A3\u30D3\u30C6\u30A3\u30A4\u30D9\u30F3\u30C8\u3092\u4E00\u89A7
|
|
583
|
+
- GET \`/activity/users/{userKey}/applications/{applicationName}\` \u2014 \u6307\u5B9A\u30E6\u30FC\u30B6\u30FC\uFF08\`userKey\` \u306F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u307E\u305F\u306F\u4E0D\u5909ID\uFF09\u306E\u30A2\u30AF\u30C6\u30A3\u30D3\u30C6\u30A3
|
|
584
|
+
|
|
585
|
+
\`applicationName\` \u306E\u5024: \`access_transparency\`, \`admin\`, \`calendar\`, \`chat\`, \`chrome\`, \`context_aware_access\`, \`data_studio\`, \`drive\`, \`gcp\`, \`gplus\`, \`groups\`, \`groups_enterprise\`, \`jamboard\`, \`keep\`, \`login\`, \`meet\`, \`mobile\`, \`rules\`, \`saml\`, \`token\`, \`user_accounts\`, \`vault\`\u3002
|
|
586
|
+
|
|
587
|
+
\u4E3B\u306A\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\uFF08\`queryParams\` \u306B\u6E21\u3059\uFF09:
|
|
588
|
+
- \`startTime\` / \`endTime\` \u2014 ISO-8601 \u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7\uFF08\u4F8B: \`2025-04-01T00:00:00Z\`\uFF09
|
|
589
|
+
- \`eventName\` \u2014 \u7279\u5B9A\u306E\u30A4\u30D9\u30F3\u30C8\u3067\u30D5\u30A3\u30EB\u30BF\uFF08\u4F8B: \`login_success\`, \`login_failure\`, \`document_open\`\uFF09
|
|
590
|
+
- \`filters\` \u2014 \u30A4\u30D9\u30F3\u30C8\u30D1\u30E9\u30E1\u30FC\u30BF\u3067\u306E\u30D5\u30A3\u30EB\u30BF\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\u3001\u4F8B: \`doc_type==document\`\uFF09
|
|
591
|
+
- \`actorIpAddress\` \u2014 IP\u30A2\u30C9\u30EC\u30B9\u3067\u30D5\u30A3\u30EB\u30BF
|
|
592
|
+
- \`maxResults\` \u2014 \u30DA\u30FC\u30B8\u30B5\u30A4\u30BA\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8 1000\uFF09
|
|
593
|
+
- \`pageToken\` \u2014 \u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`nextPageToken\` \u3092\u6E21\u3057\u3066\u30DA\u30FC\u30B8\u30F3\u30B0
|
|
594
|
+
|
|
595
|
+
#### Usage\uFF08\u5229\u7528\u30EC\u30DD\u30FC\u30C8\uFF09
|
|
596
|
+
- GET \`/usage/dates/{date}\` \u2014 \u6307\u5B9A\u65E5\uFF08\`YYYY-MM-DD\`\uFF09\u306E\u30AB\u30B9\u30BF\u30DE\u30FC\u5358\u4F4D\u306E\u5229\u7528\u30EC\u30DD\u30FC\u30C8
|
|
597
|
+
- GET \`/usage/users/all/dates/{date}\` \u2014 \u6307\u5B9A\u65E5\u306E\u5168\u30E6\u30FC\u30B6\u30FC\u5229\u7528\u30EC\u30DD\u30FC\u30C8
|
|
598
|
+
- GET \`/usage/users/{userKey}/dates/{date}\` \u2014 \u6307\u5B9A\u65E5\u306E\u7279\u5B9A\u30E6\u30FC\u30B6\u30FC\u306E\u5229\u7528\u30EC\u30DD\u30FC\u30C8
|
|
599
|
+
|
|
600
|
+
\u4E3B\u306A\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF:
|
|
601
|
+
- \`parameters\` \u2014 \u53D6\u5F97\u3059\u308B\u30E1\u30C8\u30EA\u30AF\u30B9\u540D\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\u3001\u4F8B: \`accounts:num_users,gmail:num_emails_received\`\uFF09\u3002\u4E00\u89A7: https://developers.google.com/admin-sdk/reports/v1/reference/usage-ref-appendix-a
|
|
602
|
+
- \`filters\` \u2014 \u30E1\u30C8\u30EA\u30AF\u30B9\u306B\u5BFE\u3059\u308B\u30D5\u30A3\u30EB\u30BF\u5F0F
|
|
603
|
+
- \`maxResults\` / \`pageToken\` \u2014 \u30DA\u30FC\u30B8\u30F3\u30B0
|
|
604
|
+
|
|
605
|
+
### Business Logic
|
|
606
|
+
|
|
607
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u4EE5\u4E0B\u306B\u793A\u3059\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u30CF\u30F3\u30C9\u30E9\u30B3\u30FC\u30C9\u3092\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u76F4\u63A5\u8A8D\u8A3C\u60C5\u5831\u306B\u30A2\u30AF\u30BB\u30B9\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
608
|
+
|
|
609
|
+
SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
|
|
610
|
+
|
|
611
|
+
- \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 Domain-wide Delegation \u3067\u6307\u5B9A Workspace \u7BA1\u7406\u8005\u3068\u3057\u3066 Reports API \u3092\u547C\u3076\u3002\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u306B\u5FC5\u8981\u306A\u6700\u5C0F scope \u3092\u6E21\u3059\u3002
|
|
612
|
+
|
|
613
|
+
\u30E1\u30BD\u30C3\u30C9\u306F\u6A19\u6E96\u306E \`Response\` \u3092\u8FD4\u3057\u307E\u3059\u3002\`response.json()\` \u3067\u30DC\u30C7\u30A3\u3092\u53D6\u5F97\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D1\u30B9\u306E\u66F8\u304D\u65B9\u306F\u30C4\u30FC\u30EB\u3068\u540C\u3058\u3002
|
|
614
|
+
|
|
615
|
+
#### Example
|
|
616
|
+
|
|
617
|
+
\`\`\`ts
|
|
618
|
+
import type { Context } from "hono";
|
|
619
|
+
import { connection } from "@squadbase/vite-server/connectors/google-audit-log";
|
|
620
|
+
|
|
621
|
+
const reports = connection("<connectionId>");
|
|
622
|
+
|
|
623
|
+
const SUBJECT = "admin@example.com"; // Project Knowledge \u306E "#### \u30B9\u30B3\u30FC\u30D7" \u304B\u3089\u9078\u3076
|
|
624
|
+
const AUDIT = ["https://www.googleapis.com/auth/admin.reports.audit.readonly"];
|
|
625
|
+
|
|
626
|
+
export default async function handler(c: Context) {
|
|
627
|
+
const { startTime, endTime } = await c.req.json<{
|
|
628
|
+
startTime: string;
|
|
629
|
+
endTime: string;
|
|
630
|
+
}>();
|
|
631
|
+
|
|
632
|
+
const params = new URLSearchParams({
|
|
633
|
+
startTime,
|
|
634
|
+
endTime,
|
|
635
|
+
maxResults: "100",
|
|
636
|
+
});
|
|
637
|
+
const res = await reports.requestWithDelegation(
|
|
638
|
+
\`/activity/users/all/applications/login?\${params}\`,
|
|
639
|
+
{ subject: SUBJECT, scopes: AUDIT },
|
|
640
|
+
);
|
|
641
|
+
const data = (await res.json()) as { items?: { id: { time: string }; events?: { name: string }[]; actor?: { email?: string } }[] };
|
|
642
|
+
|
|
643
|
+
return c.json(
|
|
644
|
+
(data.items ?? []).map((item) => ({
|
|
645
|
+
time: item.id.time,
|
|
646
|
+
actor: item.actor?.email,
|
|
647
|
+
event: item.events?.[0]?.name,
|
|
648
|
+
})),
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
\`\`\``
|
|
652
|
+
},
|
|
653
|
+
tools
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
// src/connectors/create-connector-sdk.ts
|
|
657
|
+
import { readFileSync } from "fs";
|
|
658
|
+
import path from "path";
|
|
659
|
+
|
|
660
|
+
// src/connector-client/env.ts
|
|
661
|
+
function resolveEnvVar(entry, key, connectionId) {
|
|
662
|
+
const envVarName = entry.envVars[key];
|
|
663
|
+
if (!envVarName) {
|
|
664
|
+
throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
|
|
665
|
+
}
|
|
666
|
+
const value = process.env[envVarName];
|
|
667
|
+
if (!value) {
|
|
668
|
+
throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
|
|
669
|
+
}
|
|
670
|
+
return value;
|
|
671
|
+
}
|
|
672
|
+
function resolveEnvVarOptional(entry, key) {
|
|
673
|
+
const envVarName = entry.envVars[key];
|
|
674
|
+
if (!envVarName) return void 0;
|
|
675
|
+
return process.env[envVarName] || void 0;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// src/connector-client/proxy-fetch.ts
|
|
679
|
+
import { getContext } from "hono/context-storage";
|
|
680
|
+
import { getCookie } from "hono/cookie";
|
|
681
|
+
var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
|
|
682
|
+
function normalizeHeaders(input) {
|
|
683
|
+
const out = {};
|
|
684
|
+
if (!input) return out;
|
|
685
|
+
new Headers(input).forEach((value, key) => {
|
|
686
|
+
out[key] = value;
|
|
687
|
+
});
|
|
688
|
+
return out;
|
|
689
|
+
}
|
|
690
|
+
function createSandboxProxyFetch(connectionId) {
|
|
691
|
+
return async (input, init) => {
|
|
692
|
+
const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
|
|
693
|
+
const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
|
|
694
|
+
if (!token || !sandboxId) {
|
|
695
|
+
throw new Error(
|
|
696
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
700
|
+
const originalMethod = init?.method ?? "GET";
|
|
701
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
702
|
+
const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
|
|
703
|
+
const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
704
|
+
return fetch(proxyUrl, {
|
|
705
|
+
method: "POST",
|
|
706
|
+
headers: {
|
|
707
|
+
"Content-Type": "application/json",
|
|
708
|
+
Authorization: `Bearer ${token}`
|
|
709
|
+
},
|
|
710
|
+
body: JSON.stringify({
|
|
711
|
+
url: originalUrl,
|
|
712
|
+
method: originalMethod,
|
|
713
|
+
headers: normalizeHeaders(init?.headers),
|
|
714
|
+
body: originalBody
|
|
715
|
+
})
|
|
716
|
+
});
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
function createDeployedAppProxyFetch(connectionId) {
|
|
720
|
+
const projectId = process.env["SQUADBASE_PROJECT_ID"];
|
|
721
|
+
if (!projectId) {
|
|
722
|
+
throw new Error(
|
|
723
|
+
"Connection proxy is not configured. Please check your deployment settings."
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
|
|
727
|
+
const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
|
|
728
|
+
return async (input, init) => {
|
|
729
|
+
const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
730
|
+
const originalMethod = init?.method ?? "GET";
|
|
731
|
+
const originalBody = init?.body ? JSON.parse(init.body) : void 0;
|
|
732
|
+
const c = getContext();
|
|
733
|
+
const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
|
|
734
|
+
if (!appSession) {
|
|
735
|
+
throw new Error(
|
|
736
|
+
"No authentication method available for connection proxy."
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
return fetch(proxyUrl, {
|
|
740
|
+
method: "POST",
|
|
741
|
+
headers: {
|
|
742
|
+
"Content-Type": "application/json",
|
|
743
|
+
Authorization: `Bearer ${appSession}`
|
|
744
|
+
},
|
|
745
|
+
body: JSON.stringify({
|
|
746
|
+
url: originalUrl,
|
|
747
|
+
method: originalMethod,
|
|
748
|
+
headers: normalizeHeaders(init?.headers),
|
|
749
|
+
body: originalBody
|
|
750
|
+
})
|
|
751
|
+
});
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
function createProxyFetch(connectionId) {
|
|
755
|
+
if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
|
|
756
|
+
return createSandboxProxyFetch(connectionId);
|
|
757
|
+
}
|
|
758
|
+
return createDeployedAppProxyFetch(connectionId);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/connectors/create-connector-sdk.ts
|
|
762
|
+
function loadConnectionsSync() {
|
|
763
|
+
const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
|
|
764
|
+
try {
|
|
765
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
766
|
+
return JSON.parse(raw);
|
|
767
|
+
} catch {
|
|
768
|
+
return {};
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
function createConnectorSdk(plugin, createClient2) {
|
|
772
|
+
return (connectionId) => {
|
|
773
|
+
const connections = loadConnectionsSync();
|
|
774
|
+
const entry = connections[connectionId];
|
|
775
|
+
if (!entry) {
|
|
776
|
+
throw new Error(
|
|
777
|
+
`Connection "${connectionId}" not found in .squadbase/connections.json`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
if (entry.connector.slug !== plugin.slug) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
`Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
const params = {};
|
|
786
|
+
for (const param of Object.values(plugin.parameters)) {
|
|
787
|
+
if (param.required) {
|
|
788
|
+
params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
|
|
789
|
+
} else {
|
|
790
|
+
const val = resolveEnvVarOptional(entry, param.slug);
|
|
791
|
+
if (val !== void 0) params[param.slug] = val;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return createClient2(params, createProxyFetch(connectionId));
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/connectors/entries/google-audit-log.ts
|
|
799
|
+
var connection = createConnectorSdk(googleAuditLogConnector, createClient);
|
|
800
|
+
export {
|
|
801
|
+
connection
|
|
802
|
+
};
|