infrahub-sdk 0.0.2 → 0.0.5

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 (55) hide show
  1. package/.github/workflows/publish.yml +1 -0
  2. package/dist/branch.d.ts +20 -0
  3. package/dist/branch.js +105 -0
  4. package/dist/cjs/index.js +65 -0
  5. package/dist/cjs/index.js.map +7 -0
  6. package/dist/client.d.ts +6 -0
  7. package/dist/client.js +35 -0
  8. package/dist/constants.d.ts +0 -0
  9. package/dist/constants.js +1 -0
  10. package/dist/esm/index.js +32 -0
  11. package/dist/esm/index.js.map +7 -0
  12. package/dist/graphql/branch.d.ts +23 -0
  13. package/dist/graphql/branch.js +35 -0
  14. package/dist/graphql/client.d.ts +71 -0
  15. package/dist/graphql/client.js +82 -0
  16. package/dist/graphql.d.ts +31 -0
  17. package/dist/graphql.js +174 -0
  18. package/dist/index.d.ts +52 -0
  19. package/dist/index.js +128 -0
  20. package/dist/index.test.d.ts +1 -0
  21. package/dist/index.test.js +62 -0
  22. package/dist/types/client.d.ts +7 -0
  23. package/dist/types/client.d.ts.map +1 -0
  24. package/dist/types/constants.d.ts +1 -0
  25. package/dist/types/constants.d.ts.map +1 -0
  26. package/dist/types/index.d.ts +2 -0
  27. package/dist/types/index.d.ts.map +1 -0
  28. package/dist/types/utils/auth.d.ts +1 -0
  29. package/dist/types/utils/auth.d.ts.map +1 -0
  30. package/dist/types/utils/error-handling.d.ts +1 -0
  31. package/dist/types/utils/error-handling.d.ts.map +1 -0
  32. package/dist/types/utils/index.d.ts +1 -0
  33. package/dist/types/utils/index.d.ts.map +1 -0
  34. package/dist/types/utils/validation.d.ts +1 -0
  35. package/dist/types/utils/validation.d.ts.map +1 -0
  36. package/dist/types.d.ts +3144 -0
  37. package/dist/types.js +6 -0
  38. package/dist/utils/auth.d.ts +0 -0
  39. package/dist/utils/auth.js +1 -0
  40. package/dist/utils/error-handling.d.ts +0 -0
  41. package/dist/utils/error-handling.js +1 -0
  42. package/dist/utils/index.d.ts +0 -0
  43. package/dist/utils/index.js +1 -0
  44. package/dist/utils/validation.d.ts +0 -0
  45. package/dist/utils/validation.js +1 -0
  46. package/package.json +4 -2
  47. package/src/branch.ts +130 -0
  48. package/src/graphql/branch.ts +61 -0
  49. package/src/graphql/client.ts +158 -0
  50. package/src/graphql.ts +266 -0
  51. package/src/index.ts +36 -2
  52. package/test/main.js +11 -0
  53. package/test/package-lock.json +1044 -0
  54. package/test/package.json +14 -0
  55. package/tsconfig.json +1 -1
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * This file was auto-generated by openapi-typescript.
4
+ * Do not make direct changes to the file.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infrahub-sdk",
3
- "version": "0.0.2",
3
+ "version": "0.0.5",
4
4
  "description": "A client SDK for the Infrahub API.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,8 +17,10 @@
17
17
  "author": "",
18
18
  "license": "Apache-2.0",
19
19
  "dependencies": {
20
+ "@graphql-codegen/typed-document-node": "^5.1.2",
20
21
  "graphql-request": "^6.1.0",
21
- "openapi-fetch": "^0.9.4"
22
+ "openapi-fetch": "^0.9.4",
23
+ "openapi-typescript-fetch": "^2.2.1"
22
24
  },
23
25
  "devDependencies": {
24
26
  "@eslint/js": "^9.31.0",
package/src/branch.ts ADDED
@@ -0,0 +1,130 @@
1
+ import { InfrahubClient, gql } from './index';
2
+ import { Mutation } from './graphql';
3
+ import {
4
+ BranchAllQuery,
5
+ BranchResponse,
6
+ BranchGetQuery,
7
+ BranchCreateInput
8
+ } from './graphql/branch';
9
+
10
+ export class BranchNotFoundError extends Error {
11
+ constructor(identifier: string) {
12
+ super(`Branch not found: ${identifier}`);
13
+ this.name = 'BranchNotFoundError';
14
+ }
15
+ }
16
+
17
+ const MUTATION_QUERY_TASK = { ok: null, task: { id: null } };
18
+ const MUTATION_QUERY_DATA = {
19
+ ok: null,
20
+ object: {
21
+ id: null,
22
+ name: null,
23
+ description: null,
24
+ origin_branch: null,
25
+ branched_from: null,
26
+ is_default: null,
27
+ sync_with_git: null,
28
+ has_schema_changes: null
29
+ }
30
+ };
31
+
32
+ // InfrahubBranchManager class to manage branches via GraphQL
33
+ export class InfrahubBranchManager {
34
+ private client: InfrahubClient;
35
+
36
+ constructor(client: InfrahubClient) {
37
+ this.client = client;
38
+ }
39
+
40
+ /**
41
+ * Fetches all branches using GraphQL and returns an object mapping branch names to branch data.
42
+ */
43
+ async all(): Promise<Record<string, BranchResponse>> {
44
+ const response = await this.client.executeGraphQL<
45
+ {
46
+ Branch: BranchResponse[];
47
+ },
48
+ Record<string, never>
49
+ >(BranchAllQuery);
50
+ const branches: BranchResponse[] = response.Branch || [];
51
+ const result: Record<string, BranchResponse> = {};
52
+ branches.forEach((branch) => {
53
+ result[branch.name] = branch;
54
+ });
55
+ return result;
56
+ }
57
+
58
+ /**
59
+ * Fetches a specific branch by name.
60
+ * @param branchName The name of the branch to fetch.
61
+ */
62
+ async get(branchName: string): Promise<BranchResponse | null> {
63
+ const response = await this.client.executeGraphQL<
64
+ {
65
+ Branch: BranchResponse[];
66
+ },
67
+ Record<string, any>
68
+ >(BranchGetQuery, {
69
+ name: branchName
70
+ });
71
+ const branchArr: BranchResponse[] = response.Branch || [];
72
+ if (!branchArr.length) {
73
+ throw new BranchNotFoundError(branchName);
74
+ }
75
+ return branchArr[0];
76
+ }
77
+
78
+ async create(input: BranchCreateInput): Promise<BranchResponse> {
79
+ const inputData = {
80
+ background_execution: input.wait_until_completion,
81
+ data: {
82
+ name: input.name,
83
+ description: input.description,
84
+ sync_with_git: input.sync_with_git
85
+ }
86
+ };
87
+
88
+ // set mutation query to MUTATION_QUERY_TASK if brackground_execution is true
89
+ const mutationQuery = input.wait_until_completion
90
+ ? MUTATION_QUERY_TASK
91
+ : MUTATION_QUERY_DATA;
92
+
93
+ const mutation = new Mutation({
94
+ mutation: 'BranchCreate',
95
+ inputData: inputData,
96
+ query: mutationQuery,
97
+ name: 'CreateBranch'
98
+ });
99
+
100
+ console.log(mutation.render());
101
+
102
+ const response = await this.client.executeGraphQL(mutation.render());
103
+ // Adjust the response path as needed based on your API
104
+ const branchData =
105
+ response.BranchCreate?.object || response.BranchCreate?.task || null;
106
+ if (!branchData) {
107
+ throw new Error('Branch creation failed');
108
+ }
109
+ return branchData as BranchResponse;
110
+ }
111
+
112
+ async delete(branchName: string): Promise<boolean> {
113
+ const inputData = {
114
+ data: {
115
+ name: branchName
116
+ }
117
+ };
118
+ const mutation = new Mutation({
119
+ mutation: 'BranchDelete',
120
+ inputData: inputData,
121
+ query: { ok: null },
122
+ name: 'DeleteBranch'
123
+ });
124
+ const response = await this.client.executeGraphQL(mutation.render(), {
125
+ input: inputData
126
+ });
127
+ console.log(response);
128
+ return !!(response.BranchDelete && response.BranchDelete.ok);
129
+ }
130
+ }
@@ -0,0 +1,61 @@
1
+ import { gql } from 'graphql-request';
2
+ import { parse } from 'graphql';
3
+ import { TypedDocumentNode } from '@graphql-typed-document-node/core';
4
+
5
+ const BranchAllQueryDocument = parse(gql`
6
+ query BranchAllQuery {
7
+ Branch {
8
+ id
9
+ name
10
+ description
11
+ origin_branch
12
+ branched_from
13
+ is_default
14
+ sync_with_git
15
+ has_schema_changes
16
+ }
17
+ }
18
+ `);
19
+
20
+ const BranchGetQueryDocument = parse(gql`
21
+ query BranchGetQuery($name: String!) {
22
+ Branch(name: $name) {
23
+ id
24
+ name
25
+ description
26
+ origin_branch
27
+ branched_from
28
+ is_default
29
+ sync_with_git
30
+ has_schema_changes
31
+ }
32
+ }
33
+ `);
34
+
35
+ export interface BranchCreateInput {
36
+ name: string;
37
+ description?: string;
38
+ sync_with_git?: boolean;
39
+ wait_until_completion?: boolean;
40
+ }
41
+
42
+ export interface BranchResponse {
43
+ id: string;
44
+ name: string;
45
+ description: string;
46
+ origin_branch: string;
47
+ branched_from: string;
48
+ is_default: boolean;
49
+ sync_with_git: boolean;
50
+ has_schema_changes: boolean;
51
+ }
52
+
53
+ export const BranchAllQuery: TypedDocumentNode<
54
+ { Branch: BranchResponse[] },
55
+ Record<any, never>
56
+ > = BranchAllQueryDocument;
57
+
58
+ export const BranchGetQuery: TypedDocumentNode<
59
+ { Branch: BranchResponse[] },
60
+ Record<any, any>
61
+ > = BranchGetQueryDocument;
@@ -0,0 +1,158 @@
1
+ import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
2
+ import { parse } from 'graphql';
3
+ import { gql } from 'graphql-request';
4
+ import { InfrahubClient } from '..';
5
+
6
+ const InfrahubInfoDocument = parse(gql`
7
+ query InfrahubInfo {
8
+ InfrahubInfo {
9
+ version
10
+ }
11
+ }
12
+ `);
13
+
14
+ export interface InfrahubInfoResponse {
15
+ InfrahubInfo: {
16
+ version: string;
17
+ };
18
+ }
19
+
20
+ export const InfrahubInfoQuery: TypedDocumentNode<
21
+ InfrahubInfoResponse,
22
+ Record<any, never>
23
+ > = InfrahubInfoDocument;
24
+
25
+ const InfrahubUserDocument = parse(gql`
26
+ query GET_PROFILE_DETAILS {
27
+ AccountProfile {
28
+ id
29
+ display_label
30
+ account_type {
31
+ value
32
+ __typename
33
+ updated_at
34
+ }
35
+ status {
36
+ label
37
+ value
38
+ updated_at
39
+ __typename
40
+ }
41
+ description {
42
+ value
43
+ updated_at
44
+ __typename
45
+ }
46
+ label {
47
+ value
48
+ updated_at
49
+ __typename
50
+ }
51
+ member_of_groups {
52
+ count
53
+ edges {
54
+ node {
55
+ display_label
56
+ group_type {
57
+ value
58
+ }
59
+ ... on CoreAccountGroup {
60
+ id
61
+ roles {
62
+ count
63
+ edges {
64
+ node {
65
+ permissions {
66
+ count
67
+ edges {
68
+ node {
69
+ display_label
70
+ identifier {
71
+ value
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ display_label
80
+ }
81
+ }
82
+ }
83
+ }
84
+ __typename
85
+ name {
86
+ value
87
+ updated_at
88
+ __typename
89
+ }
90
+ }
91
+ }
92
+ `);
93
+
94
+ export interface InfrahubUserResponse {
95
+ AccountProfile: {
96
+ id: string;
97
+ display_label: string;
98
+ account_type: {
99
+ value: string;
100
+ __typename: string;
101
+ updated_at: string;
102
+ };
103
+ status: {
104
+ label: string;
105
+ value: string;
106
+ updated_at: string;
107
+ __typename: string;
108
+ };
109
+ description: {
110
+ value: string;
111
+ updated_at: string;
112
+ __typename: string;
113
+ };
114
+ label: {
115
+ value: string;
116
+ updated_at: string;
117
+ __typename: string;
118
+ };
119
+ member_of_groups: {
120
+ count: number;
121
+ edges: Array<{
122
+ node: {
123
+ display_label: string;
124
+ group_type: { value: string };
125
+ id?: string; // Optional for CoreAccountGroup
126
+ roles?: {
127
+ count: number;
128
+ edges: Array<{
129
+ node: {
130
+ permissions?: {
131
+ count: number;
132
+ edges: Array<{
133
+ node: {
134
+ display_label: string;
135
+ identifier?: { value: string };
136
+ };
137
+ }>;
138
+ };
139
+ };
140
+ }>;
141
+ };
142
+ };
143
+ }>;
144
+ __typename?: string; // Optional, depending on the API response
145
+ };
146
+ name: {
147
+ value: string;
148
+ updated_at: string;
149
+ __typename?: string; // Optional, depending on the API response
150
+ };
151
+ };
152
+ }
153
+
154
+ export const InfrahubUserQuery: TypedDocumentNode<
155
+ InfrahubUserResponse,
156
+ Record<any, never>
157
+ > = InfrahubUserDocument;
158
+
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
+ }