@squadbase/vite-server 0.1.8 → 0.1.9-dev.3841401

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/cli/index.js +73422 -59588
  2. package/dist/connectors/airtable-oauth.js +3 -0
  3. package/dist/connectors/airtable.js +3 -0
  4. package/dist/connectors/amplitude.js +3 -0
  5. package/dist/connectors/anthropic.js +3 -0
  6. package/dist/connectors/asana.js +18 -2
  7. package/dist/connectors/attio.js +3 -0
  8. package/dist/connectors/aws-billing.d.ts +5 -0
  9. package/dist/connectors/aws-billing.js +29843 -0
  10. package/dist/connectors/azure-sql.d.ts +5 -0
  11. package/dist/connectors/azure-sql.js +668 -0
  12. package/dist/connectors/backlog-api-key.js +3 -0
  13. package/dist/connectors/clickup.d.ts +5 -0
  14. package/dist/connectors/clickup.js +850 -0
  15. package/dist/connectors/customerio.js +3 -0
  16. package/dist/connectors/dbt.js +3 -0
  17. package/dist/connectors/freshdesk.d.ts +5 -0
  18. package/dist/connectors/freshdesk.js +842 -0
  19. package/dist/connectors/freshsales.d.ts +5 -0
  20. package/dist/connectors/freshsales.js +867 -0
  21. package/dist/connectors/freshservice.d.ts +5 -0
  22. package/dist/connectors/freshservice.js +813 -0
  23. package/dist/connectors/gamma.js +3 -0
  24. package/dist/connectors/gemini.js +3 -0
  25. package/dist/connectors/github.d.ts +5 -0
  26. package/dist/connectors/github.js +963 -0
  27. package/dist/connectors/gmail-oauth.js +18 -2
  28. package/dist/connectors/gmail.js +34 -16
  29. package/dist/connectors/google-ads.js +3 -0
  30. package/dist/connectors/google-analytics-oauth.js +3 -0
  31. package/dist/connectors/google-analytics.js +3 -0
  32. package/dist/connectors/google-audit-log.d.ts +5 -0
  33. package/dist/connectors/google-audit-log.js +813 -0
  34. package/dist/connectors/google-calendar-oauth.js +21 -2
  35. package/dist/connectors/google-calendar.js +140 -73
  36. package/dist/connectors/google-docs.js +21 -2
  37. package/dist/connectors/google-drive.js +18 -2
  38. package/dist/connectors/google-search-console-oauth.d.ts +5 -0
  39. package/dist/connectors/google-search-console-oauth.js +954 -0
  40. package/dist/connectors/google-sheets.js +21 -2
  41. package/dist/connectors/google-slides.js +21 -2
  42. package/dist/connectors/grafana.js +3 -0
  43. package/dist/connectors/hubspot-oauth.js +3 -0
  44. package/dist/connectors/hubspot.js +3 -0
  45. package/dist/connectors/influxdb.js +3 -0
  46. package/dist/connectors/intercom-oauth.js +3 -0
  47. package/dist/connectors/intercom.js +3 -0
  48. package/dist/connectors/jdbc.d.ts +5 -0
  49. package/dist/connectors/jdbc.js +21509 -0
  50. package/dist/connectors/jira-api-key.js +3 -0
  51. package/dist/connectors/kintone-api-token.js +3 -0
  52. package/dist/connectors/kintone.js +3 -0
  53. package/dist/connectors/linear.js +3 -0
  54. package/dist/connectors/linkedin-ads.js +3 -0
  55. package/dist/connectors/mailchimp-oauth.js +3 -0
  56. package/dist/connectors/mailchimp.js +3 -0
  57. package/dist/connectors/meta-ads-oauth.js +3 -0
  58. package/dist/connectors/meta-ads.js +3 -0
  59. package/dist/connectors/mixpanel.js +3 -0
  60. package/dist/connectors/monday.d.ts +5 -0
  61. package/dist/connectors/monday.js +853 -0
  62. package/dist/connectors/notion-oauth.js +3 -0
  63. package/dist/connectors/notion.js +3 -0
  64. package/dist/connectors/openai.js +3 -0
  65. package/dist/connectors/oracle.d.ts +5 -0
  66. package/dist/connectors/oracle.js +676 -0
  67. package/dist/connectors/salesforce.js +3 -0
  68. package/dist/connectors/semrush.d.ts +5 -0
  69. package/dist/connectors/semrush.js +812 -0
  70. package/dist/connectors/sentry.js +3 -0
  71. package/dist/connectors/shopify-oauth.js +3 -0
  72. package/dist/connectors/shopify.js +3 -0
  73. package/dist/connectors/sqlserver.d.ts +5 -0
  74. package/dist/connectors/sqlserver.js +667 -0
  75. package/dist/connectors/stripe-api-key.js +3 -0
  76. package/dist/connectors/stripe-oauth.js +3 -0
  77. package/dist/connectors/supabase.d.ts +5 -0
  78. package/dist/connectors/supabase.js +582 -0
  79. package/dist/connectors/tiktok-ads.js +18 -2
  80. package/dist/connectors/wix-store.js +3 -0
  81. package/dist/connectors/zendesk-oauth.js +3 -0
  82. package/dist/connectors/zendesk.js +3 -0
  83. package/dist/index.js +70184 -56350
  84. package/dist/main.js +70178 -56344
  85. package/dist/vite-plugin.js +71935 -58101
  86. package/package.json +64 -2
@@ -0,0 +1,813 @@
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/lib/normalize-path.ts
259
+ function normalizeRequestPath(path2, basePathSegment) {
260
+ let p = path2.trim();
261
+ if (!p.startsWith("/")) p = "/" + p;
262
+ if (p === basePathSegment || p.startsWith(basePathSegment + "/")) {
263
+ p = p.slice(basePathSegment.length) || "/";
264
+ }
265
+ return p;
266
+ }
267
+
268
+ // ../connectors/src/connectors/google-audit-log/tools/request-with-delegation.ts
269
+ import { z } from "zod";
270
+ var BASE_HOST = "https://admin.googleapis.com";
271
+ var BASE_PATH_SEGMENT = "/admin/reports/v1";
272
+ var BASE_URL2 = `${BASE_HOST}${BASE_PATH_SEGMENT}`;
273
+ var REQUEST_TIMEOUT_MS = 6e4;
274
+ function decodeServiceAccount(keyJsonBase64) {
275
+ const decoded = Buffer.from(keyJsonBase64, "base64").toString("utf-8");
276
+ return JSON.parse(decoded);
277
+ }
278
+ var inputSchema = z.object({
279
+ toolUseIntent: z.string().optional().describe(
280
+ "Brief description of what you intend to accomplish with this tool call"
281
+ ),
282
+ connectionId: z.string().describe(
283
+ "ID of the Google Audit Log (Admin SDK Reports) service account connection to use"
284
+ ),
285
+ method: z.enum(["GET"]).describe("HTTP method. Reports API is read-only."),
286
+ path: z.string().describe(
287
+ "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'."
288
+ ),
289
+ subject: z.string().describe(
290
+ "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."
291
+ ),
292
+ scopes: z.array(z.string()).describe(
293
+ "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."
294
+ ),
295
+ queryParams: z.record(z.string(), z.string()).optional().describe(
296
+ "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' })"
297
+ )
298
+ });
299
+ var outputSchema = z.discriminatedUnion("success", [
300
+ z.object({
301
+ success: z.literal(true),
302
+ status: z.number(),
303
+ data: z.record(z.string(), z.unknown()),
304
+ serviceAccountEmail: z.string()
305
+ }),
306
+ z.object({
307
+ success: z.literal(false),
308
+ error: z.string(),
309
+ serviceAccountEmail: z.string().optional()
310
+ })
311
+ ]);
312
+ var requestWithDelegationTool = new ConnectorTool({
313
+ name: "request_with_delegation",
314
+ 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.",
315
+ inputSchema,
316
+ outputSchema,
317
+ async execute({ connectionId, method, path: path2, subject, scopes, queryParams }, connections) {
318
+ const connection2 = connections.find((c) => c.id === connectionId);
319
+ if (!connection2) {
320
+ return {
321
+ success: false,
322
+ error: `Connection ${connectionId} not found`
323
+ };
324
+ }
325
+ const keyJsonBase64 = parameters.serviceAccountKeyJsonBase64.getValue(connection2);
326
+ let serviceAccount;
327
+ try {
328
+ serviceAccount = decodeServiceAccount(keyJsonBase64);
329
+ } catch (err) {
330
+ const msg = err instanceof Error ? err.message : String(err);
331
+ return {
332
+ success: false,
333
+ error: `Failed to decode service account key: ${msg}`
334
+ };
335
+ }
336
+ const serviceAccountEmail = serviceAccount.client_email;
337
+ console.log(
338
+ `[connector-request] google-audit-log/${connection2.name}: ${method} ${path2} subject=${subject}`
339
+ );
340
+ try {
341
+ const { GoogleAuth } = await import("google-auth-library");
342
+ const auth = new GoogleAuth({
343
+ credentials: {
344
+ client_email: serviceAccount.client_email,
345
+ private_key: serviceAccount.private_key
346
+ },
347
+ scopes,
348
+ clientOptions: { subject }
349
+ });
350
+ const token = await auth.getAccessToken();
351
+ if (!token) {
352
+ return {
353
+ success: false,
354
+ error: "Failed to obtain access token",
355
+ serviceAccountEmail
356
+ };
357
+ }
358
+ const normalizedPath = normalizeRequestPath(path2, BASE_PATH_SEGMENT);
359
+ let url = `${BASE_URL2}${normalizedPath}`;
360
+ if (queryParams) {
361
+ const searchParams = new URLSearchParams(queryParams);
362
+ url += `?${searchParams.toString()}`;
363
+ }
364
+ const controller = new AbortController();
365
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
366
+ try {
367
+ const response = await fetch(url, {
368
+ method,
369
+ headers: {
370
+ Authorization: `Bearer ${token}`,
371
+ "Content-Type": "application/json"
372
+ },
373
+ signal: controller.signal
374
+ });
375
+ const data = await response.json().catch(() => ({}));
376
+ if (!response.ok) {
377
+ const errorObj = data?.error;
378
+ const errorMessage = errorObj?.message ?? (typeof data?.message === "string" ? data.message : `HTTP ${response.status} ${response.statusText}`);
379
+ return {
380
+ success: false,
381
+ error: errorMessage,
382
+ serviceAccountEmail
383
+ };
384
+ }
385
+ return {
386
+ success: true,
387
+ status: response.status,
388
+ data,
389
+ serviceAccountEmail
390
+ };
391
+ } finally {
392
+ clearTimeout(timeout);
393
+ }
394
+ } catch (err) {
395
+ const msg = err instanceof Error ? err.message : String(err);
396
+ return {
397
+ success: false,
398
+ error: msg,
399
+ serviceAccountEmail
400
+ };
401
+ }
402
+ }
403
+ });
404
+
405
+ // ../connectors/src/connectors/google-audit-log/setup.ts
406
+ var requestWithDelegationToolName = `google-audit-log-service-account_${requestWithDelegationTool.name}`;
407
+ var READONLY_SCOPES = '["https://www.googleapis.com/auth/admin.reports.audit.readonly", "https://www.googleapis.com/auth/admin.reports.usage.readonly"]';
408
+ var googleAuditLogOnboarding = new ConnectorOnboarding({
409
+ connectionSetupInstructions: {
410
+ 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
411
+
412
+ 1. \`askUserQuestion\` \u3067\u5BFE\u8C61\u306E Workspace \u7BA1\u7406\u8005\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u805E\u304F:
413
+ - \`type\`: \`"freeText"\`
414
+ - \`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
415
+ - \`placeholder\`: \`"admin@example.com"\`
416
+
417
+ 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:
418
+ - \`method\`: \`"GET"\`
419
+ - \`path\`: \`"/activity/users/all/applications/login"\`
420
+ - \`subject\`: \`<email>\`
421
+ - \`scopes\`: \`${READONLY_SCOPES}\`
422
+ - \`queryParams\`: \`{ "maxResults": "1" }\`
423
+
424
+ 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
425
+ - \`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" }]\`
426
+ - \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
427
+ - \u300C\u5165\u529B\u3057\u76F4\u3059\u300D: \u30B9\u30C6\u30C3\u30D7 1 \u304B\u3089\u518D\u5B9F\u884C
428
+
429
+ 4. \u5168\u30A2\u30C9\u30EC\u30B9\u304C\u6210\u529F\u3057\u305F\u3089 \`finalizeSetup\` \u3092\u547C\u3076\u3002\u691C\u8A3C\u6E08\u307F\u306E\u7BA1\u7406\u8005\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u3053\u306E\u30B3\u30CD\u30AF\u30B7\u30E7\u30F3\u306E\u30B9\u30B3\u30FC\u30D7\u60C5\u5831\u3068\u3057\u3066\u8A18\u9332\u3059\u308B\u3002
430
+
431
+ #### \u5236\u7D04
432
+ - \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
433
+ - \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`,
434
+ 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.
435
+
436
+ 1. Call \`askUserQuestion\` to collect target admin emails:
437
+ - \`type\`: \`"freeText"\`
438
+ - \`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."
439
+ - \`placeholder\`: \`"admin@example.com"\`
440
+
441
+ 2. Extract individual emails from the response. For each \`<email>\`, verify Domain-wide Delegation access by calling \`${requestWithDelegationToolName}\`:
442
+ - \`method\`: \`"GET"\`
443
+ - \`path\`: \`"/activity/users/all/applications/login"\`
444
+ - \`subject\`: \`<email>\`
445
+ - \`scopes\`: \`${READONLY_SCOPES}\`
446
+ - \`queryParams\`: \`{ "maxResults": "1" }\`
447
+
448
+ 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))".
449
+ - \`options\`: \`[{ label: "Authorized Domain-wide Delegation \u2014 retry", value: "retry" }, { label: "Re-enter the email addresses", value: "restart" }]\`
450
+ - On "retry" \u2192 re-run step 2 with the previously entered email list
451
+ - On "Re-enter" \u2192 re-run step 1
452
+
453
+ 4. Once every email succeeds, call \`finalizeSetup\`. Record the verified admin email addresses as this connection's scope info.
454
+
455
+ #### Constraints
456
+ - Do NOT read audit log contents during setup. Only the access verification call in step 2 is permitted
457
+ - Write at most 1 sentence between tool calls`
458
+ },
459
+ dataOverviewInstructions: {
460
+ en: `Pick ONE admin user and use that user's email as \`subject\` for every call below. Pass \`scopes: ${READONLY_SCOPES}\` every time.
461
+
462
+ 1. \`method=GET\`, \`path=/activity/users/all/applications/login\`, \`queryParams={ maxResults: "10" }\` to verify recent login activity events are available.
463
+ 2. \`method=GET\`, \`path=/activity/users/all/applications/admin\`, \`queryParams={ maxResults: "10" }\` to inspect recent admin console events.
464
+ 3. \`method=GET\`, \`path=/usage/dates/{YYYY-MM-DD}\` (use yesterday's date) to fetch a customer-level usage report sample.`,
465
+ ja: `\u5BFE\u8C61\u306E\u7BA1\u7406\u8005\u30E6\u30FC\u30B6\u30FC\u3092 1 \u4EBA\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
466
+
467
+ 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
468
+ 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
469
+ 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`
470
+ }
471
+ });
472
+
473
+ // ../connectors/src/connectors/google-audit-log/index.ts
474
+ var tools = { request_with_delegation: requestWithDelegationTool };
475
+ var googleAuditLogConnector = new ConnectorPlugin({
476
+ slug: "google-audit-log",
477
+ authType: AUTH_TYPES.SERVICE_ACCOUNT,
478
+ name: "Google Audit Log",
479
+ 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.",
480
+ iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/6VWp0bASiAEgiSlwoZOT8A/fb59a3a2d0219db7df0a943b286a5995/admin_2020q4_48dp.png",
481
+ parameters,
482
+ releaseFlag: { dev1: true, dev2: true, prod: true },
483
+ categories: ["observability"],
484
+ onboarding: googleAuditLogOnboarding,
485
+ systemPrompt: {
486
+ en: `### Tools
487
+
488
+ - \`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. Always pass \`scopes\`.
489
+
490
+ ### OAuth Scopes (pass as \`scopes\` argument)
491
+
492
+ This connector is read-only. Pass one or both:
493
+
494
+ - \`https://www.googleapis.com/auth/admin.reports.audit.readonly\` \u2014 audit activity events (Activities API)
495
+ - \`https://www.googleapis.com/auth/admin.reports.usage.readonly\` \u2014 usage reports (Customer/User Usage API)
496
+
497
+ 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.
498
+
499
+ Per-endpoint reference: https://developers.google.com/admin-sdk/reports/v1/reference
500
+
501
+ ### Reports API Reference
502
+
503
+ #### Activities (audit logs)
504
+ - GET \`/activity/users/all/applications/{applicationName}\` \u2014 list activity events across all users for an application
505
+ - GET \`/activity/users/{userKey}/applications/{applicationName}\` \u2014 list activity events for a specific user (\`userKey\` is the user's email or immutable ID)
506
+ - GET \`/activity/users/all/applications/{applicationName}/watch\` \u2014 (not supported here, push notifications)
507
+
508
+ \`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\`.
509
+
510
+ Common Activities query parameters (pass via \`queryParams\`):
511
+ - \`startTime\` / \`endTime\` \u2014 ISO-8601 timestamps (e.g., \`2025-04-01T00:00:00Z\`)
512
+ - \`eventName\` \u2014 filter by a specific event (e.g., \`login_success\`, \`login_failure\`, \`document_open\`)
513
+ - \`filters\` \u2014 comma-separated event-parameter filters (e.g., \`doc_type==document\`)
514
+ - \`actorIpAddress\` \u2014 filter by IP
515
+ - \`maxResults\` \u2014 page size (default 1000)
516
+ - \`pageToken\` \u2014 pagination token from previous response's \`nextPageToken\`
517
+
518
+ #### Usage reports
519
+ - GET \`/usage/dates/{date}\` \u2014 customer-level usage on a specific date (\`YYYY-MM-DD\`)
520
+ - GET \`/usage/users/all/dates/{date}\` \u2014 per-user usage on a specific date
521
+ - GET \`/usage/users/{userKey}/dates/{date}\` \u2014 usage for a single user on a specific date
522
+
523
+ Common Usage query parameters:
524
+ - \`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.
525
+ - \`filters\` \u2014 filter expression on the same metric namespace
526
+ - \`maxResults\` / \`pageToken\` \u2014 pagination
527
+
528
+ ### Business Logic
529
+
530
+ 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.
531
+
532
+ SDK methods (client created via \`connection(connectionId)\`):
533
+
534
+ - \`client.requestWithDelegation(path, { subject, scopes, init? })\` \u2014 call the Reports API as the impersonated Workspace admin. Pass the minimum scopes required.
535
+
536
+ The method returns a standard \`Response\`. Read the body with \`.json()\`. Same path conventions as the tool.
537
+
538
+ #### Example
539
+
540
+ \`\`\`ts
541
+ import type { Context } from "hono";
542
+ import { connection } from "@squadbase/vite-server/connectors/google-audit-log";
543
+
544
+ const reports = connection("<connectionId>");
545
+
546
+ const SUBJECT = "admin@example.com"; // the admin user to impersonate
547
+ const AUDIT = ["https://www.googleapis.com/auth/admin.reports.audit.readonly"];
548
+
549
+ export default async function handler(c: Context) {
550
+ const { startTime, endTime } = await c.req.json<{
551
+ startTime: string;
552
+ endTime: string;
553
+ }>();
554
+
555
+ const params = new URLSearchParams({
556
+ startTime,
557
+ endTime,
558
+ maxResults: "100",
559
+ });
560
+ const res = await reports.requestWithDelegation(
561
+ \`/activity/users/all/applications/login?\${params}\`,
562
+ { subject: SUBJECT, scopes: AUDIT },
563
+ );
564
+ const data = (await res.json()) as { items?: { id: { time: string }; events?: { name: string }[]; actor?: { email?: string } }[] };
565
+
566
+ return c.json(
567
+ (data.items ?? []).map((item) => ({
568
+ time: item.id.time,
569
+ actor: item.actor?.email,
570
+ event: item.events?.[0]?.name,
571
+ })),
572
+ );
573
+ }
574
+ \`\`\``,
575
+ ja: `### \u30C4\u30FC\u30EB
576
+
577
+ - \`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\`scopes\` \u3082\u6BCE\u56DE\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\u3002
578
+
579
+ ### OAuth \u30B9\u30B3\u30FC\u30D7 (\`scopes\` \u5F15\u6570\u3067\u6E21\u3059)
580
+
581
+ \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:
582
+
583
+ - \`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)
584
+ - \`https://www.googleapis.com/auth/admin.reports.usage.readonly\` \u2014 \u5229\u7528\u30EC\u30DD\u30FC\u30C8 (Customer/User Usage API)
585
+
586
+ \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
587
+
588
+ \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
589
+
590
+ ### Reports API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
591
+
592
+ #### Activities\uFF08\u76E3\u67FB\u30ED\u30B0\uFF09
593
+ - 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
594
+ - 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
595
+
596
+ \`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
597
+
598
+ \u4E3B\u306A\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\uFF08\`queryParams\` \u306B\u6E21\u3059\uFF09:
599
+ - \`startTime\` / \`endTime\` \u2014 ISO-8601 \u30BF\u30A4\u30E0\u30B9\u30BF\u30F3\u30D7\uFF08\u4F8B: \`2025-04-01T00:00:00Z\`\uFF09
600
+ - \`eventName\` \u2014 \u7279\u5B9A\u306E\u30A4\u30D9\u30F3\u30C8\u3067\u30D5\u30A3\u30EB\u30BF\uFF08\u4F8B: \`login_success\`, \`login_failure\`, \`document_open\`\uFF09
601
+ - \`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
602
+ - \`actorIpAddress\` \u2014 IP\u30A2\u30C9\u30EC\u30B9\u3067\u30D5\u30A3\u30EB\u30BF
603
+ - \`maxResults\` \u2014 \u30DA\u30FC\u30B8\u30B5\u30A4\u30BA\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8 1000\uFF09
604
+ - \`pageToken\` \u2014 \u30EC\u30B9\u30DD\u30F3\u30B9\u306E \`nextPageToken\` \u3092\u6E21\u3057\u3066\u30DA\u30FC\u30B8\u30F3\u30B0
605
+
606
+ #### Usage\uFF08\u5229\u7528\u30EC\u30DD\u30FC\u30C8\uFF09
607
+ - 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
608
+ - GET \`/usage/users/all/dates/{date}\` \u2014 \u6307\u5B9A\u65E5\u306E\u5168\u30E6\u30FC\u30B6\u30FC\u5229\u7528\u30EC\u30DD\u30FC\u30C8
609
+ - GET \`/usage/users/{userKey}/dates/{date}\` \u2014 \u6307\u5B9A\u65E5\u306E\u7279\u5B9A\u30E6\u30FC\u30B6\u30FC\u306E\u5229\u7528\u30EC\u30DD\u30FC\u30C8
610
+
611
+ \u4E3B\u306A\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF:
612
+ - \`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
613
+ - \`filters\` \u2014 \u30E1\u30C8\u30EA\u30AF\u30B9\u306B\u5BFE\u3059\u308B\u30D5\u30A3\u30EB\u30BF\u5F0F
614
+ - \`maxResults\` / \`pageToken\` \u2014 \u30DA\u30FC\u30B8\u30F3\u30B0
615
+
616
+ ### Business Logic
617
+
618
+ \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
619
+
620
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
621
+
622
+ - \`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
623
+
624
+ \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
625
+
626
+ #### Example
627
+
628
+ \`\`\`ts
629
+ import type { Context } from "hono";
630
+ import { connection } from "@squadbase/vite-server/connectors/google-audit-log";
631
+
632
+ const reports = connection("<connectionId>");
633
+
634
+ const SUBJECT = "admin@example.com"; // \u4EE3\u7406\u5BFE\u8C61\u306E\u7BA1\u7406\u8005
635
+ const AUDIT = ["https://www.googleapis.com/auth/admin.reports.audit.readonly"];
636
+
637
+ export default async function handler(c: Context) {
638
+ const { startTime, endTime } = await c.req.json<{
639
+ startTime: string;
640
+ endTime: string;
641
+ }>();
642
+
643
+ const params = new URLSearchParams({
644
+ startTime,
645
+ endTime,
646
+ maxResults: "100",
647
+ });
648
+ const res = await reports.requestWithDelegation(
649
+ \`/activity/users/all/applications/login?\${params}\`,
650
+ { subject: SUBJECT, scopes: AUDIT },
651
+ );
652
+ const data = (await res.json()) as { items?: { id: { time: string }; events?: { name: string }[]; actor?: { email?: string } }[] };
653
+
654
+ return c.json(
655
+ (data.items ?? []).map((item) => ({
656
+ time: item.id.time,
657
+ actor: item.actor?.email,
658
+ event: item.events?.[0]?.name,
659
+ })),
660
+ );
661
+ }
662
+ \`\`\``
663
+ },
664
+ tools
665
+ });
666
+
667
+ // src/connectors/create-connector-sdk.ts
668
+ import { readFileSync } from "fs";
669
+ import path from "path";
670
+
671
+ // src/connector-client/env.ts
672
+ function resolveEnvVar(entry, key, connectionId) {
673
+ const envVarName = entry.envVars[key];
674
+ if (!envVarName) {
675
+ throw new Error(`Connection "${connectionId}" is missing envVars mapping for key "${key}"`);
676
+ }
677
+ const value = process.env[envVarName];
678
+ if (!value) {
679
+ throw new Error(`Environment variable "${envVarName}" (for connection "${connectionId}", key "${key}") is not set`);
680
+ }
681
+ return value;
682
+ }
683
+ function resolveEnvVarOptional(entry, key) {
684
+ const envVarName = entry.envVars[key];
685
+ if (!envVarName) return void 0;
686
+ return process.env[envVarName] || void 0;
687
+ }
688
+
689
+ // src/connector-client/proxy-fetch.ts
690
+ import { getContext } from "hono/context-storage";
691
+ import { getCookie } from "hono/cookie";
692
+ var APP_SESSION_COOKIE_NAME = "__Host-squadbase-session";
693
+ function normalizeHeaders(input) {
694
+ const out = {};
695
+ if (!input) return out;
696
+ new Headers(input).forEach((value, key) => {
697
+ out[key] = value;
698
+ });
699
+ return out;
700
+ }
701
+ function createSandboxProxyFetch(connectionId) {
702
+ return async (input, init) => {
703
+ const token = process.env.INTERNAL_SQUADBASE_OAUTH_MACHINE_CREDENTIAL;
704
+ const sandboxId = process.env.INTERNAL_SQUADBASE_SANDBOX_ID;
705
+ if (!token || !sandboxId) {
706
+ throw new Error(
707
+ "Connection proxy is not configured. Please check your deployment settings."
708
+ );
709
+ }
710
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
711
+ const originalMethod = init?.method ?? "GET";
712
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
713
+ const baseDomain = process.env["SQUADBASE_PREVIEW_BASE_DOMAIN"] ?? "preview.app.squadbase.dev";
714
+ const proxyUrl = `https://${sandboxId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
715
+ return fetch(proxyUrl, {
716
+ method: "POST",
717
+ headers: {
718
+ "Content-Type": "application/json",
719
+ Authorization: `Bearer ${token}`
720
+ },
721
+ body: JSON.stringify({
722
+ url: originalUrl,
723
+ method: originalMethod,
724
+ headers: normalizeHeaders(init?.headers),
725
+ body: originalBody
726
+ })
727
+ });
728
+ };
729
+ }
730
+ function createDeployedAppProxyFetch(connectionId) {
731
+ const projectId = process.env["SQUADBASE_PROJECT_ID"];
732
+ if (!projectId) {
733
+ throw new Error(
734
+ "Connection proxy is not configured. Please check your deployment settings."
735
+ );
736
+ }
737
+ const baseDomain = process.env["SQUADBASE_APP_BASE_DOMAIN"] ?? "squadbase.app";
738
+ const proxyUrl = `https://${projectId}.${baseDomain}/_sqcore/connections/${connectionId}/request`;
739
+ return async (input, init) => {
740
+ const originalUrl = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
741
+ const originalMethod = init?.method ?? "GET";
742
+ const originalBody = init?.body ? JSON.parse(init.body) : void 0;
743
+ const c = getContext();
744
+ const appSession = getCookie(c, APP_SESSION_COOKIE_NAME);
745
+ if (!appSession) {
746
+ throw new Error(
747
+ "No authentication method available for connection proxy."
748
+ );
749
+ }
750
+ return fetch(proxyUrl, {
751
+ method: "POST",
752
+ headers: {
753
+ "Content-Type": "application/json",
754
+ Authorization: `Bearer ${appSession}`
755
+ },
756
+ body: JSON.stringify({
757
+ url: originalUrl,
758
+ method: originalMethod,
759
+ headers: normalizeHeaders(init?.headers),
760
+ body: originalBody
761
+ })
762
+ });
763
+ };
764
+ }
765
+ function createProxyFetch(connectionId) {
766
+ if (process.env.INTERNAL_SQUADBASE_SANDBOX_ID) {
767
+ return createSandboxProxyFetch(connectionId);
768
+ }
769
+ return createDeployedAppProxyFetch(connectionId);
770
+ }
771
+
772
+ // src/connectors/create-connector-sdk.ts
773
+ function loadConnectionsSync() {
774
+ const filePath = process.env.CONNECTIONS_PATH ?? path.join(process.cwd(), ".squadbase/connections.json");
775
+ try {
776
+ const raw = readFileSync(filePath, "utf-8");
777
+ return JSON.parse(raw);
778
+ } catch {
779
+ return {};
780
+ }
781
+ }
782
+ function createConnectorSdk(plugin, createClient2) {
783
+ return (connectionId) => {
784
+ const connections = loadConnectionsSync();
785
+ const entry = connections[connectionId];
786
+ if (!entry) {
787
+ throw new Error(
788
+ `Connection "${connectionId}" not found in .squadbase/connections.json`
789
+ );
790
+ }
791
+ if (entry.connector.slug !== plugin.slug) {
792
+ throw new Error(
793
+ `Connection "${connectionId}" is not a ${plugin.slug} connection (got "${entry.connector.slug}")`
794
+ );
795
+ }
796
+ const params = {};
797
+ for (const param of Object.values(plugin.parameters)) {
798
+ if (param.required) {
799
+ params[param.slug] = resolveEnvVar(entry, param.slug, connectionId);
800
+ } else {
801
+ const val = resolveEnvVarOptional(entry, param.slug);
802
+ if (val !== void 0) params[param.slug] = val;
803
+ }
804
+ }
805
+ return createClient2(params, createProxyFetch(connectionId));
806
+ };
807
+ }
808
+
809
+ // src/connectors/entries/google-audit-log.ts
810
+ var connection = createConnectorSdk(googleAuditLogConnector, createClient);
811
+ export {
812
+ connection
813
+ };