@ai2aim.ai/hivemind-sdk 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,655 @@
1
+ # @ai2aim/hivemind-sdk
2
+
3
+ Node.js / TypeScript SDK for the **Hivemind** API.
4
+ Covers every endpoint — organizations, RAG queries, generation, scraping, analytics, billing, audio, agents, and more.
5
+ Includes a **CLI** (`hivemind`) for init, config, health, helper utilities, query, org creation, and scraping.
6
+
7
+ **The Hivemind API is fully IAP-protected.** All endpoints require IAP. Supply `baseUrl` and `iapClientId` in config or via env (**HIVEMIND_BASE_URL** / **HIVEMIND_API_URL** and **IAP_CLIENT_ID**). Store org API keys in your system and pass them per-request (or in config).
8
+
9
+ ## Install
10
+
11
+ **From this repo (local):**
12
+
13
+ ```bash
14
+ cd sdk
15
+ npm install
16
+ npm run build
17
+
18
+ # Then in your other project:
19
+ npm install ../path-to/VERTEX-AI/sdk
20
+ ```
21
+
22
+ **Or publish to a private registry and install normally:**
23
+
24
+ ```bash
25
+ npm install @ai2aim/hivemind-sdk
26
+ ```
27
+
28
+ ## Quick start
29
+
30
+ Set **HIVEMIND_BASE_URL** (or HIVEMIND_API_URL) and **IAP_CLIENT_ID** in your environment once. Then create clients with only the overrides you need (e.g. `adminKey`, `apiKey`); baseUrl and iapClientId are read from env when omitted.
31
+
32
+ ```typescript
33
+ import { HivemindClient } from "@ai2aim/hivemind-sdk";
34
+
35
+ // With env set: HIVEMIND_BASE_URL, IAP_CLIENT_ID — no need to pass them
36
+ const client = new HivemindClient({
37
+ apiKey: "vtx_myorg_abc123...", // or pass per-request via options
38
+ });
39
+
40
+ const health = await client.health();
41
+ const result = await client.query("my-org", { query: "What is the return policy?" });
42
+ console.log(result.answer);
43
+ ```
44
+
45
+ ## Configuration
46
+
47
+ | Option | Required | Description |
48
+ |---|---|---|
49
+ | `baseUrl` | No* | API base URL; defaults to **HIVEMIND_BASE_URL** or **HIVEMIND_API_URL** |
50
+ | `iapClientId` | No* | IAP OAuth2 Client ID; defaults to **IAP_CLIENT_ID** |
51
+ | `apiPrefix` | No | Path prefix (default `/v1`) |
52
+ | `apiKey` | No | Org API key; or pass per-request (see below) |
53
+ | `adminKey` | No | Bootstrap admin key for admin endpoints |
54
+ | `webhookSecret` | No | Secret for webhook endpoints |
55
+ | `iapServiceAccountKeyPath` | No | Path to SA key for IAP; defaults to **GOOGLE_SA_KEY_PATH** |
56
+
57
+ \* Required in total: either pass them in config or set the env vars.
58
+ | `employeeId` | No | Employee ID header for RBAC |
59
+ | `timeoutMs` | No | Request timeout in ms (default 30 000) |
60
+ | `insecure` | No | Skip TLS verification for self-signed certs |
61
+
62
+ ### API key from your database or cache
63
+
64
+ You do **not** need to put the org API key in the client config. Store it in **your system’s database or cache** (e.g. per tenant/org) and pass it per request via the optional `options` parameter.
65
+
66
+ Set **HIVEMIND_BASE_URL** (or HIVEMIND_API_URL) and **IAP_CLIENT_ID** in your environment. Then create one shared client with no API key; pass the key from your store on each org-scoped call:
67
+
68
+ ```typescript
69
+ import { HivemindClient } from "@ai2aim/hivemind-sdk";
70
+
71
+ // Env: HIVEMIND_BASE_URL, IAP_CLIENT_ID (and optionally GOOGLE_SA_KEY_PATH)
72
+ // One shared client — no API key in config
73
+ const client = new HivemindClient({});
74
+
75
+ // In your app: load API key from your DB/cache for the current org
76
+ const apiKey = await getOrgApiKeyFromDb(orgId); // your function
77
+
78
+ const result = await client.query(orgId, { query: "What is the return policy?" }, { apiKey });
79
+ ```
80
+
81
+ All org-scoped methods accept an optional last argument `options?: RequestOptions` with `{ apiKey?: string }`. Use it to pass the key from your store instead of setting it on the client.
82
+
83
+ ### CLI config
84
+
85
+ The CLI reads config from **environment variables** and optionally **`.hivemindrc.json`** in the current directory. Env overrides file.
86
+
87
+ | Env | Description |
88
+ |---|---|
89
+ | `HIVEMIND_BASE_URL` | API base URL (required) |
90
+ | `IAP_CLIENT_ID` | IAP OAuth2 Client ID (required; all endpoints are IAP-protected) |
91
+ | `HIVEMIND_API_KEY` | Org API key (for org-scoped commands) |
92
+ | `HIVEMIND_ADMIN_KEY` | Admin key for org:create |
93
+ | `HIVEMIND_API_PREFIX` | Path prefix (default `/v1`) |
94
+ | `GOOGLE_SA_KEY_PATH` | Service account key path for IAP |
95
+ | `HIVEMIND_INSECURE` | Set to `true` to skip TLS verification |
96
+ | `HIVEMIND_TIMEOUT_MS` | Request timeout in ms |
97
+
98
+ You can also set `apiKey` on the client for single-tenant use. The SDK sends an IAP ID token (from `iapClientId` / IAP_CLIENT_ID) and, when present, the org API key.
99
+
100
+ ### Admin endpoints
101
+
102
+ If base URL and IAP are already in env, pass only `adminKey`:
103
+
104
+ ```typescript
105
+ const admin = new HivemindClient({
106
+ adminKey: "your-bootstrap-admin-key",
107
+ });
108
+
109
+ // Create a new organization (returns the org + API key)
110
+ const { organization, api_key } = await admin.createOrganization({
111
+ org_id: "acme",
112
+ name: "Acme Corp",
113
+ tier: "premium",
114
+ });
115
+
116
+ console.log("API Key:", api_key);
117
+ ```
118
+
119
+ ## CLI
120
+
121
+ After install, the `hivemind` binary is available (`npx hivemind` or via `npm exec hivemind` if installed globally).
122
+
123
+ ### Commands
124
+
125
+ | Command | Description |
126
+ |---|---|
127
+ | `hivemind init` | Create `.hivemindrc.json` and `.env.example` in the current directory |
128
+ | `hivemind config` | Print resolved config (secrets masked) |
129
+ | `hivemind health` | Call the API health endpoint |
130
+ | `hivemind helper validate` | Validate config and test connection |
131
+ | `hivemind helper env` | Print env var template for copy-paste |
132
+ | `hivemind query <org_id> <question>` | Run a RAG query (needs API key) |
133
+ | `hivemind org:create <org_id> <name>` | Create an organization (needs admin key) |
134
+ | `hivemind scrape <url...>` | Submit URLs to scrape |
135
+ | `hivemind scrape:status <task_id>` | Get scrape task status and result |
136
+
137
+ ### Examples
138
+
139
+ ```bash
140
+ # Initialize config in current directory
141
+ hivemind init
142
+
143
+ # Only create .env.example
144
+ hivemind init --env-only
145
+
146
+ # Check connection (requires HIVEMIND_BASE_URL and IAP_CLIENT_ID)
147
+ export HIVEMIND_BASE_URL=https://your-api.com
148
+ export IAP_CLIENT_ID=xxx.apps.googleusercontent.com
149
+ hivemind health
150
+
151
+ # Validate config and ping API
152
+ hivemind helper validate
153
+
154
+ # Print env template
155
+ hivemind helper env
156
+
157
+ # Run a RAG query (requires HIVEMIND_API_KEY)
158
+ hivemind query my-org "What is the return policy?"
159
+
160
+ # Create org (requires HIVEMIND_ADMIN_KEY)
161
+ hivemind org:create acme "Acme Corp" --tier premium
162
+
163
+ # Scrape URLs and wait for results
164
+ hivemind scrape https://example.com https://example.org --wait
165
+ ```
166
+
167
+ ### Options
168
+
169
+ - **`-d, --dir <path>`** (for init, config, health, helper, query, org:create, scrape): Directory to use for `.hivemindrc.json` (default: current directory).
170
+ - **`-u, --url <url>`** (health): Override base URL for a one-off health check.
171
+ - **`--skip-ping`** (helper validate): Validate config only, do not call the API.
172
+
173
+ ## All methods
174
+
175
+ All org-scoped methods accept an optional last argument `options?: RequestOptions` where you can pass `{ apiKey: string }` from your database or cache.
176
+
177
+ **Authentication types:**
178
+ - **Admin** — Set `adminKey` in client config. Sends `X-Admin-Key` header.
179
+ - **API Key** — Set `apiKey` in config or pass per-request via `options.apiKey`. Sent as `Authorization: Bearer <key>` (or `X-API-Key` when IAP is active).
180
+ - **Webhook** — Set `webhookSecret` in client config. Sends `X-Webhook-Secret` header.
181
+ - **None** — No authentication required.
182
+
183
+ All responses are wrapped in the standard envelope:
184
+ ```json
185
+ { "success": true, "statusCode": 200, "data": { ... }, "message": "Request successful" }
186
+ ```
187
+ The SDK returns the **`data`** payload directly (unwrapped).
188
+
189
+ ### Health
190
+
191
+ | Method | Auth | Description |
192
+ |---|---|---|
193
+ | `health()` | None | Service health check |
194
+
195
+ **Returns** `HealthResponse`:
196
+
197
+ | Field | Type | Description |
198
+ |-----------|--------|-------------------------------------------------------|
199
+ | `service` | string | Service name |
200
+ | `version` | string | Service version |
201
+ | `status` | string | Health status (`"ok"`) |
202
+ | `stats` | object | `{ organizations, documents, total_chunks }` |
203
+
204
+ ### Admin auth
205
+
206
+ | Method | Auth | Description |
207
+ |---|---|---|
208
+ | `adminLogin({ admin_key })` | None | Exchange admin key for a signed session token |
209
+
210
+ **Parameters** (`AdminLoginParams`):
211
+
212
+ | Field | Type | Required | Description |
213
+ |-------------|--------|----------|----------------------------|
214
+ | `admin_key` | string | Yes | The bootstrap admin key |
215
+
216
+ **Returns** `AdminLoginResponse`:
217
+
218
+ | Field | Type | Description |
219
+ |----------------------|--------|------------------------------------------|
220
+ | `access_token` | string | Signed JWT session token |
221
+ | `token_type` | string | Always `"bearer"` |
222
+ | `expires_in_seconds` | number | Token validity (default 28800 = 8 hours) |
223
+
224
+ ```typescript
225
+ const { access_token } = await client.adminLogin({ admin_key: "your-admin-key" });
226
+ ```
227
+
228
+ ### Organizations
229
+
230
+ | Method | Auth | Description |
231
+ |---|---|---|
232
+ | `createOrganization(params)` | Admin | Create org, returns org + API key |
233
+ | `getOrganization(orgId, options?)` | API Key | Get org details |
234
+ | `rotateApiKey(orgId, options?)` | Admin | Rotate org API key (24h grace period for old key) |
235
+ | `suspendOrganization(orgId, options?)` | Admin | Suspend an org (blocks API access) |
236
+ | `reactivateOrganization(orgId, options?)` | Admin | Reactivate a suspended org |
237
+ | `deleteOrganization(orgId, options?)` | Admin | Permanently delete an org (irreversible) |
238
+
239
+ **`createOrganization` parameters** (`OrgCreateParams`):
240
+
241
+ | Field | Type | Required | Default | Description |
242
+ |------------|--------|----------|--------------|------------------------------------------------|
243
+ | `org_id` | string | Yes | — | Unique org identifier (2–64 chars) |
244
+ | `name` | string | Yes | — | Display name (2–128 chars) |
245
+ | `tier` | string | No | `"standard"` | `"free"`, `"standard"`, `"premium"`, `"enterprise"` |
246
+ | `settings` | object | No | `{}` | Custom org settings |
247
+
248
+ **Returns** `OrgBootstrapResponse`:
249
+
250
+ | Field | Type | Description |
251
+ |----------------|--------------|------------------------------------|
252
+ | `organization` | Organization | Full organization entity |
253
+ | `api_key` | string | Generated API key (shown only once)|
254
+
255
+ ```typescript
256
+ const { organization, api_key } = await admin.createOrganization({
257
+ org_id: "acme-corp",
258
+ name: "Acme Corporation",
259
+ tier: "premium",
260
+ });
261
+ ```
262
+
263
+ ### Documents
264
+
265
+ | Method | Auth | Description |
266
+ |---|---|---|
267
+ | `uploadDocument(orgId, file, filename, options?)` | API Key | Upload a document (Buffer or Blob) |
268
+
269
+ **Parameters:**
270
+
271
+ | Param | Type | Required | Description |
272
+ |------------|----------------|----------|---------------------------------------|
273
+ | `orgId` | string | Yes | Organization identifier |
274
+ | `file` | Blob \| Buffer | Yes | Document content |
275
+ | `filename` | string | Yes | Original filename (e.g. `"report.pdf"`) |
276
+
277
+ **Returns** `DocumentUploadResponse`:
278
+
279
+ | Field | Type | Description |
280
+ |---------------|--------|-------------------------------------------|
281
+ | `document_id` | string | Unique document identifier |
282
+ | `org_id` | string | Organization ID |
283
+ | `filename` | string | Original filename |
284
+ | `chunks` | number | Number of text chunks created |
285
+ | `status` | string | Processing status (e.g. `"processed"`) |
286
+
287
+ ```typescript
288
+ import { readFileSync } from "fs";
289
+ const file = readFileSync("./report.pdf");
290
+ const result = await client.uploadDocument("acme-corp", file, "report.pdf");
291
+ console.log(`${result.chunks} chunks created`);
292
+ ```
293
+
294
+ ### Query (RAG)
295
+
296
+ | Method | Auth | Description |
297
+ |---|---|---|
298
+ | `query(orgId, params, options?)` | API Key | RAG query with retrieval and generation |
299
+
300
+ **Parameters** (`QueryParams`):
301
+
302
+ | Field | Type | Required | Default | Description |
303
+ |----------------------|--------|----------|--------------|-------------------------------------------|
304
+ | `query` | string | Yes | — | Query text |
305
+ | `user_id` | string | No | `null` | User identifier for tracking |
306
+ | `model_type` | string | No | `"gemini-pro"` | Gemini model for generation |
307
+ | `temperature` | number | No | `0.2` | Sampling temperature (0.0–1.0) |
308
+ | `retrieval_strategy` | string | No | `"hybrid"` | `"hybrid"`, `"dense"`, or `"sparse"` |
309
+
310
+ **Returns** `QueryResponse`:
311
+
312
+ | Field | Type | Description |
313
+ |--------------|----------|-------------------------------------------------|
314
+ | `answer` | string | Generated answer text |
315
+ | `sources` | object[] | Source citations (doc_id, chunk_id, score, snippet) |
316
+ | `model_type` | string | Model used |
317
+
318
+ ```typescript
319
+ const result = await client.query("acme-corp", {
320
+ query: "What are the key findings in Q4?",
321
+ temperature: 0.2,
322
+ });
323
+ console.log(result.answer);
324
+ result.sources.forEach(s => console.log(s.doc_id, s.score));
325
+ ```
326
+
327
+ ### Generation
328
+
329
+ | Method | Auth | Description |
330
+ |---|---|---|
331
+ | `generateVideo(orgId, params, options?)` | API Key | Start async video generation (Vertex AI Veo) |
332
+ | `generateImage(orgId, params, options?)` | API Key | Start async image generation (Vertex AI Imagen) |
333
+
334
+ **`generateVideo` parameters** (`GenerateVideoParams`):
335
+
336
+ | Field | Type | Required | Default | Description |
337
+ |----------------|--------|----------|----------|------------------------------------|
338
+ | `prompt` | string | Yes | — | Video generation prompt |
339
+ | `duration` | number | No | `8` | Duration: `4`, `6`, or `8` seconds |
340
+ | `aspect_ratio` | string | No | `"16:9"` | Aspect ratio |
341
+ | `style` | string | No | `null` | Visual style hint |
342
+ | `user_id` | string | No | `null` | User identifier |
343
+
344
+ **`generateImage` parameters** (`GenerateImageParams`):
345
+
346
+ | Field | Type | Required | Default | Description |
347
+ |----------------|--------|----------|---------|-------------------------------|
348
+ | `prompt` | string | Yes | — | Image generation prompt |
349
+ | `aspect_ratio` | string | No | `"1:1"` | Aspect ratio |
350
+ | `style` | string | No | `null` | Visual style hint |
351
+ | `num_images` | number | No | `1` | Number of images (1–8) |
352
+ | `user_id` | string | No | `null` | User identifier |
353
+
354
+ **Both return** `JobAcceptedResponse` (HTTP 202):
355
+
356
+ | Field | Type | Description |
357
+ |------------------|--------|-----------------------------------------------|
358
+ | `job_id` | string | Job ID — use with `getJob()` / `waitForJob()` |
359
+ | `status` | string | Always `"processing"` |
360
+ | `estimated_time` | number | Estimated processing time in seconds |
361
+
362
+ ```typescript
363
+ const job = await client.generateVideo("acme-corp", {
364
+ prompt: "A drone flyover of a mountain lake at sunset",
365
+ duration: 8,
366
+ style: "cinematic",
367
+ });
368
+ const result = await client.waitForJob("acme-corp", job.job_id);
369
+ console.log(result.result); // { output_url, signed_url }
370
+ ```
371
+
372
+ ### Jobs
373
+
374
+ | Method | Auth | Description |
375
+ |---|---|---|
376
+ | `getJob(orgId, jobId, options?)` | API Key | Get job status |
377
+ | `waitForJob(orgId, jobId, intervalMs?, maxWaitMs?, options?)` | API Key | Poll until job reaches terminal status |
378
+
379
+ **Returns** `JobStatusResponse`:
380
+
381
+ | Field | Type | Description |
382
+ |----------|----------------|------------------------------------------------------|
383
+ | `job_id` | string | Job identifier |
384
+ | `status` | string | `"processing"`, `"completed"`, `"failed"`, `"cancelled"` |
385
+ | `result` | object \| null | Result payload when completed (e.g. `{ output_url, signed_url }`) |
386
+ | `error` | string \| null | Error message if failed |
387
+
388
+ **`waitForJob` parameters:**
389
+
390
+ | Param | Type | Default | Description |
391
+ |--------------|--------|-----------|-----------------------------|
392
+ | `intervalMs` | number | `2000` | Polling interval (ms) |
393
+ | `maxWaitMs` | number | `300000` | Maximum wait time (ms) |
394
+
395
+ ### Data chat
396
+
397
+ | Method | Auth | Description |
398
+ |---|---|---|
399
+ | `dataChat(orgId, params, options?)` | API Key | Natural-language questions over BigQuery |
400
+
401
+ **Parameters** (`DataChatParams`):
402
+
403
+ | Field | Type | Required | Description |
404
+ |------------|--------|----------|--------------------------------|
405
+ | `question` | string | Yes | Natural-language question |
406
+ | `user_id` | string | No | User identifier for tracking |
407
+
408
+ **Returns** `DataChatResponse`:
409
+
410
+ | Field | Type | Description |
411
+ |----------|----------|------------------------------------|
412
+ | `answer` | string | Natural-language answer |
413
+ | `sql` | string | Generated SQL query |
414
+ | `rows` | object[] | Result rows from BigQuery |
415
+
416
+ ```typescript
417
+ const result = await client.dataChat("acme-corp", {
418
+ question: "How many active users this month?",
419
+ });
420
+ console.log(result.answer); // "There are 1,247 active users."
421
+ console.log(result.sql); // "SELECT COUNT(DISTINCT user_id) FROM ..."
422
+ ```
423
+
424
+ ### Agents
425
+
426
+ | Method | Auth | Description |
427
+ |---|---|---|
428
+ | `createAgent(orgId, params, options?)` | API Key | Create a custom AI agent template |
429
+ | `queryAgent(orgId, params, options?)` | API Key | Query an AI agent |
430
+
431
+ **`createAgent` parameters** (`AgentCreateParams`):
432
+
433
+ | Field | Type | Required | Default | Description |
434
+ |----------------|----------|----------|---------|---------------------------------|
435
+ | `name` | string | Yes | — | Agent name (2–64 chars) |
436
+ | `instructions` | string | Yes | — | System instructions (min 4 chars) |
437
+ | `tools` | string[] | No | `[]` | Tool identifiers to enable |
438
+
439
+ **`queryAgent` parameters** (`AgentQueryParams`):
440
+
441
+ | Field | Type | Required | Default | Description |
442
+ |--------------|--------|----------|----------|--------------------------|
443
+ | `query` | string | Yes | — | User query |
444
+ | `user_id` | string | Yes | — | User identifier |
445
+ | `agent_type` | string | No | `"auto"` | Agent type to route to |
446
+
447
+ ### Audio
448
+
449
+ | Method | Auth | Description |
450
+ |---|---|---|
451
+ | `transcribeAudio(orgId, params, options?)` | API Key | Speech-to-text transcription |
452
+ | `synthesizeAudio(orgId, params, options?)` | API Key | Text-to-speech synthesis |
453
+
454
+ **`transcribeAudio` parameters** (`AudioTranscribeParams`):
455
+
456
+ | Field | Type | Required | Default | Description |
457
+ |-----------------|--------|----------|------------|---------------------------|
458
+ | `audio_text` | string | Yes | — | Audio content / reference |
459
+ | `language_code` | string | No | `"en-US"` | BCP-47 language code |
460
+
461
+ **`synthesizeAudio` parameters** (`AudioSynthesizeParams`):
462
+
463
+ | Field | Type | Required | Default | Description |
464
+ |--------------|--------|----------|----------------------|---------------------|
465
+ | `text` | string | Yes | — | Text to synthesize |
466
+ | `voice_name` | string | No | `"en-US-Neural2-J"` | Voice identifier |
467
+
468
+ ### Analytics / ML
469
+
470
+ | Method | Auth | Description |
471
+ |---|---|---|
472
+ | `trainModel(orgId, params, options?)` | API Key | Train a predictive model on tabular data |
473
+ | `predict(orgId, params, options?)` | API Key | Run predictions with a trained model |
474
+ | `forecast(orgId, params, options?)` | API Key | Time-series forecast (ARIMA-based) |
475
+
476
+ **`trainModel` parameters** (`TrainModelParams`):
477
+
478
+ | Field | Type | Required | Description |
479
+ |-------------------|----------|----------|-----------------------------|
480
+ | `target_column` | string | Yes | Column to predict |
481
+ | `feature_columns` | string[] | Yes | Feature column names |
482
+ | `rows` | object[] | Yes | Training data rows |
483
+
484
+ **`predict` parameters** (`PredictParams`):
485
+
486
+ | Field | Type | Required | Description |
487
+ |-------------|----------|----------|------------------------------|
488
+ | `model_id` | string | Yes | Trained model ID |
489
+ | `instances` | object[] | Yes | Data instances to predict on |
490
+
491
+ **`forecast` parameters** (`ForecastParams`):
492
+
493
+ | Field | Type | Required | Default | Description |
494
+ |-----------|----------|----------|---------|--------------------------------|
495
+ | `series` | number[] | Yes | — | Historical time-series values |
496
+ | `horizon` | number | No | `30` | Forecast horizon (1–365) |
497
+
498
+ ```typescript
499
+ // Train
500
+ const model = await client.trainModel("acme-corp", {
501
+ target_column: "churn",
502
+ feature_columns: ["tenure", "monthly_charges"],
503
+ rows: [{ tenure: 12, monthly_charges: 50, churn: 0 }],
504
+ });
505
+
506
+ // Predict
507
+ const { predictions } = await client.predict("acme-corp", {
508
+ model_id: model.model_id,
509
+ instances: [{ tenure: 6, monthly_charges: 65 }],
510
+ });
511
+ ```
512
+
513
+ ### Billing
514
+
515
+ | Method | Auth | Description |
516
+ |---|---|---|
517
+ | `getUsage(orgId, month?, options?)` | API Key | Monthly usage summary with tier limits |
518
+ | `getInvoice(orgId, month?, options?)` | API Key | Monthly invoice with cost breakdown |
519
+
520
+ **Optional `month` parameter:** `YYYY-MM` format. Defaults to current month.
521
+
522
+ **`getUsage` returns** `UsageSummaryResponse`:
523
+
524
+ | Field | Type | Description |
525
+ |-------------------|----------|------------------------------------------------|
526
+ | `org_id` | string | Organization ID |
527
+ | `month` | string | Month (`YYYY-MM`) |
528
+ | `usage` | object | `{ tokens_used, images_generated, videos_generated, storage_bytes, compute_hours }` |
529
+ | `limits` | object | Tier limits |
530
+ | `within_quota` | boolean | Whether all metrics are within quota |
531
+ | `exceeded_limits` | string[] | List of exceeded metric names |
532
+
533
+ **`getInvoice` returns** `InvoiceResponse`:
534
+
535
+ | Field | Type | Description |
536
+ |--------------|----------|--------------------------------------|
537
+ | `org_id` | string | Organization ID |
538
+ | `month` | string | Month (`YYYY-MM`) |
539
+ | `total` | number | Total cost in USD |
540
+ | `line_items` | object[] | Itemized costs per resource type |
541
+
542
+ ### Audit
543
+
544
+ | Method | Auth | Description |
545
+ |---|---|---|
546
+ | `getAuditLogs(orgId, options?)` | API Key | List audit log records |
547
+
548
+ **Returns** `AuditLogResponse`:
549
+
550
+ | Field | Type | Description |
551
+ |-----------|----------------|--------------------|
552
+ | `org_id` | string | Organization ID |
553
+ | `records` | AuditRecord[] | Audit log entries |
554
+
555
+ Each `AuditRecord`:
556
+
557
+ | Field | Type | Description |
558
+ |------------|----------------|-----------------------------------------|
559
+ | `timestamp`| string | ISO 8601 timestamp |
560
+ | `action` | string | Action (e.g. `"query.execute"`) |
561
+ | `resource` | string | Resource path |
562
+ | `status` | string | `"success"` or `"failure"` |
563
+ | `user_id` | string \| null | User who performed the action |
564
+ | `metadata` | object | Additional context |
565
+
566
+ ### Scraping
567
+
568
+ | Method | Auth | Description |
569
+ |---|---|---|
570
+ | `getScrapingConfig()` | None | Runtime scraping configuration |
571
+ | `scrape({ urls })` | None | Submit URLs for scraping |
572
+ | `getScrapeStatus(taskId)` | None | Check scrape task status and results |
573
+ | `scrapeAndWait(urls, intervalMs?, maxWaitMs?)` | None | Submit + poll until results are ready |
574
+
575
+ **`scrape` parameters** (`ScrapeParams`):
576
+
577
+ | Field | Type | Required | Description |
578
+ |--------|----------|----------|---------------------------------|
579
+ | `urls` | string[] | Yes | URLs to scrape |
580
+
581
+ **`getScrapeStatus` returns** `ScrapeStatusResponse`:
582
+
583
+ | Field | Type | Description |
584
+ |-----------|-------------------|----------------------------------------------------|
585
+ | `task_id` | string | Task identifier |
586
+ | `status` | string | `"PENDING"`, `"SUCCESS"`, `"FAILURE"`, `"completed"` |
587
+ | `result` | ScrapeResultItem[] | Scraped results (each with url, title, full_text) |
588
+
589
+ ```typescript
590
+ const result = await client.scrapeAndWait(["https://example.com"]);
591
+ for (const page of result.result) {
592
+ console.log(page.title, page.full_text?.substring(0, 200));
593
+ }
594
+ ```
595
+
596
+ ### Webhooks
597
+
598
+ | Method | Auth | Description |
599
+ |---|---|---|
600
+ | `sendVideoCompleteWebhook(payload)` | Webhook | Send video completion notification |
601
+ | `sendDocumentProcessedWebhook(payload)` | Webhook | Send document processing notification |
602
+
603
+ **`VideoCompleteWebhook` payload:**
604
+
605
+ | Field | Type | Required | Description |
606
+ |------------|--------|----------|-------------------------------------|
607
+ | `job_id` | string | Yes | Job identifier |
608
+ | `org_id` | string | Yes | Organization identifier |
609
+ | `status` | string | Yes | Completion status |
610
+ | `metadata` | object | No | Additional data (e.g. `{ output_uri }`) |
611
+
612
+ **`DocumentProcessedWebhook` payload:**
613
+
614
+ | Field | Type | Required | Description |
615
+ |---------------|--------|----------|-------------------------------------|
616
+ | `document_id` | string | Yes | Document identifier |
617
+ | `org_id` | string | Yes | Organization identifier |
618
+ | `status` | string | Yes | Processing status |
619
+ | `metadata` | object | No | Additional data (e.g. `{ chunks }`) |
620
+
621
+ ## Error handling
622
+
623
+ All API errors throw `HivemindError`:
624
+
625
+ ```typescript
626
+ import { HivemindClient, HivemindError } from "@ai2aim/hivemind-sdk";
627
+
628
+ try {
629
+ await client.query("my-org", { query: "hello" });
630
+ } catch (err) {
631
+ if (err instanceof HivemindError) {
632
+ console.error(err.statusCode, err.detail);
633
+ }
634
+ }
635
+ ```
636
+
637
+ ## Vercel / Next.js example
638
+
639
+ ```typescript
640
+ // app/api/query/route.ts (Next.js App Router)
641
+ import { HivemindClient } from "@ai2aim/hivemind-sdk";
642
+ import { NextResponse } from "next/server";
643
+
644
+ // With HIVEMIND_API_URL and IAP_CLIENT_ID set in env, only overrides are needed
645
+ const client = new HivemindClient({
646
+ apiKey: process.env.HIVEMIND_API_KEY!,
647
+ iapServiceAccountKeyPath: process.env.GOOGLE_SA_KEY_PATH,
648
+ });
649
+
650
+ export async function POST(req: Request) {
651
+ const { query } = await req.json();
652
+ const result = await client.query("my-org", { query });
653
+ return NextResponse.json(result);
654
+ }
655
+ ```
@@ -0,0 +1,12 @@
1
+ import type { HivemindClientConfig } from "./types";
2
+ /**
3
+ * Load config from env (HIVEMIND_*) and optional .hivemindrc.json in cwd.
4
+ * Env overrides file. Returns null if baseUrl or iapClientId is missing (all endpoints are IAP-protected).
5
+ */
6
+ export declare function loadCliConfig(cwd?: string): HivemindClientConfig | null;
7
+ /**
8
+ * Return config with secrets masked for display.
9
+ */
10
+ export declare function maskConfig(config: HivemindClientConfig): Record<string, unknown>;
11
+ export declare const RC_FILENAME_EXPORT = ".hivemindrc.json";
12
+ //# sourceMappingURL=cli-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-config.d.ts","sourceRoot":"","sources":["../src/cli-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAsBpD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,SAAgB,GAAG,oBAAoB,GAAG,IAAI,CAqD9E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAehF;AAED,eAAO,MAAM,kBAAkB,qBAAc,CAAC"}