@happyvertical/graphql 0.74.8
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/AGENT.md +33 -0
- package/LICENSE +7 -0
- package/dist/claude-context.d.ts +1 -0
- package/dist/cli/claude-context.d.ts +3 -0
- package/dist/cli/claude-context.js +21 -0
- package/dist/cli/claude-context.js.map +1 -0
- package/dist/index.d.ts +171 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/metadata.json +29 -0
- package/package.json +53 -0
package/AGENT.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @happyvertical/graphql
|
|
2
|
+
|
|
3
|
+
<!-- BEGIN AGENT:GENERATED -->
|
|
4
|
+
## Purpose
|
|
5
|
+
GitHub GraphQL client for SDK packages
|
|
6
|
+
|
|
7
|
+
## Package Map
|
|
8
|
+
- Package: `@happyvertical/graphql`
|
|
9
|
+
- Hierarchy path: `@happyvertical/sdk > packages > graphql`
|
|
10
|
+
- Workspace position: `14 of 30` local packages
|
|
11
|
+
- Internal dependencies: none
|
|
12
|
+
- Internal dependents: `@happyvertical/projects`, `@happyvertical/repos`
|
|
13
|
+
- Knowledge graph files: `AGENT.md`, `metadata.json`, `ecosystem-manifest.json`
|
|
14
|
+
|
|
15
|
+
## Build & Test
|
|
16
|
+
```bash
|
|
17
|
+
pnpm --filter @happyvertical/graphql build
|
|
18
|
+
pnpm --filter @happyvertical/graphql test
|
|
19
|
+
pnpm --filter @happyvertical/graphql clean
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Agent Correction Loops
|
|
23
|
+
- If Vite or TypeScript reports missing packages, run `pnpm install` at the repo root and rerun `pnpm --filter @happyvertical/graphql build`.
|
|
24
|
+
- If tests or exports fail after API, type, or bundle changes, run `pnpm --filter @happyvertical/graphql clean` followed by `pnpm --filter @happyvertical/graphql build` and `pnpm --filter @happyvertical/graphql test`.
|
|
25
|
+
- If failures span multiple packages or Turborepo ordering looks wrong, run `pnpm build` and `pnpm typecheck` from the repo root before retrying package-scoped commands.
|
|
26
|
+
|
|
27
|
+
## Ecosystem Relationships
|
|
28
|
+
- Provides: GitHub GraphQL client for SDK packages
|
|
29
|
+
- Implements: none
|
|
30
|
+
- Requires: none
|
|
31
|
+
- Stability: stable (Primary package surface is described as implemented and production-oriented.)
|
|
32
|
+
<!-- END AGENT:GENERATED -->
|
|
33
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, mkdirSync, copyFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const Dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const pkgRoot = join(Dirname, "../..");
|
|
7
|
+
const targetDir = join(process.cwd(), ".claude");
|
|
8
|
+
if (!existsSync(targetDir)) {
|
|
9
|
+
mkdirSync(targetDir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
const pkgName = "graphql";
|
|
12
|
+
const agentMdSrc = existsSync(join(pkgRoot, "AGENT.md")) ? join(pkgRoot, "AGENT.md") : join(pkgRoot, "CLAUDE.md");
|
|
13
|
+
const metaSrc = existsSync(join(pkgRoot, "metadata.json")) ? join(pkgRoot, "metadata.json") : join(pkgRoot, ".claude-meta.json");
|
|
14
|
+
if (existsSync(agentMdSrc)) {
|
|
15
|
+
copyFileSync(agentMdSrc, join(targetDir, `have-${pkgName}.md`));
|
|
16
|
+
}
|
|
17
|
+
if (existsSync(metaSrc)) {
|
|
18
|
+
copyFileSync(metaSrc, join(targetDir, `have-${pkgName}.meta.json`));
|
|
19
|
+
}
|
|
20
|
+
console.log(`✓ Installed @happyvertical/${pkgName} context to .claude/`);
|
|
21
|
+
//# sourceMappingURL=claude-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-context.js","sources":["../../src/cli/claude-context.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI script to install agent context for @happyvertical/graphql\n * Run the published context installer binary for this package.\n */\nimport { copyFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst Dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgRoot = join(Dirname, '../..');\nconst targetDir = join(process.cwd(), '.claude');\n\nif (!existsSync(targetDir)) {\n mkdirSync(targetDir, { recursive: true });\n}\n\nconst pkgName = 'graphql';\nconst agentMdSrc = existsSync(join(pkgRoot, 'AGENT.md'))\n ? join(pkgRoot, 'AGENT.md')\n : join(pkgRoot, 'CLAUDE.md');\nconst metaSrc = existsSync(join(pkgRoot, 'metadata.json'))\n ? join(pkgRoot, 'metadata.json')\n : join(pkgRoot, '.claude-meta.json');\n\nif (existsSync(agentMdSrc)) {\n copyFileSync(agentMdSrc, join(targetDir, `have-${pkgName}.md`));\n}\n\nif (existsSync(metaSrc)) {\n copyFileSync(metaSrc, join(targetDir, `have-${pkgName}.meta.json`));\n}\n\nconsole.log(`✓ Installed @happyvertical/${pkgName} context to .claude/`);\n"],"names":[],"mappings":";;;;AASA,MAAM,UAAU,QAAQ,cAAc,YAAY,GAAG,CAAC;AACtD,MAAM,UAAU,KAAK,SAAS,OAAO;AACrC,MAAM,YAAY,KAAK,QAAQ,IAAA,GAAO,SAAS;AAE/C,IAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,YAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AAC1C;AAEA,MAAM,UAAU;AAChB,MAAM,aAAa,WAAW,KAAK,SAAS,UAAU,CAAC,IACnD,KAAK,SAAS,UAAU,IACxB,KAAK,SAAS,WAAW;AAC7B,MAAM,UAAU,WAAW,KAAK,SAAS,eAAe,CAAC,IACrD,KAAK,SAAS,eAAe,IAC7B,KAAK,SAAS,mBAAmB;AAErC,IAAI,WAAW,UAAU,GAAG;AAC1B,eAAa,YAAY,KAAK,WAAW,QAAQ,OAAO,KAAK,CAAC;AAChE;AAEA,IAAI,WAAW,OAAO,GAAG;AACvB,eAAa,SAAS,KAAK,WAAW,QAAQ,OAAO,YAAY,CAAC;AACpE;AAEA,QAAQ,IAAI,8BAA8B,OAAO,sBAAsB;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a GraphQL client instance
|
|
3
|
+
*
|
|
4
|
+
* This is the main entry point for creating GraphQL clients.
|
|
5
|
+
* It can accept either a configuration object or an existing client instance.
|
|
6
|
+
*
|
|
7
|
+
* @param options - GraphQL configuration or existing client instance
|
|
8
|
+
* @returns Promise resolving to GraphQL client interface
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { getGraphQLClient } from '@happyvertical/graphql';
|
|
13
|
+
*
|
|
14
|
+
* // Create a GitHub GraphQL client
|
|
15
|
+
* const github = await getGraphQLClient({
|
|
16
|
+
* endpoint: 'https://api.github.com/graphql',
|
|
17
|
+
* token: process.env.GITHUB_TOKEN
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Create a GitLab GraphQL client
|
|
21
|
+
* const gitlab = await getGraphQLClient({
|
|
22
|
+
* endpoint: 'https://gitlab.com/api/graphql',
|
|
23
|
+
* token: process.env.GITLAB_TOKEN
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Custom headers for other APIs
|
|
27
|
+
* const custom = await getGraphQLClient({
|
|
28
|
+
* endpoint: 'https://api.example.com/graphql',
|
|
29
|
+
* headers: {
|
|
30
|
+
* 'X-API-Key': 'my-api-key',
|
|
31
|
+
* 'X-Custom-Header': 'value'
|
|
32
|
+
* }
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Execute a query
|
|
36
|
+
* const result = await github.query<{ viewer: { login: string } }>(`
|
|
37
|
+
* query {
|
|
38
|
+
* viewer {
|
|
39
|
+
* login
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* `);
|
|
43
|
+
*
|
|
44
|
+
* // Pass existing instance (returns it unchanged)
|
|
45
|
+
* const sameClient = await getGraphQLClient(github);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function getGraphQLClient(options: GraphQLConfig | IGraphQLClient): Promise<IGraphQLClient>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generic GraphQL client implementation
|
|
52
|
+
*
|
|
53
|
+
* Works with any GraphQL endpoint - GitHub, GitLab, Shopify, custom APIs, etc.
|
|
54
|
+
*/
|
|
55
|
+
export declare class GraphQLClient implements IGraphQLClient {
|
|
56
|
+
private readonly endpoint;
|
|
57
|
+
private readonly headers;
|
|
58
|
+
constructor(config: GraphQLConfig);
|
|
59
|
+
/**
|
|
60
|
+
* Execute a GraphQL query
|
|
61
|
+
*/
|
|
62
|
+
query<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
63
|
+
/**
|
|
64
|
+
* Execute a GraphQL mutation
|
|
65
|
+
*/
|
|
66
|
+
mutate<T>(mutation: string, variables?: Record<string, unknown>): Promise<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Execute GraphQL operation
|
|
69
|
+
*/
|
|
70
|
+
private execute;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* GraphQL client types
|
|
75
|
+
*/
|
|
76
|
+
/**
|
|
77
|
+
* GraphQL client configuration
|
|
78
|
+
*
|
|
79
|
+
* Generic configuration for any GraphQL endpoint.
|
|
80
|
+
* GraphQL is a protocol, not a provider - the client
|
|
81
|
+
* works with any GraphQL API (GitHub, GitLab, Shopify, etc.)
|
|
82
|
+
*/
|
|
83
|
+
export declare interface GraphQLConfig {
|
|
84
|
+
/** GraphQL endpoint URL */
|
|
85
|
+
endpoint: string;
|
|
86
|
+
/** Bearer token for Authorization header */
|
|
87
|
+
token?: string;
|
|
88
|
+
/** Custom headers (merged with defaults) */
|
|
89
|
+
headers?: Record<string, string>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* GraphQL error class
|
|
94
|
+
*/
|
|
95
|
+
export declare class GraphQLError extends Error {
|
|
96
|
+
readonly code: GraphQLErrorCode;
|
|
97
|
+
readonly details?: GraphQLErrorDetail[];
|
|
98
|
+
readonly originalError?: unknown;
|
|
99
|
+
constructor(message: string, code: GraphQLErrorCode, details?: GraphQLErrorDetail[], originalError?: unknown);
|
|
100
|
+
/**
|
|
101
|
+
* Create error from HTTP status code
|
|
102
|
+
*/
|
|
103
|
+
static fromHTTPStatus(status: number, message: string, originalError?: unknown): GraphQLError;
|
|
104
|
+
/**
|
|
105
|
+
* Create error from GraphQL response errors
|
|
106
|
+
*/
|
|
107
|
+
static fromGraphQLErrors(errors: GraphQLErrorDetail[]): GraphQLError;
|
|
108
|
+
/**
|
|
109
|
+
* Create network error
|
|
110
|
+
*/
|
|
111
|
+
static networkError(message: string, originalError?: unknown): GraphQLError;
|
|
112
|
+
/**
|
|
113
|
+
* Check if error is retryable
|
|
114
|
+
*/
|
|
115
|
+
isRetryable(): boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Error codes for GraphQL operations
|
|
120
|
+
*/
|
|
121
|
+
export declare enum GraphQLErrorCode {
|
|
122
|
+
/** Authentication failed */
|
|
123
|
+
UNAUTHORIZED = "UNAUTHORIZED",
|
|
124
|
+
/** Resource not found */
|
|
125
|
+
NOT_FOUND = "NOT_FOUND",
|
|
126
|
+
/** Rate limit exceeded */
|
|
127
|
+
RATE_LIMITED = "RATE_LIMITED",
|
|
128
|
+
/** Network error */
|
|
129
|
+
NETWORK_ERROR = "NETWORK_ERROR",
|
|
130
|
+
/** Invalid query or mutation */
|
|
131
|
+
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
132
|
+
/** Unknown error */
|
|
133
|
+
UNKNOWN = "UNKNOWN"
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* GraphQL error detail from API response
|
|
138
|
+
*/
|
|
139
|
+
export declare interface GraphQLErrorDetail {
|
|
140
|
+
message: string;
|
|
141
|
+
type?: string;
|
|
142
|
+
path?: string[];
|
|
143
|
+
locations?: Array<{
|
|
144
|
+
line: number;
|
|
145
|
+
column: number;
|
|
146
|
+
}>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* GraphQL response structure
|
|
151
|
+
*/
|
|
152
|
+
export declare interface GraphQLResponse<T> {
|
|
153
|
+
data?: T;
|
|
154
|
+
errors?: GraphQLErrorDetail[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* GraphQL client interface
|
|
159
|
+
*/
|
|
160
|
+
export declare interface IGraphQLClient {
|
|
161
|
+
/**
|
|
162
|
+
* Execute a GraphQL query
|
|
163
|
+
*/
|
|
164
|
+
query<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
165
|
+
/**
|
|
166
|
+
* Execute a GraphQL mutation
|
|
167
|
+
*/
|
|
168
|
+
mutate<T>(mutation: string, variables?: Record<string, unknown>): Promise<T>;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
var GraphQLErrorCode = /* @__PURE__ */ ((GraphQLErrorCode2) => {
|
|
2
|
+
GraphQLErrorCode2["UNAUTHORIZED"] = "UNAUTHORIZED";
|
|
3
|
+
GraphQLErrorCode2["NOT_FOUND"] = "NOT_FOUND";
|
|
4
|
+
GraphQLErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
|
|
5
|
+
GraphQLErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
6
|
+
GraphQLErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
7
|
+
GraphQLErrorCode2["UNKNOWN"] = "UNKNOWN";
|
|
8
|
+
return GraphQLErrorCode2;
|
|
9
|
+
})(GraphQLErrorCode || {});
|
|
10
|
+
class GraphQLError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
details;
|
|
13
|
+
originalError;
|
|
14
|
+
constructor(message, code, details, originalError) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "GraphQLError";
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.details = details;
|
|
19
|
+
this.originalError = originalError;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Create error from HTTP status code
|
|
23
|
+
*/
|
|
24
|
+
static fromHTTPStatus(status, message, originalError) {
|
|
25
|
+
let code;
|
|
26
|
+
switch (status) {
|
|
27
|
+
case 401:
|
|
28
|
+
code = "UNAUTHORIZED";
|
|
29
|
+
break;
|
|
30
|
+
case 403:
|
|
31
|
+
code = "RATE_LIMITED";
|
|
32
|
+
break;
|
|
33
|
+
case 404:
|
|
34
|
+
code = "NOT_FOUND";
|
|
35
|
+
break;
|
|
36
|
+
case 422:
|
|
37
|
+
code = "VALIDATION_ERROR";
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
code = "UNKNOWN";
|
|
41
|
+
}
|
|
42
|
+
return new GraphQLError(message, code, void 0, originalError);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Create error from GraphQL response errors
|
|
46
|
+
*/
|
|
47
|
+
static fromGraphQLErrors(errors) {
|
|
48
|
+
const message = errors.map((e) => e.message).join("; ");
|
|
49
|
+
return new GraphQLError(
|
|
50
|
+
`GraphQL errors: ${message}`,
|
|
51
|
+
"VALIDATION_ERROR",
|
|
52
|
+
errors
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create network error
|
|
57
|
+
*/
|
|
58
|
+
static networkError(message, originalError) {
|
|
59
|
+
return new GraphQLError(
|
|
60
|
+
message,
|
|
61
|
+
"NETWORK_ERROR",
|
|
62
|
+
void 0,
|
|
63
|
+
originalError
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if error is retryable
|
|
68
|
+
*/
|
|
69
|
+
isRetryable() {
|
|
70
|
+
return this.code === "RATE_LIMITED" || this.code === "NETWORK_ERROR";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class GraphQLClient {
|
|
74
|
+
endpoint;
|
|
75
|
+
headers;
|
|
76
|
+
constructor(config) {
|
|
77
|
+
if (!config.endpoint) {
|
|
78
|
+
throw new GraphQLError(
|
|
79
|
+
"GraphQL endpoint is required",
|
|
80
|
+
GraphQLError.fromHTTPStatus(400, "Missing endpoint").code
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
this.endpoint = config.endpoint;
|
|
84
|
+
this.headers = {
|
|
85
|
+
"Content-Type": "application/json"
|
|
86
|
+
};
|
|
87
|
+
if (config.token) {
|
|
88
|
+
this.headers.Authorization = `Bearer ${config.token}`;
|
|
89
|
+
}
|
|
90
|
+
if (config.headers) {
|
|
91
|
+
Object.assign(this.headers, config.headers);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Execute a GraphQL query
|
|
96
|
+
*/
|
|
97
|
+
async query(query, variables) {
|
|
98
|
+
return this.execute(query, variables);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Execute a GraphQL mutation
|
|
102
|
+
*/
|
|
103
|
+
async mutate(mutation, variables) {
|
|
104
|
+
return this.execute(mutation, variables);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Execute GraphQL operation
|
|
108
|
+
*/
|
|
109
|
+
async execute(operation, variables) {
|
|
110
|
+
let response;
|
|
111
|
+
try {
|
|
112
|
+
response = await fetch(this.endpoint, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: this.headers,
|
|
115
|
+
body: JSON.stringify({ query: operation, variables })
|
|
116
|
+
});
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw GraphQLError.networkError(
|
|
119
|
+
`Failed to connect to GraphQL API: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
120
|
+
error
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const errorText = await response.text();
|
|
125
|
+
throw GraphQLError.fromHTTPStatus(
|
|
126
|
+
response.status,
|
|
127
|
+
`GraphQL error: ${response.statusText}
|
|
128
|
+
${errorText}`,
|
|
129
|
+
errorText
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
const result = await response.json();
|
|
133
|
+
if (result.errors && result.errors.length > 0) {
|
|
134
|
+
throw GraphQLError.fromGraphQLErrors(result.errors);
|
|
135
|
+
}
|
|
136
|
+
if (!result.data) {
|
|
137
|
+
throw new GraphQLError(
|
|
138
|
+
"GraphQL response contained no data",
|
|
139
|
+
GraphQLError.fromHTTPStatus(500, "No data").code
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
return result.data;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function isGraphQLClientInstance(value) {
|
|
146
|
+
return value !== null && typeof value === "object" && "query" in value && "mutate" in value && typeof value.query === "function" && typeof value.mutate === "function";
|
|
147
|
+
}
|
|
148
|
+
async function getGraphQLClient(options) {
|
|
149
|
+
if (isGraphQLClientInstance(options)) {
|
|
150
|
+
return options;
|
|
151
|
+
}
|
|
152
|
+
if (!options.endpoint) {
|
|
153
|
+
throw new GraphQLError(
|
|
154
|
+
"GraphQL endpoint is required",
|
|
155
|
+
GraphQLErrorCode.VALIDATION_ERROR
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return new GraphQLClient(options);
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
GraphQLClient,
|
|
162
|
+
GraphQLError,
|
|
163
|
+
GraphQLErrorCode,
|
|
164
|
+
getGraphQLClient
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/errors.ts","../src/client.ts","../src/factory.ts"],"sourcesContent":["/**\n * GraphQL error handling\n */\n\nimport type { GraphQLErrorDetail } from './types.js';\n\n/**\n * Error codes for GraphQL operations\n */\nexport enum GraphQLErrorCode {\n /** Authentication failed */\n UNAUTHORIZED = 'UNAUTHORIZED',\n /** Resource not found */\n NOT_FOUND = 'NOT_FOUND',\n /** Rate limit exceeded */\n RATE_LIMITED = 'RATE_LIMITED',\n /** Network error */\n NETWORK_ERROR = 'NETWORK_ERROR',\n /** Invalid query or mutation */\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n /** Unknown error */\n UNKNOWN = 'UNKNOWN',\n}\n\n/**\n * GraphQL error class\n */\nexport class GraphQLError extends Error {\n readonly code: GraphQLErrorCode;\n readonly details?: GraphQLErrorDetail[];\n readonly originalError?: unknown;\n\n constructor(\n message: string,\n code: GraphQLErrorCode,\n details?: GraphQLErrorDetail[],\n originalError?: unknown,\n ) {\n super(message);\n this.name = 'GraphQLError';\n this.code = code;\n this.details = details;\n this.originalError = originalError;\n }\n\n /**\n * Create error from HTTP status code\n */\n static fromHTTPStatus(\n status: number,\n message: string,\n originalError?: unknown,\n ): GraphQLError {\n let code: GraphQLErrorCode;\n\n switch (status) {\n case 401:\n code = GraphQLErrorCode.UNAUTHORIZED;\n break;\n case 403:\n code = GraphQLErrorCode.RATE_LIMITED;\n break;\n case 404:\n code = GraphQLErrorCode.NOT_FOUND;\n break;\n case 422:\n code = GraphQLErrorCode.VALIDATION_ERROR;\n break;\n default:\n code = GraphQLErrorCode.UNKNOWN;\n }\n\n return new GraphQLError(message, code, undefined, originalError);\n }\n\n /**\n * Create error from GraphQL response errors\n */\n static fromGraphQLErrors(errors: GraphQLErrorDetail[]): GraphQLError {\n const message = errors.map((e) => e.message).join('; ');\n return new GraphQLError(\n `GraphQL errors: ${message}`,\n GraphQLErrorCode.VALIDATION_ERROR,\n errors,\n );\n }\n\n /**\n * Create network error\n */\n static networkError(message: string, originalError?: unknown): GraphQLError {\n return new GraphQLError(\n message,\n GraphQLErrorCode.NETWORK_ERROR,\n undefined,\n originalError,\n );\n }\n\n /**\n * Check if error is retryable\n */\n isRetryable(): boolean {\n return (\n this.code === GraphQLErrorCode.RATE_LIMITED ||\n this.code === GraphQLErrorCode.NETWORK_ERROR\n );\n }\n}\n","/**\n * Generic GraphQL client\n */\n\nimport { GraphQLError } from './errors.js';\nimport type {\n GraphQLConfig,\n GraphQLErrorDetail,\n IGraphQLClient,\n} from './types.js';\n\n/**\n * Generic GraphQL client implementation\n *\n * Works with any GraphQL endpoint - GitHub, GitLab, Shopify, custom APIs, etc.\n */\nexport class GraphQLClient implements IGraphQLClient {\n private readonly endpoint: string;\n private readonly headers: Record<string, string>;\n\n constructor(config: GraphQLConfig) {\n if (!config.endpoint) {\n throw new GraphQLError(\n 'GraphQL endpoint is required',\n GraphQLError.fromHTTPStatus(400, 'Missing endpoint').code,\n );\n }\n\n this.endpoint = config.endpoint;\n\n // Build headers - start with defaults\n this.headers = {\n 'Content-Type': 'application/json',\n };\n\n // Add Authorization if token provided\n if (config.token) {\n this.headers.Authorization = `Bearer ${config.token}`;\n }\n\n // Merge custom headers (can override defaults)\n if (config.headers) {\n Object.assign(this.headers, config.headers);\n }\n }\n\n /**\n * Execute a GraphQL query\n */\n async query<T>(\n query: string,\n variables?: Record<string, unknown>,\n ): Promise<T> {\n return this.execute<T>(query, variables);\n }\n\n /**\n * Execute a GraphQL mutation\n */\n async mutate<T>(\n mutation: string,\n variables?: Record<string, unknown>,\n ): Promise<T> {\n return this.execute<T>(mutation, variables);\n }\n\n /**\n * Execute GraphQL operation\n */\n private async execute<T>(\n operation: string,\n variables?: Record<string, unknown>,\n ): Promise<T> {\n let response: Response;\n\n try {\n response = await fetch(this.endpoint, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ query: operation, variables }),\n });\n } catch (error) {\n throw GraphQLError.networkError(\n `Failed to connect to GraphQL API: ${error instanceof Error ? error.message : 'Unknown error'}`,\n error,\n );\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n throw GraphQLError.fromHTTPStatus(\n response.status,\n `GraphQL error: ${response.statusText}\\n${errorText}`,\n errorText,\n );\n }\n\n const result = (await response.json()) as {\n data?: T;\n errors?: GraphQLErrorDetail[];\n };\n\n if (result.errors && result.errors.length > 0) {\n throw GraphQLError.fromGraphQLErrors(result.errors);\n }\n\n if (!result.data) {\n throw new GraphQLError(\n 'GraphQL response contained no data',\n GraphQLError.fromHTTPStatus(500, 'No data').code,\n );\n }\n\n return result.data;\n }\n}\n","/**\n * GraphQL client factory function\n */\n\nimport { GraphQLClient } from './client.js';\nimport { GraphQLError, GraphQLErrorCode } from './errors.js';\nimport type { GraphQLConfig, IGraphQLClient } from './types.js';\n\n/**\n * Check if value is already a GraphQL client instance\n */\nfunction isGraphQLClientInstance(value: unknown): value is IGraphQLClient {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'query' in value &&\n 'mutate' in value &&\n typeof (value as IGraphQLClient).query === 'function' &&\n typeof (value as IGraphQLClient).mutate === 'function'\n );\n}\n\n/**\n * Get a GraphQL client instance\n *\n * This is the main entry point for creating GraphQL clients.\n * It can accept either a configuration object or an existing client instance.\n *\n * @param options - GraphQL configuration or existing client instance\n * @returns Promise resolving to GraphQL client interface\n *\n * @example\n * ```typescript\n * import { getGraphQLClient } from '@happyvertical/graphql';\n *\n * // Create a GitHub GraphQL client\n * const github = await getGraphQLClient({\n * endpoint: 'https://api.github.com/graphql',\n * token: process.env.GITHUB_TOKEN\n * });\n *\n * // Create a GitLab GraphQL client\n * const gitlab = await getGraphQLClient({\n * endpoint: 'https://gitlab.com/api/graphql',\n * token: process.env.GITLAB_TOKEN\n * });\n *\n * // Custom headers for other APIs\n * const custom = await getGraphQLClient({\n * endpoint: 'https://api.example.com/graphql',\n * headers: {\n * 'X-API-Key': 'my-api-key',\n * 'X-Custom-Header': 'value'\n * }\n * });\n *\n * // Execute a query\n * const result = await github.query<{ viewer: { login: string } }>(`\n * query {\n * viewer {\n * login\n * }\n * }\n * `);\n *\n * // Pass existing instance (returns it unchanged)\n * const sameClient = await getGraphQLClient(github);\n * ```\n */\nexport async function getGraphQLClient(\n options: GraphQLConfig | IGraphQLClient,\n): Promise<IGraphQLClient> {\n // If already a client instance, return it\n if (isGraphQLClientInstance(options)) {\n return options;\n }\n\n // Validate configuration\n if (!options.endpoint) {\n throw new GraphQLError(\n 'GraphQL endpoint is required',\n GraphQLErrorCode.VALIDATION_ERROR,\n );\n }\n\n return new GraphQLClient(options);\n}\n"],"names":["GraphQLErrorCode"],"mappings":"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"}
|
package/metadata.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@happyvertical/graphql",
|
|
3
|
+
"path": "packages/graphql",
|
|
4
|
+
"position": {
|
|
5
|
+
"index": 14,
|
|
6
|
+
"count": 30
|
|
7
|
+
},
|
|
8
|
+
"description": "GitHub GraphQL client for SDK packages",
|
|
9
|
+
"provides": [
|
|
10
|
+
"GitHub GraphQL client for SDK packages"
|
|
11
|
+
],
|
|
12
|
+
"implements": [],
|
|
13
|
+
"requires": {
|
|
14
|
+
"workspace": [],
|
|
15
|
+
"externalHappyVertical": [],
|
|
16
|
+
"external": []
|
|
17
|
+
},
|
|
18
|
+
"dependents": [
|
|
19
|
+
"@happyvertical/projects",
|
|
20
|
+
"@happyvertical/repos"
|
|
21
|
+
],
|
|
22
|
+
"stability": {
|
|
23
|
+
"level": "stable",
|
|
24
|
+
"reason": "Primary package surface is described as implemented and production-oriented."
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"graphql"
|
|
28
|
+
]
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@happyvertical/graphql",
|
|
3
|
+
"version": "0.74.8",
|
|
4
|
+
"description": "GitHub GraphQL client for SDK packages",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"have-graphql-context": "./dist/cli/claude-context.js"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "25.0.10",
|
|
19
|
+
"typescript": "^5.9.3",
|
|
20
|
+
"vite": "7.3.2",
|
|
21
|
+
"vite-plugin-dts": "4.5.4",
|
|
22
|
+
"vitest": "4.1.5"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"AGENT.md",
|
|
29
|
+
"metadata.json"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"registry": "https://registry.npmjs.org",
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/happyvertical/sdk.git",
|
|
38
|
+
"directory": "packages/graphql"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/happyvertical/sdk/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/happyvertical/sdk/tree/main/packages/graphql#readme",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"test": "npx vitest run --passWithNoTests",
|
|
47
|
+
"test:watch": "npx vitest",
|
|
48
|
+
"build": "vite build",
|
|
49
|
+
"build:watch": "vite build --watch",
|
|
50
|
+
"clean": "rm -rf dist",
|
|
51
|
+
"dev": "npm run build:watch & npm run test:watch"
|
|
52
|
+
}
|
|
53
|
+
}
|