infrahub-sdk 0.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/.eslintrc.js +18 -0
- package/.prettierrc +6 -0
- package/LICENSE +201 -0
- package/README.md +47 -0
- package/dist/branch.d.ts +36 -0
- package/dist/branch.js +136 -0
- package/dist/cjs/index.js +65 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +35 -0
- package/dist/constants.d.ts +0 -0
- package/dist/constants.js +1 -0
- package/dist/esm/index.js +32 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/graphql.d.ts +31 -0
- package/dist/graphql.js +174 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +115 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +62 -0
- package/dist/types/client.d.ts +7 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/utils/auth.d.ts +1 -0
- package/dist/types/utils/auth.d.ts.map +1 -0
- package/dist/types/utils/error-handling.d.ts +1 -0
- package/dist/types/utils/error-handling.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/validation.d.ts +1 -0
- package/dist/types/utils/validation.d.ts.map +1 -0
- package/dist/types.d.ts +3144 -0
- package/dist/types.js +6 -0
- package/dist/utils/auth.d.ts +0 -0
- package/dist/utils/auth.js +1 -0
- package/dist/utils/error-handling.d.ts +0 -0
- package/dist/utils/error-handling.js +1 -0
- package/dist/utils/index.d.ts +0 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/validation.d.ts +0 -0
- package/dist/utils/validation.js +1 -0
- package/eslint.config.mjs +9 -0
- package/jest.config.js +6 -0
- package/package.json +33 -0
- package/src/branch.ts +161 -0
- package/src/graphql.ts +266 -0
- package/src/index.test.ts +74 -0
- package/src/index.ts +144 -0
- package/src/types.ts +3169 -0
- package/tsconfig.json +14 -0
package/dist/types.js
ADDED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "infrahub-sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A client SDK for the Infrahub API.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "jest --config=jest.config.js --runInBand",
|
|
10
|
+
"format": "prettier --write \"src/**/*.{ts,js,json}\"",
|
|
11
|
+
"lint": "eslint --ext .ts,.js src"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"sdk",
|
|
15
|
+
"infrahub"
|
|
16
|
+
],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"graphql-request": "^6.1.0",
|
|
21
|
+
"openapi-fetch": "^0.9.4"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@eslint/js": "^9.31.0",
|
|
25
|
+
"eslint": "^9.31.0",
|
|
26
|
+
"eslint-config-prettier": "^10.1.5",
|
|
27
|
+
"eslint-plugin-prettier": "^5.5.1",
|
|
28
|
+
"prettier": "3.6.2",
|
|
29
|
+
"ts-jest": "^29.4.0",
|
|
30
|
+
"typescript": "^5.8.3",
|
|
31
|
+
"typescript-eslint": "^8.37.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/branch.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { InfrahubClient, gql } from './index';
|
|
2
|
+
import { Mutation } from './graphql';
|
|
3
|
+
|
|
4
|
+
interface Branch {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
origin_branch: string;
|
|
9
|
+
branched_from: string;
|
|
10
|
+
is_default: boolean;
|
|
11
|
+
sync_with_git: boolean;
|
|
12
|
+
has_schema_changes: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BranchCreateInput {
|
|
16
|
+
name: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
sync_with_git?: boolean;
|
|
19
|
+
wait_until_completion?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class BranchNotFoundError extends Error {
|
|
23
|
+
constructor(identifier: string) {
|
|
24
|
+
super(`Branch not found: ${identifier}`);
|
|
25
|
+
this.name = 'BranchNotFoundError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const MUTATION_QUERY_TASK = { ok: null, task: { id: null } };
|
|
30
|
+
const MUTATION_QUERY_DATA = {
|
|
31
|
+
ok: null,
|
|
32
|
+
object: {
|
|
33
|
+
id: null,
|
|
34
|
+
name: null,
|
|
35
|
+
description: null,
|
|
36
|
+
origin_branch: null,
|
|
37
|
+
branched_from: null,
|
|
38
|
+
is_default: null,
|
|
39
|
+
sync_with_git: null,
|
|
40
|
+
has_schema_changes: null
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// InfrahubBranchManager class to manage branches via GraphQL
|
|
45
|
+
export class InfrahubBranchManager {
|
|
46
|
+
private client: InfrahubClient;
|
|
47
|
+
|
|
48
|
+
constructor(client: InfrahubClient) {
|
|
49
|
+
this.client = client;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Fetches all branches using GraphQL and returns an object mapping branch names to branch data.
|
|
54
|
+
*/
|
|
55
|
+
async all(): Promise<Record<string, Branch>> {
|
|
56
|
+
const query = gql`
|
|
57
|
+
query BranchQuery {
|
|
58
|
+
Branch {
|
|
59
|
+
id
|
|
60
|
+
name
|
|
61
|
+
description
|
|
62
|
+
origin_branch
|
|
63
|
+
branched_from
|
|
64
|
+
is_default
|
|
65
|
+
sync_with_git
|
|
66
|
+
has_schema_changes
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
const response = await this.client.executeGraphQL(query);
|
|
71
|
+
const branches: Branch[] = response.Branch || [];
|
|
72
|
+
const result: Record<string, Branch> = {};
|
|
73
|
+
for (const branch of branches) {
|
|
74
|
+
result[branch.name] = branch;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Fetches a specific branch by name.
|
|
81
|
+
* @param branchName The name of the branch to fetch.
|
|
82
|
+
*/
|
|
83
|
+
async get(branchName: string): Promise<Branch | null> {
|
|
84
|
+
const query = gql`
|
|
85
|
+
query BranchQuery($name: String!) {
|
|
86
|
+
Branch(name: $name) {
|
|
87
|
+
id
|
|
88
|
+
name
|
|
89
|
+
description
|
|
90
|
+
origin_branch
|
|
91
|
+
branched_from
|
|
92
|
+
is_default
|
|
93
|
+
sync_with_git
|
|
94
|
+
has_schema_changes
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
const response = await this.client.executeGraphQL(query, {
|
|
99
|
+
name: branchName
|
|
100
|
+
});
|
|
101
|
+
const branchArr: Branch[] = response.Branch || [];
|
|
102
|
+
if (!branchArr.length) {
|
|
103
|
+
throw new BranchNotFoundError(branchName);
|
|
104
|
+
}
|
|
105
|
+
return branchArr[0];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async create(input: BranchCreateInput): Promise<Branch> {
|
|
109
|
+
const inputData = {
|
|
110
|
+
background_execution: input.wait_until_completion,
|
|
111
|
+
data: {
|
|
112
|
+
name: input.name,
|
|
113
|
+
description: input.description,
|
|
114
|
+
sync_with_git: input.sync_with_git
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// set mutation query to MUTATION_QUERY_TASK if brackground_execution is true
|
|
119
|
+
const mutationQuery = input.wait_until_completion
|
|
120
|
+
? MUTATION_QUERY_TASK
|
|
121
|
+
: MUTATION_QUERY_DATA;
|
|
122
|
+
|
|
123
|
+
const mutation = new Mutation({
|
|
124
|
+
mutation: 'BranchCreate',
|
|
125
|
+
inputData: inputData,
|
|
126
|
+
query: mutationQuery,
|
|
127
|
+
name: 'CreateBranch'
|
|
128
|
+
});
|
|
129
|
+
// You may want to remove this log in production
|
|
130
|
+
console.log(mutation.render());
|
|
131
|
+
const response = await this.client.executeGraphQL(mutation.render(), {
|
|
132
|
+
input: inputData
|
|
133
|
+
});
|
|
134
|
+
// Adjust the response path as needed based on your API
|
|
135
|
+
const branchData =
|
|
136
|
+
response.BranchCreate?.object || response.BranchCreate?.task || null;
|
|
137
|
+
if (!branchData) {
|
|
138
|
+
throw new Error('Branch creation failed');
|
|
139
|
+
}
|
|
140
|
+
return branchData as Branch;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async delete(branchName: string): Promise<boolean> {
|
|
144
|
+
const inputData = {
|
|
145
|
+
data: {
|
|
146
|
+
name: branchName
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const mutation = new Mutation({
|
|
150
|
+
mutation: 'BranchDelete',
|
|
151
|
+
inputData: inputData,
|
|
152
|
+
query: { ok: null },
|
|
153
|
+
name: 'DeleteBranch'
|
|
154
|
+
});
|
|
155
|
+
const response = await this.client.executeGraphQL(mutation.render(), {
|
|
156
|
+
input: inputData
|
|
157
|
+
});
|
|
158
|
+
console.log(response);
|
|
159
|
+
return !!(response.BranchDelete && response.BranchDelete.ok);
|
|
160
|
+
}
|
|
161
|
+
}
|
package/src/graphql.ts
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
export type VariableType =
|
|
2
|
+
| string
|
|
3
|
+
| number
|
|
4
|
+
| boolean
|
|
5
|
+
| null
|
|
6
|
+
| undefined
|
|
7
|
+
| VariableType[]
|
|
8
|
+
| Record<string, any>;
|
|
9
|
+
|
|
10
|
+
export function convertToGraphqlAsString(
|
|
11
|
+
value: VariableType,
|
|
12
|
+
convertEnum: boolean = false
|
|
13
|
+
): string {
|
|
14
|
+
if (typeof value === 'string' && value.startsWith('$')) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (
|
|
18
|
+
typeof value === 'object' &&
|
|
19
|
+
value &&
|
|
20
|
+
'constructor' in value &&
|
|
21
|
+
value.constructor.name === 'Enum'
|
|
22
|
+
) {
|
|
23
|
+
// TypeScript enums are not runtime objects, so you may need to handle this differently
|
|
24
|
+
return convertEnum
|
|
25
|
+
? convertToGraphqlAsString((value as any).value, true)
|
|
26
|
+
: (value as any).name;
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === 'string') {
|
|
29
|
+
return `"${value}"`;
|
|
30
|
+
}
|
|
31
|
+
if (typeof value === 'boolean') {
|
|
32
|
+
return value ? 'true' : 'false';
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
const valuesAsString = value.map((item) =>
|
|
36
|
+
convertToGraphqlAsString(item, convertEnum)
|
|
37
|
+
);
|
|
38
|
+
return `[${valuesAsString.join(', ')}]`;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === 'object' && value !== null) {
|
|
41
|
+
const entries = Object.entries(value).map(
|
|
42
|
+
([key, val]) => `${key}: ${convertToGraphqlAsString(val, convertEnum)}`
|
|
43
|
+
);
|
|
44
|
+
return `{ ${entries.join(', ')} }`;
|
|
45
|
+
}
|
|
46
|
+
return String(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const VARIABLE_TYPE_MAPPING: [any, string][] = [
|
|
50
|
+
[String, 'String!'],
|
|
51
|
+
[Number, 'Int!'],
|
|
52
|
+
[Boolean, 'Boolean!']
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
export function renderVariablesToString(data: Record<string, any>): string {
|
|
56
|
+
const varsDict: Record<string, string> = {};
|
|
57
|
+
for (const [key, value] of Object.entries(data)) {
|
|
58
|
+
for (const [classType, varString] of VARIABLE_TYPE_MAPPING) {
|
|
59
|
+
if (value === classType) {
|
|
60
|
+
varsDict[`$${key}`] = varString;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return Object.entries(varsDict)
|
|
65
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
66
|
+
.join(', ');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function renderQueryBlock(
|
|
70
|
+
data: Record<string, any>,
|
|
71
|
+
offset: number = 4,
|
|
72
|
+
indentation: number = 4,
|
|
73
|
+
convertEnum: boolean = false
|
|
74
|
+
): string[] {
|
|
75
|
+
const FILTERS_KEY = '@filters';
|
|
76
|
+
const ALIAS_KEY = '@alias';
|
|
77
|
+
const KEYWORDS_TO_SKIP = [FILTERS_KEY, ALIAS_KEY];
|
|
78
|
+
|
|
79
|
+
const offsetStr = ' '.repeat(offset);
|
|
80
|
+
const lines: string[] = [];
|
|
81
|
+
for (const [key, value] of Object.entries(data)) {
|
|
82
|
+
if (KEYWORDS_TO_SKIP.includes(key)) continue;
|
|
83
|
+
if (value === null || value === undefined) {
|
|
84
|
+
lines.push(`${offsetStr}${key}`);
|
|
85
|
+
} else if (
|
|
86
|
+
typeof value === 'object' &&
|
|
87
|
+
value !== null &&
|
|
88
|
+
Object.keys(value).length === 1 &&
|
|
89
|
+
value[ALIAS_KEY]
|
|
90
|
+
) {
|
|
91
|
+
lines.push(`${offsetStr}${value[ALIAS_KEY]}: ${key}`);
|
|
92
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
93
|
+
const keyStr = value[ALIAS_KEY] ? `${value[ALIAS_KEY]}: ${key}` : key;
|
|
94
|
+
if (value[FILTERS_KEY]) {
|
|
95
|
+
const filtersStr = Object.entries(value[FILTERS_KEY])
|
|
96
|
+
.map(
|
|
97
|
+
([k2, v2]) =>
|
|
98
|
+
`${k2}: ${convertToGraphqlAsString(v2 as VariableType, convertEnum)}`
|
|
99
|
+
)
|
|
100
|
+
.join(', ');
|
|
101
|
+
lines.push(`${offsetStr}${keyStr}(${filtersStr}) {`);
|
|
102
|
+
} else {
|
|
103
|
+
lines.push(`${offsetStr}${keyStr} {`);
|
|
104
|
+
}
|
|
105
|
+
lines.push(
|
|
106
|
+
...renderQueryBlock(
|
|
107
|
+
value,
|
|
108
|
+
offset + indentation,
|
|
109
|
+
indentation,
|
|
110
|
+
convertEnum
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
lines.push(offsetStr + '}');
|
|
114
|
+
} else {
|
|
115
|
+
lines.push(`${offsetStr}${key}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return lines;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function renderInputBlock(
|
|
122
|
+
data: Record<string, any>,
|
|
123
|
+
offset: number = 4,
|
|
124
|
+
indentation: number = 4,
|
|
125
|
+
convertEnum: boolean = false
|
|
126
|
+
): string[] {
|
|
127
|
+
const offsetStr = ' '.repeat(offset);
|
|
128
|
+
const lines: string[] = [];
|
|
129
|
+
for (const [key, value] of Object.entries(data)) {
|
|
130
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
131
|
+
lines.push(`${offsetStr}${key}: {`);
|
|
132
|
+
lines.push(
|
|
133
|
+
...renderInputBlock(
|
|
134
|
+
value,
|
|
135
|
+
offset + indentation,
|
|
136
|
+
indentation,
|
|
137
|
+
convertEnum
|
|
138
|
+
)
|
|
139
|
+
);
|
|
140
|
+
lines.push(offsetStr + '}');
|
|
141
|
+
} else if (Array.isArray(value)) {
|
|
142
|
+
lines.push(`${offsetStr}${key}: [`);
|
|
143
|
+
for (const item of value) {
|
|
144
|
+
if (typeof item === 'object' && item !== null) {
|
|
145
|
+
lines.push(`${offsetStr}${' '.repeat(indentation)}{`);
|
|
146
|
+
lines.push(
|
|
147
|
+
...renderInputBlock(
|
|
148
|
+
item,
|
|
149
|
+
offset + indentation * 2,
|
|
150
|
+
indentation,
|
|
151
|
+
convertEnum
|
|
152
|
+
)
|
|
153
|
+
);
|
|
154
|
+
lines.push(`${offsetStr}${' '.repeat(indentation)}},`);
|
|
155
|
+
} else {
|
|
156
|
+
lines.push(
|
|
157
|
+
`${offsetStr}${' '.repeat(indentation)}${convertToGraphqlAsString(item, convertEnum)},`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
lines.push(offsetStr + ']');
|
|
162
|
+
} else {
|
|
163
|
+
lines.push(
|
|
164
|
+
`${offsetStr}${key}: ${convertToGraphqlAsString(value, convertEnum)}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return lines;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export class BaseGraphQLQuery {
|
|
172
|
+
queryType: string = 'not-defined';
|
|
173
|
+
indentation: number = 4;
|
|
174
|
+
query: Record<string, any>;
|
|
175
|
+
variables?: Record<string, any>;
|
|
176
|
+
name: string;
|
|
177
|
+
|
|
178
|
+
constructor(
|
|
179
|
+
query: Record<string, any>,
|
|
180
|
+
variables?: Record<string, any>,
|
|
181
|
+
name?: string
|
|
182
|
+
) {
|
|
183
|
+
this.query = query;
|
|
184
|
+
this.variables = variables;
|
|
185
|
+
this.name = name || '';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
renderFirstLine(): string {
|
|
189
|
+
let firstLine = this.queryType;
|
|
190
|
+
if (this.name) {
|
|
191
|
+
firstLine += ' ' + this.name;
|
|
192
|
+
}
|
|
193
|
+
if (this.variables) {
|
|
194
|
+
firstLine += ` (${renderVariablesToString(this.variables)})`;
|
|
195
|
+
}
|
|
196
|
+
firstLine += ' {';
|
|
197
|
+
return firstLine;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export class Query extends BaseGraphQLQuery {
|
|
202
|
+
queryType = 'query';
|
|
203
|
+
|
|
204
|
+
render(convertEnum: boolean = false): string {
|
|
205
|
+
const lines: string[] = [this.renderFirstLine()];
|
|
206
|
+
lines.push(
|
|
207
|
+
...renderQueryBlock(
|
|
208
|
+
this.query,
|
|
209
|
+
this.indentation,
|
|
210
|
+
this.indentation,
|
|
211
|
+
convertEnum
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
lines.push('}');
|
|
215
|
+
return '\n' + lines.join('\n') + '\n';
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export class Mutation extends BaseGraphQLQuery {
|
|
220
|
+
queryType = 'mutation';
|
|
221
|
+
inputData: Record<string, any>;
|
|
222
|
+
mutation: string;
|
|
223
|
+
|
|
224
|
+
constructor({
|
|
225
|
+
mutation,
|
|
226
|
+
inputData,
|
|
227
|
+
query,
|
|
228
|
+
variables,
|
|
229
|
+
name
|
|
230
|
+
}: {
|
|
231
|
+
mutation: string;
|
|
232
|
+
inputData: Record<string, any>;
|
|
233
|
+
query: Record<string, any>;
|
|
234
|
+
variables?: Record<string, any>;
|
|
235
|
+
name?: string;
|
|
236
|
+
}) {
|
|
237
|
+
super(query, variables, name);
|
|
238
|
+
this.inputData = inputData;
|
|
239
|
+
this.mutation = mutation;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
render(convertEnum: boolean = false): string {
|
|
243
|
+
const lines: string[] = [this.renderFirstLine()];
|
|
244
|
+
lines.push(' '.repeat(this.indentation) + `${this.mutation}(`);
|
|
245
|
+
lines.push(
|
|
246
|
+
...renderInputBlock(
|
|
247
|
+
this.inputData,
|
|
248
|
+
this.indentation,
|
|
249
|
+
this.indentation * 2,
|
|
250
|
+
convertEnum
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
lines.push(' '.repeat(this.indentation) + '){');
|
|
254
|
+
lines.push(
|
|
255
|
+
...renderQueryBlock(
|
|
256
|
+
this.query,
|
|
257
|
+
this.indentation,
|
|
258
|
+
this.indentation * 2,
|
|
259
|
+
convertEnum
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
lines.push(' '.repeat(this.indentation) + '}');
|
|
263
|
+
lines.push('}');
|
|
264
|
+
return '\n' + lines.join('\n') + '\n';
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { InfrahubClient, InfrahubClientOptions } from './index';
|
|
2
|
+
import { GraphQLClient } from 'graphql-request';
|
|
3
|
+
// Import expect for type checking and editor support
|
|
4
|
+
import { beforeEach, describe, expect, it, jest } from '@jest/globals';
|
|
5
|
+
|
|
6
|
+
describe('InfrahubClient', () => {
|
|
7
|
+
const baseURL = 'https://example.com';
|
|
8
|
+
const token = 'test-token';
|
|
9
|
+
let client: InfrahubClient;
|
|
10
|
+
|
|
11
|
+
// Initialize the client before each test
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
const options: InfrahubClientOptions = {
|
|
15
|
+
address: baseURL,
|
|
16
|
+
token: token
|
|
17
|
+
};
|
|
18
|
+
client = new InfrahubClient(options);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should initialize with baseURL and token', () => {
|
|
22
|
+
expect((client as any).baseUrl).toBe(baseURL);
|
|
23
|
+
expect((client as any).token).toBe(token);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should set auth token and update GraphQL headers', () => {
|
|
27
|
+
const newToken = 'new-token';
|
|
28
|
+
client.setAuthToken(newToken);
|
|
29
|
+
expect((client as any).token).toBe(newToken);
|
|
30
|
+
// GraphQLClient headers are private, so we check no error is thrown
|
|
31
|
+
expect(() => client.executeGraphQL('{ __typename }')).not.toThrow();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should call graphqlQuery and handle errors', async () => {
|
|
35
|
+
const mockRequest = jest
|
|
36
|
+
.fn()
|
|
37
|
+
.mockImplementationOnce(() => Promise.reject(new Error('GraphQL error')));
|
|
38
|
+
(client as any).graphqlClient.request = mockRequest;
|
|
39
|
+
const consoleErrorSpy = jest
|
|
40
|
+
.spyOn(console, 'error')
|
|
41
|
+
.mockImplementation(() => {});
|
|
42
|
+
await expect(client.executeGraphQL('{ test }')).rejects.toThrow(
|
|
43
|
+
'GraphQL error'
|
|
44
|
+
);
|
|
45
|
+
consoleErrorSpy.mockRestore();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should initialize rest client with baseUrl', () => {
|
|
49
|
+
expect((client as any).rest).toBeDefined();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should have a GraphQL client initialized', () => {
|
|
53
|
+
expect((client as any).graphqlClient).toBeInstanceOf(GraphQLClient);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should have a rest client initialized', () => {
|
|
57
|
+
expect((client as any).rest).toBeDefined();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should have a default branch set', () => {
|
|
61
|
+
expect((client as any).defaultBranch).toBe('main');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should have a graphqlUrl method that returns the correct URL', () => {
|
|
65
|
+
const url = (client as any)._graphqlUrl();
|
|
66
|
+
expect(url).toBe(`${baseURL}/graphql/main`);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('graphqlUrl should return the correct URL for a specific branch', () => {
|
|
70
|
+
const branchName = 'test-branch';
|
|
71
|
+
const url = (client as any)._graphqlUrl(branchName);
|
|
72
|
+
expect(url).toBe(`${baseURL}/graphql/${branchName}`);
|
|
73
|
+
});
|
|
74
|
+
});
|