@hasna/connectors 0.3.16 → 0.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 (127) hide show
  1. package/bin/index.js +71 -1
  2. package/bin/mcp.js +71 -1
  3. package/bin/serve.js +70 -0
  4. package/connectors/connect-asana/.env.example +11 -0
  5. package/connectors/connect-asana/CLAUDE.md +128 -0
  6. package/connectors/connect-asana/README.md +193 -0
  7. package/connectors/connect-asana/package.json +52 -0
  8. package/connectors/connect-asana/src/api/client.ts +119 -0
  9. package/connectors/connect-asana/src/api/index.ts +319 -0
  10. package/connectors/connect-asana/src/cli/index.ts +731 -0
  11. package/connectors/connect-asana/src/index.ts +19 -0
  12. package/connectors/connect-asana/src/types/index.ts +270 -0
  13. package/connectors/connect-asana/src/utils/config.ts +171 -0
  14. package/connectors/connect-asana/src/utils/output.ts +119 -0
  15. package/connectors/connect-asana/tsconfig.json +16 -0
  16. package/connectors/connect-clickup/.env.example +11 -0
  17. package/connectors/connect-clickup/CLAUDE.md +128 -0
  18. package/connectors/connect-clickup/README.md +193 -0
  19. package/connectors/connect-clickup/package.json +52 -0
  20. package/connectors/connect-clickup/src/api/client.ts +116 -0
  21. package/connectors/connect-clickup/src/api/index.ts +400 -0
  22. package/connectors/connect-clickup/src/cli/index.ts +625 -0
  23. package/connectors/connect-clickup/src/index.ts +19 -0
  24. package/connectors/connect-clickup/src/types/index.ts +591 -0
  25. package/connectors/connect-clickup/src/utils/config.ts +157 -0
  26. package/connectors/connect-clickup/src/utils/output.ts +119 -0
  27. package/connectors/connect-clickup/tsconfig.json +16 -0
  28. package/connectors/connect-confluence/.env.example +11 -0
  29. package/connectors/connect-confluence/CLAUDE.md +272 -0
  30. package/connectors/connect-confluence/README.md +193 -0
  31. package/connectors/connect-confluence/package.json +53 -0
  32. package/connectors/connect-confluence/scripts/release.ts +179 -0
  33. package/connectors/connect-confluence/src/api/client.ts +213 -0
  34. package/connectors/connect-confluence/src/api/example.ts +48 -0
  35. package/connectors/connect-confluence/src/api/index.ts +51 -0
  36. package/connectors/connect-confluence/src/cli/index.ts +254 -0
  37. package/connectors/connect-confluence/src/index.ts +103 -0
  38. package/connectors/connect-confluence/src/types/index.ts +237 -0
  39. package/connectors/connect-confluence/src/utils/auth.ts +274 -0
  40. package/connectors/connect-confluence/src/utils/bulk.ts +212 -0
  41. package/connectors/connect-confluence/src/utils/config.ts +326 -0
  42. package/connectors/connect-confluence/src/utils/output.ts +175 -0
  43. package/connectors/connect-confluence/src/utils/settings.ts +114 -0
  44. package/connectors/connect-confluence/src/utils/storage.ts +198 -0
  45. package/connectors/connect-confluence/tsconfig.json +16 -0
  46. package/connectors/connect-jira/.env.example +11 -0
  47. package/connectors/connect-jira/CLAUDE.md +128 -0
  48. package/connectors/connect-jira/README.md +193 -0
  49. package/connectors/connect-jira/package.json +53 -0
  50. package/connectors/connect-jira/src/api/client.ts +131 -0
  51. package/connectors/connect-jira/src/api/index.ts +266 -0
  52. package/connectors/connect-jira/src/cli/index.ts +653 -0
  53. package/connectors/connect-jira/src/index.ts +23 -0
  54. package/connectors/connect-jira/src/types/index.ts +448 -0
  55. package/connectors/connect-jira/src/utils/config.ts +179 -0
  56. package/connectors/connect-jira/src/utils/output.ts +119 -0
  57. package/connectors/connect-jira/tsconfig.json +16 -0
  58. package/connectors/connect-linear/CLAUDE.md +88 -0
  59. package/connectors/connect-linear/README.md +201 -0
  60. package/connectors/connect-linear/package.json +45 -0
  61. package/connectors/connect-linear/src/api/client.ts +62 -0
  62. package/connectors/connect-linear/src/api/index.ts +46 -0
  63. package/connectors/connect-linear/src/api/issues.ts +247 -0
  64. package/connectors/connect-linear/src/api/projects.ts +179 -0
  65. package/connectors/connect-linear/src/api/teams.ts +125 -0
  66. package/connectors/connect-linear/src/api/users.ts +112 -0
  67. package/connectors/connect-linear/src/cli/index.ts +560 -0
  68. package/connectors/connect-linear/src/index.ts +27 -0
  69. package/connectors/connect-linear/src/types/index.ts +275 -0
  70. package/connectors/connect-linear/src/utils/config.ts +249 -0
  71. package/connectors/connect-linear/src/utils/output.ts +119 -0
  72. package/connectors/connect-linear/tsconfig.json +16 -0
  73. package/connectors/connect-slack/.env.example +7 -0
  74. package/connectors/connect-slack/CLAUDE.md +69 -0
  75. package/connectors/connect-slack/README.md +150 -0
  76. package/connectors/connect-slack/package.json +44 -0
  77. package/connectors/connect-slack/src/api/channels.ts +112 -0
  78. package/connectors/connect-slack/src/api/client.ts +97 -0
  79. package/connectors/connect-slack/src/api/index.ts +42 -0
  80. package/connectors/connect-slack/src/api/messages.ts +127 -0
  81. package/connectors/connect-slack/src/api/users.ts +110 -0
  82. package/connectors/connect-slack/src/cli/index.ts +494 -0
  83. package/connectors/connect-slack/src/index.ts +21 -0
  84. package/connectors/connect-slack/src/types/index.ts +263 -0
  85. package/connectors/connect-slack/src/utils/config.ts +297 -0
  86. package/connectors/connect-slack/src/utils/output.ts +119 -0
  87. package/connectors/connect-slack/tsconfig.json +16 -0
  88. package/connectors/connect-telegram/.env.example +2 -0
  89. package/connectors/connect-telegram/package.json +49 -0
  90. package/connectors/connect-todoist/.env.example +11 -0
  91. package/connectors/connect-todoist/CLAUDE.md +104 -0
  92. package/connectors/connect-todoist/README.md +193 -0
  93. package/connectors/connect-todoist/package.json +52 -0
  94. package/connectors/connect-todoist/src/api/client.ts +117 -0
  95. package/connectors/connect-todoist/src/api/index.ts +188 -0
  96. package/connectors/connect-todoist/src/cli/index.ts +990 -0
  97. package/connectors/connect-todoist/src/index.ts +21 -0
  98. package/connectors/connect-todoist/src/types/index.ts +240 -0
  99. package/connectors/connect-todoist/src/utils/config.ts +157 -0
  100. package/connectors/connect-todoist/src/utils/output.ts +119 -0
  101. package/connectors/connect-todoist/tsconfig.json +16 -0
  102. package/connectors/connect-trello/.env.example +11 -0
  103. package/connectors/connect-trello/CLAUDE.md +128 -0
  104. package/connectors/connect-trello/README.md +193 -0
  105. package/connectors/connect-trello/package.json +53 -0
  106. package/connectors/connect-trello/src/api/client.ts +128 -0
  107. package/connectors/connect-trello/src/api/index.ts +278 -0
  108. package/connectors/connect-trello/src/cli/index.ts +737 -0
  109. package/connectors/connect-trello/src/index.ts +21 -0
  110. package/connectors/connect-trello/src/types/index.ts +314 -0
  111. package/connectors/connect-trello/src/utils/config.ts +182 -0
  112. package/connectors/connect-trello/src/utils/output.ts +119 -0
  113. package/connectors/connect-trello/tsconfig.json +16 -0
  114. package/connectors/connect-whatsapp/.env.example +11 -0
  115. package/connectors/connect-whatsapp/CLAUDE.md +113 -0
  116. package/connectors/connect-whatsapp/README.md +193 -0
  117. package/connectors/connect-whatsapp/package.json +53 -0
  118. package/connectors/connect-whatsapp/src/api/client.ts +133 -0
  119. package/connectors/connect-whatsapp/src/api/index.ts +365 -0
  120. package/connectors/connect-whatsapp/src/cli/index.ts +686 -0
  121. package/connectors/connect-whatsapp/src/index.ts +25 -0
  122. package/connectors/connect-whatsapp/src/types/index.ts +502 -0
  123. package/connectors/connect-whatsapp/src/utils/config.ts +179 -0
  124. package/connectors/connect-whatsapp/src/utils/output.ts +119 -0
  125. package/connectors/connect-whatsapp/tsconfig.json +16 -0
  126. package/dist/index.js +70 -0
  127. package/package.json +1 -1
@@ -0,0 +1,119 @@
1
+ import chalk from 'chalk';
2
+
3
+ export type OutputFormat = 'json' | 'table' | 'pretty';
4
+
5
+ export function formatOutput(data: unknown, format: OutputFormat = 'pretty'): string {
6
+ switch (format) {
7
+ case 'json':
8
+ return JSON.stringify(data, null, 2);
9
+ case 'table':
10
+ return formatAsTable(data);
11
+ case 'pretty':
12
+ default:
13
+ return formatPretty(data);
14
+ }
15
+ }
16
+
17
+ function formatAsTable(data: unknown): string {
18
+ if (!Array.isArray(data)) {
19
+ data = [data];
20
+ }
21
+
22
+ const items = data as Record<string, unknown>[];
23
+ if (items.length === 0) {
24
+ return 'No data';
25
+ }
26
+
27
+ const firstItem = items[0];
28
+ if (!firstItem || typeof firstItem !== 'object') {
29
+ return 'No data';
30
+ }
31
+
32
+ const keys = Object.keys(firstItem);
33
+ const colWidths = keys.map(key => {
34
+ const maxValue = Math.max(
35
+ key.length,
36
+ ...items.map(item => String(item[key] ?? '').length)
37
+ );
38
+ return Math.min(maxValue, 40);
39
+ });
40
+
41
+ const header = keys.map((key, i) => key.padEnd(colWidths[i] ?? 10)).join(' | ');
42
+ const separator = colWidths.map(w => '-'.repeat(w)).join('-+-');
43
+
44
+ const rows = items.map(item =>
45
+ keys.map((key, i) => {
46
+ const value = String(item[key] ?? '');
47
+ const width = colWidths[i] ?? 10;
48
+ return value.length > width
49
+ ? value.substring(0, width - 3) + '...'
50
+ : value.padEnd(width);
51
+ }).join(' | ')
52
+ );
53
+
54
+ return [header, separator, ...rows].join('\n');
55
+ }
56
+
57
+ function formatPretty(data: unknown): string {
58
+ if (Array.isArray(data)) {
59
+ return data.map((item, i) => `${chalk.cyan(`[${i + 1}]`)} ${formatPrettyItem(item)}`).join('\n\n');
60
+ }
61
+ return formatPrettyItem(data);
62
+ }
63
+
64
+ function formatPrettyItem(item: unknown, indent = 0): string {
65
+ if (item === null || item === undefined) {
66
+ return chalk.gray('null');
67
+ }
68
+
69
+ if (typeof item !== 'object') {
70
+ return String(item);
71
+ }
72
+
73
+ const spaces = ' '.repeat(indent);
74
+ const entries = Object.entries(item as Record<string, unknown>);
75
+
76
+ return entries
77
+ .map(([key, value]) => {
78
+ if (Array.isArray(value)) {
79
+ if (value.length === 0) {
80
+ return `${spaces}${chalk.blue(key)}: ${chalk.gray('[]')}`;
81
+ }
82
+ if (typeof value[0] === 'object') {
83
+ return `${spaces}${chalk.blue(key)}:\n${value.map(v => formatPrettyItem(v, indent + 1)).join('\n')}`;
84
+ }
85
+ return `${spaces}${chalk.blue(key)}: ${value.join(', ')}`;
86
+ }
87
+
88
+ if (typeof value === 'object' && value !== null) {
89
+ return `${spaces}${chalk.blue(key)}:\n${formatPrettyItem(value, indent + 1)}`;
90
+ }
91
+
92
+ return `${spaces}${chalk.blue(key)}: ${chalk.white(String(value))}`;
93
+ })
94
+ .join('\n');
95
+ }
96
+
97
+ export function success(message: string): void {
98
+ console.log(chalk.green('✓'), message);
99
+ }
100
+
101
+ export function error(message: string): void {
102
+ console.error(chalk.red('✗'), message);
103
+ }
104
+
105
+ export function warn(message: string): void {
106
+ console.warn(chalk.yellow('⚠'), message);
107
+ }
108
+
109
+ export function info(message: string): void {
110
+ console.log(chalk.blue('ℹ'), message);
111
+ }
112
+
113
+ export function heading(message: string): void {
114
+ console.log(chalk.bold.cyan(`\n${message}\n`));
115
+ }
116
+
117
+ export function print(data: unknown, format: OutputFormat = 'pretty'): void {
118
+ console.log(formatOutput(data, format));
119
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "declaration": true,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "types": ["bun-types"]
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist", "bin"]
16
+ }
@@ -0,0 +1,88 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code when working with this repository.
4
+
5
+ ## Project Overview
6
+
7
+ connect-linear is a TypeScript CLI and library for Linear's GraphQL API. It provides issue management, project management, team operations, and user operations with multi-profile support for managing multiple Linear workspaces.
8
+
9
+ ## Build & Run Commands
10
+
11
+ ```bash
12
+ bun install # Install dependencies
13
+ bun run dev # Run CLI in development
14
+ bun run build # Build for distribution
15
+ bun run typecheck # Type check
16
+ ```
17
+
18
+ ## Code Style
19
+
20
+ - TypeScript with strict mode
21
+ - ESM modules (type: module)
22
+ - Async/await for all async operations
23
+ - Minimal dependencies: commander, chalk
24
+
25
+ ## Project Structure
26
+
27
+ ```
28
+ src/
29
+ ├── api/
30
+ │ ├── client.ts # GraphQL client with Bearer auth
31
+ │ ├── issues.ts # Issues API
32
+ │ ├── projects.ts # Projects API
33
+ │ ├── teams.ts # Teams API
34
+ │ ├── users.ts # Users API
35
+ │ └── index.ts # Main Linear class
36
+ ├── cli/
37
+ │ └── index.ts # CLI commands
38
+ ├── types/
39
+ │ └── index.ts # TypeScript types
40
+ ├── utils/
41
+ │ ├── config.ts # Multi-profile configuration
42
+ │ └── output.ts # CLI output formatting
43
+ └── index.ts # Library exports
44
+ ```
45
+
46
+ ## API Architecture
47
+
48
+ The Linear API uses GraphQL. The client architecture:
49
+
50
+ 1. `LinearClient` - Base GraphQL client that handles authentication and requests
51
+ 2. API modules (Issues, Projects, Teams, Users) - Use the client to make specific queries/mutations
52
+ 3. `Linear` class - Main entry point that combines all API modules
53
+
54
+ ## Environment Variables
55
+
56
+ | Variable | Description |
57
+ |----------|-------------|
58
+ | `LINEAR_API_KEY` | Linear API key |
59
+
60
+ ## Multi-Profile Configuration
61
+
62
+ Configuration stored in `~/.connect/connect-linear/`:
63
+
64
+ ```
65
+ ~/.connect/connect-linear/
66
+ ├── current_profile
67
+ └── profiles/
68
+ └── default/
69
+ └── config.json
70
+ ```
71
+
72
+ ## GraphQL Endpoint
73
+
74
+ - Base URL: https://api.linear.app/graphql
75
+ - Auth: Bearer token (API key sent directly as Authorization header)
76
+
77
+ ## Dependencies
78
+
79
+ - commander: CLI framework
80
+ - chalk: Terminal styling
81
+
82
+ ## Priority Values
83
+
84
+ - 0: No priority
85
+ - 1: Urgent
86
+ - 2: High
87
+ - 3: Normal
88
+ - 4: Low
@@ -0,0 +1,201 @@
1
+ # @hasna/connect-linear
2
+
3
+ Linear API connector with CLI and library support. Provides a TypeScript-first interface for interacting with the Linear GraphQL API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @hasna/connect-linear
9
+ # or
10
+ bun add @hasna/connect-linear
11
+ ```
12
+
13
+ For CLI usage, install globally:
14
+
15
+ ```bash
16
+ npm install -g @hasna/connect-linear
17
+ ```
18
+
19
+ ## Configuration
20
+
21
+ ### Environment Variable
22
+
23
+ Set your Linear API key as an environment variable:
24
+
25
+ ```bash
26
+ export LINEAR_API_KEY="lin_api_xxxxx"
27
+ ```
28
+
29
+ ### CLI Configuration
30
+
31
+ Or use the CLI to save your API key:
32
+
33
+ ```bash
34
+ connect-linear config set-api-key lin_api_xxxxx
35
+ ```
36
+
37
+ Configuration is stored in `~/.connect/connect-linear/`.
38
+
39
+ ## CLI Usage
40
+
41
+ ### Authentication
42
+
43
+ ```bash
44
+ # Test authentication
45
+ connect-linear test
46
+
47
+ # Show current user
48
+ connect-linear whoami
49
+ ```
50
+
51
+ ### Issues
52
+
53
+ ```bash
54
+ # List issues
55
+ connect-linear issues list
56
+ connect-linear issues list --team <team-id>
57
+ connect-linear issues list --project <project-id>
58
+ connect-linear issues list --assignee <user-id>
59
+
60
+ # Get issue details
61
+ connect-linear issues get <issue-id>
62
+
63
+ # Create issue
64
+ connect-linear issues create --title "Bug fix" --team <team-id>
65
+ connect-linear issues create --title "Feature" --team <team-id> --description "Details here" --priority 2
66
+
67
+ # Update issue
68
+ connect-linear issues update <issue-id> --title "New title"
69
+ connect-linear issues update <issue-id> --state <state-id>
70
+ connect-linear issues update <issue-id> --assignee <user-id>
71
+
72
+ # Archive issue
73
+ connect-linear issues archive <issue-id>
74
+
75
+ # Search issues
76
+ connect-linear issues search "bug"
77
+ ```
78
+
79
+ ### Projects
80
+
81
+ ```bash
82
+ # List projects
83
+ connect-linear projects list
84
+
85
+ # Get project details
86
+ connect-linear projects get <project-id>
87
+ ```
88
+
89
+ ### Teams
90
+
91
+ ```bash
92
+ # List teams
93
+ connect-linear teams list
94
+
95
+ # Get team details
96
+ connect-linear teams get <team-id>
97
+
98
+ # List workflow states for a team
99
+ connect-linear teams states <team-id>
100
+ ```
101
+
102
+ ### Users
103
+
104
+ ```bash
105
+ # List users
106
+ connect-linear users list
107
+ connect-linear users list --all # Include inactive users
108
+
109
+ # Get user details
110
+ connect-linear users get <user-id>
111
+
112
+ # Current user
113
+ connect-linear users me
114
+ ```
115
+
116
+ ### Multi-Profile Support
117
+
118
+ ```bash
119
+ # Create a profile
120
+ connect-linear profile create work
121
+
122
+ # Switch profiles
123
+ connect-linear profile use work
124
+
125
+ # List profiles
126
+ connect-linear profile list
127
+
128
+ # Use profile for a single command
129
+ connect-linear --profile work issues list
130
+ ```
131
+
132
+ ### Output Formats
133
+
134
+ ```bash
135
+ # JSON output
136
+ connect-linear issues list --format json
137
+
138
+ # Table output
139
+ connect-linear issues list --format table
140
+
141
+ # Pretty output (default)
142
+ connect-linear issues list --format pretty
143
+ ```
144
+
145
+ ## Library Usage
146
+
147
+ ```typescript
148
+ import { Linear } from '@hasna/connect-linear';
149
+
150
+ const linear = new Linear({
151
+ apiKey: process.env.LINEAR_API_KEY!,
152
+ });
153
+
154
+ // List issues
155
+ const issues = await linear.issues.list({ teamId: 'team-id' });
156
+
157
+ // Create issue
158
+ const issue = await linear.issues.create({
159
+ title: 'New feature',
160
+ teamId: 'team-id',
161
+ description: 'Feature description',
162
+ priority: 2,
163
+ });
164
+
165
+ // Update issue
166
+ await linear.issues.update(issue.id, {
167
+ stateId: 'done-state-id',
168
+ });
169
+
170
+ // Get current user
171
+ const me = await linear.users.me();
172
+
173
+ // List teams
174
+ const teams = await linear.teams.list();
175
+
176
+ // Get workflow states
177
+ const states = await linear.teams.getWorkflowStates('team-id');
178
+
179
+ // Search issues
180
+ const results = await linear.issues.search('bug');
181
+ ```
182
+
183
+ ## Environment Variables
184
+
185
+ | Variable | Description |
186
+ |----------|-------------|
187
+ | `LINEAR_API_KEY` | Linear API key (required) |
188
+
189
+ ## Priority Values
190
+
191
+ | Value | Label |
192
+ |-------|-------|
193
+ | 0 | No priority |
194
+ | 1 | Urgent |
195
+ | 2 | High |
196
+ | 3 | Normal |
197
+ | 4 | Low |
198
+
199
+ ## License
200
+
201
+ Apache-2.0
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@hasna/connect-linear",
3
+ "version": "0.0.1",
4
+ "description": "Linear API connector with CLI and library support",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "connect-linear": "bin/index.js"
10
+ },
11
+ "scripts": {
12
+ "dev": "bun run ./src/cli/index.ts",
13
+ "build": "bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/cli/index.ts --outdir ./bin --target bun",
14
+ "typecheck": "tsc --noEmit",
15
+ "prepublishOnly": "bun run build"
16
+ },
17
+ "keywords": [
18
+ "linear",
19
+ "api",
20
+ "cli",
21
+ "connector",
22
+ "graphql"
23
+ ],
24
+ "author": "Hasna",
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "chalk": "^5.3.0",
28
+ "commander": "^12.1.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/bun": "latest",
32
+ "typescript": "^5.0.0"
33
+ },
34
+ "publishConfig": {
35
+ "registry": "https://registry.npmjs.org",
36
+ "access": "restricted"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "bin",
41
+ "src",
42
+ "README.md",
43
+ "CLAUDE.md"
44
+ ]
45
+ }
@@ -0,0 +1,62 @@
1
+ import type { LinearConfig, GraphQLResponse } from '../types';
2
+ import { LinearApiError } from '../types';
3
+
4
+ const DEFAULT_BASE_URL = 'https://api.linear.app/graphql';
5
+
6
+ export class LinearClient {
7
+ private readonly apiKey: string;
8
+ private readonly baseUrl: string;
9
+
10
+ constructor(config: LinearConfig) {
11
+ if (!config.apiKey) {
12
+ throw new Error('Linear API key is required');
13
+ }
14
+ this.apiKey = config.apiKey;
15
+ this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
16
+ }
17
+
18
+ /**
19
+ * Execute a GraphQL query
20
+ */
21
+ async query<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
22
+ const response = await fetch(this.baseUrl, {
23
+ method: 'POST',
24
+ headers: {
25
+ 'Content-Type': 'application/json',
26
+ 'Authorization': this.apiKey,
27
+ },
28
+ body: JSON.stringify({ query, variables }),
29
+ });
30
+
31
+ if (!response.ok) {
32
+ throw new LinearApiError(
33
+ `HTTP ${response.status}: ${response.statusText}`,
34
+ 'http_error',
35
+ response.status
36
+ );
37
+ }
38
+
39
+ const result = await response.json() as GraphQLResponse<T>;
40
+
41
+ if (result.errors && result.errors.length > 0) {
42
+ const error = result.errors[0];
43
+ throw new LinearApiError(
44
+ error.message,
45
+ error.extensions?.code as string || 'graphql_error'
46
+ );
47
+ }
48
+
49
+ if (!result.data) {
50
+ throw new LinearApiError('No data returned', 'no_data');
51
+ }
52
+
53
+ return result.data;
54
+ }
55
+
56
+ /**
57
+ * Execute a GraphQL mutation
58
+ */
59
+ async mutate<T>(mutation: string, variables?: Record<string, unknown>): Promise<T> {
60
+ return this.query<T>(mutation, variables);
61
+ }
62
+ }
@@ -0,0 +1,46 @@
1
+ import type { LinearConfig } from '../types';
2
+ import { LinearClient } from './client';
3
+ import { IssuesApi } from './issues';
4
+ import { ProjectsApi } from './projects';
5
+ import { TeamsApi } from './teams';
6
+ import { UsersApi } from './users';
7
+
8
+ export { LinearClient } from './client';
9
+ export { IssuesApi } from './issues';
10
+ export { ProjectsApi } from './projects';
11
+ export { TeamsApi } from './teams';
12
+ export { UsersApi } from './users';
13
+
14
+ /**
15
+ * Main Linear API class
16
+ */
17
+ export class Linear {
18
+ private readonly client: LinearClient;
19
+
20
+ public readonly issues: IssuesApi;
21
+ public readonly projects: ProjectsApi;
22
+ public readonly teams: TeamsApi;
23
+ public readonly users: UsersApi;
24
+
25
+ constructor(config: LinearConfig) {
26
+ this.client = new LinearClient(config);
27
+ this.issues = new IssuesApi(this.client);
28
+ this.projects = new ProjectsApi(this.client);
29
+ this.teams = new TeamsApi(this.client);
30
+ this.users = new UsersApi(this.client);
31
+ }
32
+
33
+ /**
34
+ * Test authentication and return current user
35
+ */
36
+ async test() {
37
+ return this.users.me();
38
+ }
39
+
40
+ /**
41
+ * Get the GraphQL client for custom queries
42
+ */
43
+ getClient(): LinearClient {
44
+ return this.client;
45
+ }
46
+ }