@hasna/connectors 1.3.45 → 1.4.0

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 (118) hide show
  1. package/README.md +25 -10
  2. package/bin/index.js +1362 -11796
  3. package/bin/mcp.js +751 -10328
  4. package/bin/serve.js +2252 -11829
  5. package/connectors/cloudflare-workers/.env.example +5 -0
  6. package/connectors/cloudflare-workers/AGENTS.md +11 -0
  7. package/connectors/cloudflare-workers/CLAUDE.md +11 -0
  8. package/connectors/cloudflare-workers/README.md +45 -0
  9. package/connectors/cloudflare-workers/package.json +47 -0
  10. package/connectors/cloudflare-workers/src/api/client.test.ts +144 -0
  11. package/connectors/cloudflare-workers/src/api/client.ts +386 -0
  12. package/connectors/cloudflare-workers/src/api/index.ts +1 -0
  13. package/connectors/cloudflare-workers/src/cli/index.ts +206 -0
  14. package/connectors/cloudflare-workers/src/index.ts +16 -0
  15. package/connectors/cloudflare-workers/src/types/index.ts +53 -0
  16. package/connectors/cloudflare-workers/src/utils/config.ts +61 -0
  17. package/connectors/cloudflare-workers/src/utils/output.ts +26 -0
  18. package/connectors/cloudflare-workers/tsconfig.build.json +4 -0
  19. package/connectors/cloudflare-workers/tsconfig.json +14 -0
  20. package/connectors/tidio/.env.example +3 -2
  21. package/connectors/tidio/CLAUDE.md +21 -96
  22. package/connectors/tidio/README.md +22 -18
  23. package/connectors/tidio/package.json +4 -2
  24. package/connectors/tidio/src/api/client.ts +26 -15
  25. package/connectors/tidio/src/api/index.ts +185 -128
  26. package/connectors/tidio/src/api/tidio.test.ts +175 -44
  27. package/connectors/tidio/src/cli/index.ts +154 -388
  28. package/connectors/tidio/src/index.ts +5 -3
  29. package/connectors/tidio/src/types/index.ts +135 -82
  30. package/connectors/tidio/src/utils/config.ts +90 -44
  31. package/connectors/wandb/.env.example +7 -0
  32. package/connectors/wandb/AGENTS.md +43 -0
  33. package/connectors/wandb/CLAUDE.md +67 -0
  34. package/connectors/wandb/README.md +65 -0
  35. package/connectors/wandb/package.json +52 -0
  36. package/connectors/wandb/src/api/client.test.ts +116 -0
  37. package/connectors/wandb/src/api/client.ts +83 -0
  38. package/connectors/wandb/src/api/graphql.ts +9 -0
  39. package/connectors/wandb/src/api/index.ts +36 -0
  40. package/connectors/wandb/src/api/projects.ts +36 -0
  41. package/connectors/wandb/src/api/viewer.ts +20 -0
  42. package/connectors/wandb/src/cli/index.ts +265 -0
  43. package/connectors/wandb/src/index.ts +22 -0
  44. package/connectors/wandb/src/types/index.ts +75 -0
  45. package/connectors/wandb/src/utils/config.ts +164 -0
  46. package/connectors/wandb/src/utils/output.ts +119 -0
  47. package/connectors/wandb/tsconfig.json +16 -0
  48. package/connectors/weights-biases/.env.example +7 -0
  49. package/connectors/weights-biases/CLAUDE.md +65 -0
  50. package/connectors/weights-biases/README.md +62 -0
  51. package/connectors/weights-biases/package.json +53 -0
  52. package/connectors/weights-biases/src/api/client.test.ts +46 -0
  53. package/connectors/weights-biases/src/api/client.ts +119 -0
  54. package/connectors/weights-biases/src/api/events.ts +18 -0
  55. package/connectors/weights-biases/src/api/index.ts +56 -0
  56. package/connectors/weights-biases/src/api/runs.ts +28 -0
  57. package/connectors/weights-biases/src/api/search.ts +10 -0
  58. package/connectors/weights-biases/src/cli/index.ts +289 -0
  59. package/connectors/weights-biases/src/index.ts +19 -0
  60. package/connectors/weights-biases/src/types/index.ts +92 -0
  61. package/connectors/weights-biases/src/utils/config.ts +168 -0
  62. package/connectors/weights-biases/src/utils/output.ts +116 -0
  63. package/connectors/weights-biases/tsconfig.json +16 -0
  64. package/connectors/x/src/api/oauth.test.ts +205 -0
  65. package/connectors/zoominfo/.env.example +4 -0
  66. package/connectors/zoominfo/AGENTS.md +26 -0
  67. package/connectors/zoominfo/CLAUDE.md +20 -0
  68. package/connectors/zoominfo/README.md +69 -0
  69. package/connectors/zoominfo/package.json +52 -0
  70. package/connectors/zoominfo/src/api/client.test.ts +140 -0
  71. package/connectors/zoominfo/src/api/client.ts +228 -0
  72. package/connectors/zoominfo/src/api/index.ts +1 -0
  73. package/connectors/zoominfo/src/cli/index.ts +179 -0
  74. package/connectors/zoominfo/src/index.ts +3 -0
  75. package/connectors/zoominfo/src/types/index.ts +39 -0
  76. package/connectors/zoominfo/src/utils/config.ts +61 -0
  77. package/connectors/zoominfo/src/utils/output.ts +27 -0
  78. package/connectors/zoominfo/tsconfig.json +20 -0
  79. package/connectors/zotero/.env.example +7 -0
  80. package/connectors/zotero/.npmrc.example +2 -0
  81. package/connectors/zotero/AGENTS.md +40 -0
  82. package/connectors/zotero/CLAUDE.md +69 -0
  83. package/connectors/zotero/README.md +91 -0
  84. package/connectors/zotero/package.json +43 -0
  85. package/connectors/zotero/src/api/attachments.ts +130 -0
  86. package/connectors/zotero/src/api/client.test.ts +166 -0
  87. package/connectors/zotero/src/api/client.ts +169 -0
  88. package/connectors/zotero/src/api/collections.ts +26 -0
  89. package/connectors/zotero/src/api/index.ts +45 -0
  90. package/connectors/zotero/src/api/items.ts +64 -0
  91. package/connectors/zotero/src/cli/index.ts +386 -0
  92. package/connectors/zotero/src/index.ts +28 -0
  93. package/connectors/zotero/src/types/index.ts +129 -0
  94. package/connectors/zotero/src/utils/config.ts +245 -0
  95. package/connectors/zotero/src/utils/output.ts +119 -0
  96. package/connectors/zotero/tsconfig.json +16 -0
  97. package/connectors/zymbly/.env.example +2 -0
  98. package/connectors/zymbly/AGENTS.md +11 -0
  99. package/connectors/zymbly/CLAUDE.md +5 -0
  100. package/connectors/zymbly/README.md +35 -0
  101. package/connectors/zymbly/package.json +52 -0
  102. package/connectors/zymbly/src/api/client.test.ts +110 -0
  103. package/connectors/zymbly/src/api/client.ts +166 -0
  104. package/connectors/zymbly/src/api/index.ts +1 -0
  105. package/connectors/zymbly/src/cli/index.ts +156 -0
  106. package/connectors/zymbly/src/index.ts +12 -0
  107. package/connectors/zymbly/src/types/index.ts +34 -0
  108. package/connectors/zymbly/src/utils/config.ts +52 -0
  109. package/connectors/zymbly/src/utils/output.ts +17 -0
  110. package/connectors/zymbly/tsconfig.json +13 -0
  111. package/dist/db/database.d.ts +2 -1
  112. package/dist/db/sqlite-adapter.d.ts +43 -0
  113. package/dist/index.js +172 -9653
  114. package/dist/lib/compact-output.d.ts +40 -0
  115. package/dist/mcp/tools/jobs.d.ts +32 -0
  116. package/dist/mcp/tools/jobs.test.d.ts +1 -0
  117. package/dist/no-cloud-boundary.test.d.ts +1 -0
  118. package/package.json +3 -3
@@ -0,0 +1,67 @@
1
+ # CLAUDE.md
2
+
3
+ Guidance for Claude Code when working with the Weights & Biases connector.
4
+
5
+ ## Project Overview
6
+
7
+ connect-wandb is a TypeScript CLI and library for the Weights & Biases GraphQL API (`https://api.wandb.ai/graphql`). It provides viewer lookup, project run listing, and ad-hoc GraphQL queries with multi-profile support.
8
+
9
+ ## Build & Run Commands
10
+
11
+ ```bash
12
+ bun install
13
+ bun run dev
14
+ bun run build
15
+ bun run typecheck
16
+ bun test
17
+ ```
18
+
19
+ ## Project Structure
20
+
21
+ ```
22
+ src/
23
+ ├── api/
24
+ │ ├── client.ts # GraphQL client with Bearer auth
25
+ │ ├── viewer.ts # Viewer query
26
+ │ ├── projects.ts # Project runs query
27
+ │ ├── graphql.ts # Ad-hoc queries
28
+ │ └── index.ts # Wandb facade
29
+ ├── cli/index.ts
30
+ ├── types/index.ts
31
+ ├── utils/config.ts
32
+ └── utils/output.ts
33
+ ```
34
+
35
+ ## Authentication
36
+
37
+ Bearer Token authentication. Credentials via:
38
+ - `WANDB_API_KEY` environment variable
39
+ - Profile config: `wandb config set-key <key>`
40
+
41
+ ## Environment Variables
42
+
43
+ | Variable | Description |
44
+ |----------|-------------|
45
+ | `WANDB_API_KEY` | W&B API key |
46
+ | `WANDB_BASE_URL` | Custom GraphQL endpoint (default: `https://api.wandb.ai/graphql`) |
47
+
48
+ ## Multi-Profile Configuration
49
+
50
+ Configuration stored in `~/.hasna/connectors/wandb/`:
51
+
52
+ ```
53
+ ~/.hasna/connectors/wandb/
54
+ ├── current_profile
55
+ └── profiles/
56
+ └── default.json
57
+ ```
58
+
59
+ ## GraphQL Endpoint
60
+
61
+ - Base URL: `https://api.wandb.ai/graphql`
62
+ - Auth: `Authorization: Bearer <api_key>`
63
+
64
+ ## Dependencies
65
+
66
+ - commander: CLI framework
67
+ - chalk: Terminal styling
@@ -0,0 +1,65 @@
1
+ # connect-wandb
2
+
3
+ Weights & Biases GraphQL API connector — experiment tracking with multi-profile support.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun install -g @hasna/connect-wandb
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ # Set your API key
15
+ wandb config set-key YOUR_API_KEY
16
+
17
+ # Or use environment variable
18
+ export WANDB_API_KEY=YOUR_API_KEY
19
+
20
+ # Verify authentication
21
+ wandb viewer
22
+ ```
23
+
24
+ ## CLI Commands
25
+
26
+ ```bash
27
+ wandb config set-key <key> # Set API key
28
+ wandb config show # Show config
29
+ wandb viewer # Get authenticated user
30
+ wandb project-runs --entity <e> --project <p> # List project runs
31
+ wandb graphql --query '<query>' [--variables '<json>']
32
+ wandb raw --body '<json>' # Raw GraphQL POST body
33
+ wandb profile list # List profiles
34
+ wandb profile use <name> # Switch profile
35
+ ```
36
+
37
+ ## Profile Management
38
+
39
+ ```bash
40
+ wandb profile create work --api-key xxx --use
41
+ wandb profile create personal --api-key yyy
42
+ wandb -p personal viewer
43
+ ```
44
+
45
+ ## Library Usage
46
+
47
+ ```typescript
48
+ import { Wandb } from '@hasna/connect-wandb';
49
+
50
+ const client = new Wandb({ apiKey: process.env.WANDB_API_KEY! });
51
+
52
+ const { viewer } = await client.viewer.get();
53
+ const runs = await client.projects.projectRuns({ entity: 'team', project: 'demo' });
54
+ ```
55
+
56
+ ## Environment Variables
57
+
58
+ | Variable | Description |
59
+ |----------|-------------|
60
+ | `WANDB_API_KEY` | API key (overrides profile) |
61
+ | `WANDB_BASE_URL` | Override GraphQL base URL |
62
+
63
+ ## License
64
+
65
+ Apache-2.0
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@hasna/connect-wandb",
3
+ "version": "0.1.0",
4
+ "description": "Weights & Biases GraphQL API connector - experiment tracking with multi-profile support",
5
+ "type": "module",
6
+ "bin": {
7
+ "wandb": "./bin/index.js"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "scripts": {
18
+ "build": "bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/cli/index.ts --outdir ./bin --target bun",
19
+ "dev": "bun run ./src/cli/index.ts",
20
+ "typecheck": "tsc --noEmit",
21
+ "test": "bun test src/api/client.test.ts"
22
+ },
23
+ "keywords": [
24
+ "wandb",
25
+ "weights-and-biases",
26
+ "ml",
27
+ "experiments",
28
+ "graphql",
29
+ "connector",
30
+ "cli",
31
+ "typescript",
32
+ "bun",
33
+ "hasna"
34
+ ],
35
+ "author": "Hasna",
36
+ "license": "Apache-2.0",
37
+ "devDependencies": {
38
+ "@types/bun": "latest",
39
+ "typescript": "^5"
40
+ },
41
+ "dependencies": {
42
+ "commander": "^12.1.0",
43
+ "chalk": "^5.3.0"
44
+ },
45
+ "engines": {
46
+ "bun": ">=1.0.0"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/hasna/connectors.git"
51
+ }
52
+ }
@@ -0,0 +1,116 @@
1
+ import { afterEach, describe, expect, test } from 'bun:test';
2
+ import { Wandb, WandbClient } from './index';
3
+ import { WandbApiError } from '../types';
4
+
5
+ const realFetch = globalThis.fetch;
6
+
7
+ interface RecordedRequest {
8
+ url: string;
9
+ method: string;
10
+ headers: Record<string, string>;
11
+ body?: string;
12
+ }
13
+
14
+ function installFetch(handler: (recorded: RecordedRequest) => unknown) {
15
+ const recorded: RecordedRequest[] = [];
16
+ globalThis.fetch = (async (input: string | URL | Request, init?: RequestInit) => {
17
+ const url = typeof input === 'string' ? input : input.toString();
18
+ const headers: Record<string, string> = {};
19
+ if (init?.headers) {
20
+ const h = init.headers as Record<string, string>;
21
+ Object.assign(headers, h);
22
+ }
23
+ const body = typeof init?.body === 'string' ? init.body : undefined;
24
+ const entry = { url, method: init?.method ?? 'GET', headers, body };
25
+ recorded.push(entry);
26
+ const json = handler(entry);
27
+ return {
28
+ ok: true,
29
+ status: 200,
30
+ statusText: 'OK',
31
+ async json() {
32
+ return json ?? {};
33
+ },
34
+ } as Response;
35
+ }) as typeof fetch;
36
+ return recorded;
37
+ }
38
+
39
+ afterEach(() => {
40
+ globalThis.fetch = realFetch;
41
+ });
42
+
43
+ describe('WandbClient', () => {
44
+ test('requires API key', () => {
45
+ expect(() => new WandbClient({ apiKey: '' })).toThrow('W&B API key is required');
46
+ });
47
+
48
+ test('sends Bearer authorization header', async () => {
49
+ const recorded = installFetch(() => ({
50
+ data: { viewer: { id: '1', username: 'testuser' } },
51
+ }));
52
+ const client = new WandbClient({ apiKey: 'test-key-123' });
53
+ await client.query('query Viewer { viewer { id username } }');
54
+ expect(recorded[0].url).toBe('https://api.wandb.ai/graphql');
55
+ expect(recorded[0].method).toBe('POST');
56
+ expect(recorded[0].headers['Authorization']).toBe('Bearer test-key-123');
57
+ });
58
+
59
+ test('viewer query sends expected GraphQL body', async () => {
60
+ const recorded = installFetch(() => ({
61
+ data: { viewer: { id: 'v1', username: 'alice', name: 'Alice' } },
62
+ }));
63
+ const wandb = new Wandb({ apiKey: 'key' });
64
+ const result = await wandb.viewer.get();
65
+ expect(result.viewer.username).toBe('alice');
66
+ const body = JSON.parse(recorded[0].body!);
67
+ expect(body.query).toContain('viewer');
68
+ expect(body.query).toContain('username');
69
+ });
70
+
71
+ test('projectRuns passes entity and project variables', async () => {
72
+ const recorded = installFetch(() => ({
73
+ data: {
74
+ project: {
75
+ runs: {
76
+ edges: [{ node: { id: 'r1', name: 'run-1', displayName: 'Run 1', state: 'finished' } }],
77
+ },
78
+ },
79
+ },
80
+ }));
81
+ const wandb = new Wandb({ apiKey: 'key' });
82
+ const result = await wandb.projects.projectRuns({ entity: 'team', project: 'demo' });
83
+ expect(result.project?.runs.edges[0].node.name).toBe('run-1');
84
+ const body = JSON.parse(recorded[0].body!);
85
+ expect(body.variables).toEqual({ entity: 'team', project: 'demo', first: 50 });
86
+ expect(body.query).toContain('ProjectRuns');
87
+ });
88
+
89
+ test('throws WandbApiError on GraphQL errors', async () => {
90
+ installFetch(() => ({
91
+ errors: [{ message: 'Not authorized', extensions: { code: 'UNAUTHORIZED' } }],
92
+ }));
93
+ const client = new WandbClient({ apiKey: 'bad-key' });
94
+ await expect(client.query('query { viewer { id } }')).rejects.toThrow('Not authorized');
95
+ });
96
+
97
+ test('throws WandbApiError on HTTP errors', async () => {
98
+ globalThis.fetch = (async () => ({
99
+ ok: false,
100
+ status: 401,
101
+ statusText: 'Unauthorized',
102
+ async json() {
103
+ return {};
104
+ },
105
+ })) as unknown as typeof fetch;
106
+ const client = new WandbClient({ apiKey: 'key' });
107
+ await expect(client.query('query { viewer { id } }')).rejects.toThrow(WandbApiError);
108
+ });
109
+
110
+ test('custom base URL is respected', async () => {
111
+ const recorded = installFetch(() => ({ data: { viewer: { id: '1' } } }));
112
+ const client = new WandbClient({ apiKey: 'key', baseUrl: 'https://custom.example/graphql' });
113
+ await client.query('query { viewer { id } }');
114
+ expect(recorded[0].url).toBe('https://custom.example/graphql');
115
+ });
116
+ });
@@ -0,0 +1,83 @@
1
+ import type { WandbConfig, GraphQLResponse } from '../types';
2
+ import { WandbApiError } from '../types';
3
+
4
+ export const DEFAULT_BASE_URL = 'https://api.wandb.ai/graphql';
5
+
6
+ export class WandbClient {
7
+ private readonly apiKey: string;
8
+ private readonly baseUrl: string;
9
+
10
+ constructor(config: WandbConfig) {
11
+ if (!config.apiKey) {
12
+ throw new Error('W&B API key is required');
13
+ }
14
+ this.apiKey = config.apiKey;
15
+ this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
16
+ }
17
+
18
+ getBaseUrl(): string {
19
+ return this.baseUrl;
20
+ }
21
+
22
+ /**
23
+ * Execute a GraphQL query or mutation against the W&B API.
24
+ */
25
+ async query<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
26
+ const response = await fetch(this.baseUrl, {
27
+ method: 'POST',
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ 'Authorization': `Bearer ${this.apiKey}`,
31
+ },
32
+ body: JSON.stringify({ query, variables }),
33
+ });
34
+
35
+ if (!response.ok) {
36
+ throw new WandbApiError(
37
+ `HTTP ${response.status}: ${response.statusText}`,
38
+ 'http_error',
39
+ response.status
40
+ );
41
+ }
42
+
43
+ const result = await response.json() as GraphQLResponse<T>;
44
+
45
+ if (result.errors && result.errors.length > 0) {
46
+ const error = result.errors[0];
47
+ throw new WandbApiError(
48
+ error.message,
49
+ (error.extensions?.code as string) || 'graphql_error'
50
+ );
51
+ }
52
+
53
+ if (!result.data) {
54
+ throw new WandbApiError('No data returned', 'no_data');
55
+ }
56
+
57
+ return result.data;
58
+ }
59
+
60
+ /**
61
+ * Send a raw JSON body to the GraphQL endpoint (for advanced use).
62
+ */
63
+ async raw<T>(body: Record<string, unknown>): Promise<T> {
64
+ const response = await fetch(this.baseUrl, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ 'Authorization': `Bearer ${this.apiKey}`,
69
+ },
70
+ body: JSON.stringify(body),
71
+ });
72
+
73
+ if (!response.ok) {
74
+ throw new WandbApiError(
75
+ `HTTP ${response.status}: ${response.statusText}`,
76
+ 'http_error',
77
+ response.status
78
+ );
79
+ }
80
+
81
+ return await response.json() as T;
82
+ }
83
+ }
@@ -0,0 +1,9 @@
1
+ import type { WandbClient } from './client';
2
+
3
+ export class GraphqlApi {
4
+ constructor(private readonly client: WandbClient) {}
5
+
6
+ async execute<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
7
+ return this.client.query<T>(query, variables);
8
+ }
9
+ }
@@ -0,0 +1,36 @@
1
+ import type { WandbConfig } from '../types';
2
+ import { WandbClient } from './client';
3
+ import { ViewerApi } from './viewer';
4
+ import { ProjectsApi } from './projects';
5
+ import { GraphqlApi } from './graphql';
6
+
7
+ export { WandbClient, DEFAULT_BASE_URL } from './client';
8
+ export { ViewerApi } from './viewer';
9
+ export { ProjectsApi } from './projects';
10
+ export { GraphqlApi } from './graphql';
11
+
12
+ /**
13
+ * Main Weights & Biases GraphQL API class.
14
+ */
15
+ export class Wandb {
16
+ private readonly client: WandbClient;
17
+
18
+ public readonly viewer: ViewerApi;
19
+ public readonly projects: ProjectsApi;
20
+ public readonly graphql: GraphqlApi;
21
+
22
+ constructor(config: WandbConfig) {
23
+ this.client = new WandbClient(config);
24
+ this.viewer = new ViewerApi(this.client);
25
+ this.projects = new ProjectsApi(this.client);
26
+ this.graphql = new GraphqlApi(this.client);
27
+ }
28
+
29
+ async test() {
30
+ return this.viewer.get();
31
+ }
32
+
33
+ getClient(): WandbClient {
34
+ return this.client;
35
+ }
36
+ }
@@ -0,0 +1,36 @@
1
+ import type { WandbClient } from './client';
2
+ import type { ProjectRunsOptions, ProjectRunsResponse } from '../types';
3
+
4
+ const PROJECT_RUNS_QUERY = `query ProjectRuns($entity: String!, $project: String!, $first: Int, $order: String, $filters: JSONString) {
5
+ project(name: $project, entityName: $entity) {
6
+ runs(first: $first, order: $order, filters: $filters) {
7
+ edges {
8
+ node {
9
+ id
10
+ name
11
+ displayName
12
+ state
13
+ createdAt
14
+ summaryMetrics
15
+ }
16
+ }
17
+ pageInfo {
18
+ endCursor
19
+ hasNextPage
20
+ }
21
+ }
22
+ }
23
+ }`;
24
+
25
+ export class ProjectsApi {
26
+ constructor(private readonly client: WandbClient) {}
27
+
28
+ async projectRuns(options: ProjectRunsOptions) {
29
+ const { entity, project, first = 50, order, filters } = options;
30
+ const variables: Record<string, unknown> = { entity, project, first };
31
+ if (order) variables.order = order;
32
+ if (filters) variables.filters = JSON.stringify(filters);
33
+
34
+ return this.client.query<ProjectRunsResponse>(PROJECT_RUNS_QUERY, variables);
35
+ }
36
+ }
@@ -0,0 +1,20 @@
1
+ import type { WandbClient } from './client';
2
+ import type { ViewerResponse } from '../types';
3
+
4
+ const VIEWER_QUERY = `query Viewer {
5
+ viewer {
6
+ id
7
+ username
8
+ name
9
+ email
10
+ entity
11
+ }
12
+ }`;
13
+
14
+ export class ViewerApi {
15
+ constructor(private readonly client: WandbClient) {}
16
+
17
+ async get() {
18
+ return this.client.query<ViewerResponse>(VIEWER_QUERY);
19
+ }
20
+ }