@pcg/graphql-kit 1.0.0-alpha.1 → 1.0.0-alpha.2
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/dist/index.d.ts +43 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/package.json +4 -1
- package/.turbo/turbo-lint.log +0 -4
- package/CHANGELOG.md +0 -7
- package/eslint.config.js +0 -5
- package/src/graphql-error-log.ts +0 -105
- package/src/index.ts +0 -3
- package/src/tools.ts +0 -20
- package/src/types.ts +0 -32
- package/tests/graphql-error-log.test.ts +0 -219
- package/tests/tools.test.ts +0 -152
- package/tsconfig.json +0 -9
- package/tsconfig.lib.json +0 -9
- package/tsdown.config.ts +0 -11
- package/vitest.config.ts +0 -19
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { GraphQLError, GraphQLFormattedError } from "graphql";
|
|
2
|
+
import { ApolloError } from "@apollo/client/core";
|
|
3
|
+
import { ErrorResponse } from "@apollo/client/link/error";
|
|
4
|
+
|
|
5
|
+
//#region src/graphql-error-log.d.ts
|
|
6
|
+
declare const getErrorMessages: (error: ErrorResponse | ApolloError) => string[];
|
|
7
|
+
declare const logErrorMessages: (error: ApolloError | ErrorResponse, printStack?: boolean) => void;
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/types.d.ts
|
|
10
|
+
interface ErrorStackItem {
|
|
11
|
+
key: string;
|
|
12
|
+
message: string;
|
|
13
|
+
context: Record<string, unknown>;
|
|
14
|
+
stacktrace?: string;
|
|
15
|
+
}
|
|
16
|
+
declare class NestJsGraphQLError extends GraphQLError {
|
|
17
|
+
extensions: {
|
|
18
|
+
context: {
|
|
19
|
+
scope?: string;
|
|
20
|
+
action?: string;
|
|
21
|
+
requestId?: string;
|
|
22
|
+
userId?: string;
|
|
23
|
+
[attributeName: string]: unknown;
|
|
24
|
+
};
|
|
25
|
+
key: string;
|
|
26
|
+
statusCode: number;
|
|
27
|
+
errorStack?: ErrorStackItem[];
|
|
28
|
+
format: 'NESTJS';
|
|
29
|
+
[attributeName: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
type NestJsGraphQLErrors = readonly NestJsGraphQLError[];
|
|
33
|
+
declare class NestJsApolloError extends ApolloError {
|
|
34
|
+
graphQLErrors: NestJsGraphQLErrors;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/tools.d.ts
|
|
38
|
+
declare const isNestJsApolloError: (err: GraphQLFormattedError) => err is NestJsApolloError;
|
|
39
|
+
declare const isNestJsGraphQLError: (err: GraphQLFormattedError) => err is NestJsGraphQLError;
|
|
40
|
+
declare const getFirstNestJsGraphQLError: (err: GraphQLFormattedError) => NestJsGraphQLError | null;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { ErrorStackItem, NestJsApolloError, NestJsGraphQLError, NestJsGraphQLErrors, getErrorMessages, getFirstNestJsGraphQLError, isNestJsApolloError, isNestJsGraphQLError, logErrorMessages };
|
|
43
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { GraphQLError, print } from "graphql";
|
|
2
|
+
import { ApolloError } from "@apollo/client/core";
|
|
3
|
+
|
|
4
|
+
//#region src/tools.ts
|
|
5
|
+
const isNestJsApolloError = (err) => {
|
|
6
|
+
return Object.prototype.hasOwnProperty.call(err, "graphQLErrors");
|
|
7
|
+
};
|
|
8
|
+
const isNestJsGraphQLError = (err) => {
|
|
9
|
+
const nestError = err;
|
|
10
|
+
return Boolean(nestError.extensions) && Boolean(nestError.extensions.context);
|
|
11
|
+
};
|
|
12
|
+
const getFirstNestJsGraphQLError = (err) => {
|
|
13
|
+
if (!isNestJsApolloError(err)) return null;
|
|
14
|
+
return err.graphQLErrors[0] ?? null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/graphql-error-log.ts
|
|
19
|
+
const getErrorMessages = (error) => {
|
|
20
|
+
const messages = [];
|
|
21
|
+
const { graphQLErrors, networkError } = error;
|
|
22
|
+
const operation = "operation" in error ? error.operation : void 0;
|
|
23
|
+
const stack = "stack" in error ? error.stack : void 0;
|
|
24
|
+
let printedQuery;
|
|
25
|
+
if (operation) printedQuery = print(operation.query);
|
|
26
|
+
if (graphQLErrors) graphQLErrors.forEach((error$1) => {
|
|
27
|
+
if (isNestJsGraphQLError(error$1)) messages.push(`[NestJs GraphQL Error] ${error$1.message} (${error$1.extensions.key})`);
|
|
28
|
+
else messages.push(`[GraphQL Error] ${error$1.message}`);
|
|
29
|
+
if (operation) {
|
|
30
|
+
messages.push(logOperation(printedQuery, error$1.locations));
|
|
31
|
+
if (Object.keys(operation.variables).length) messages.push(`with variables: ${JSON.stringify(operation.variables, null, 2)}`);
|
|
32
|
+
}
|
|
33
|
+
if (isNestJsGraphQLError(error$1)) {
|
|
34
|
+
messages.push(`with context: ${JSON.stringify(error$1.extensions.context, null, 2)}`);
|
|
35
|
+
if (error$1.extensions.errorStack) messages.push(`with stack: ${JSON.stringify(error$1.extensions.errorStack, null, 2)}`);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
if (networkError) messages.push(`[GraphQL Network Error] ${networkError}`);
|
|
39
|
+
if (stack) messages.push(stack);
|
|
40
|
+
return messages;
|
|
41
|
+
};
|
|
42
|
+
const logErrorMessages = (error, printStack = true) => {
|
|
43
|
+
getErrorMessages(error).forEach((message) => {
|
|
44
|
+
const result = /\[([\w ]*)](.*)/.exec(message);
|
|
45
|
+
if (result) {
|
|
46
|
+
const [, tag, msg] = result;
|
|
47
|
+
console.log(`%c${tag}`, "color:white;border-radius:3px;background:#ff4400;font-weight:bold;padding:2px 6px;", msg);
|
|
48
|
+
} else console.log(message);
|
|
49
|
+
});
|
|
50
|
+
if (printStack) {
|
|
51
|
+
let stack = (/* @__PURE__ */ new Error()).stack;
|
|
52
|
+
if (stack == null) return;
|
|
53
|
+
const newLineIndex = stack.indexOf("\n");
|
|
54
|
+
stack = stack.slice(stack.indexOf("\n", newLineIndex + 1));
|
|
55
|
+
console.log(`%c${stack}`, "color:grey;");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const logOperation = (printedQuery, locations) => {
|
|
59
|
+
const lines = printedQuery.split("\n");
|
|
60
|
+
const l = lines.length;
|
|
61
|
+
const result = lines.slice();
|
|
62
|
+
const lineMap = {};
|
|
63
|
+
for (let i = 0; i < l; i++) lineMap[i] = i;
|
|
64
|
+
if (locations) for (const { line, column } of locations) {
|
|
65
|
+
const index = lineMap[line];
|
|
66
|
+
result.splice(index, 0, "▲".padStart(column, " "));
|
|
67
|
+
for (let i = index + 1; i < l; i++) lineMap[i]++;
|
|
68
|
+
}
|
|
69
|
+
return result.join("\n");
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/types.ts
|
|
74
|
+
var NestJsGraphQLError = class extends GraphQLError {};
|
|
75
|
+
var NestJsApolloError = class extends ApolloError {};
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
export { NestJsApolloError, NestJsGraphQLError, getErrorMessages, getFirstNestJsGraphQLError, isNestJsApolloError, isNestJsGraphQLError, logErrorMessages };
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["messages: string[]","printedQuery: string","error","lineMap: Record<number, number>"],"sources":["../src/tools.ts","../src/graphql-error-log.ts","../src/types.ts"],"sourcesContent":["import { type GraphQLFormattedError } from 'graphql';\n\nimport { type NestJsApolloError, type NestJsGraphQLError } from './types';\n\nexport const isNestJsApolloError = (err: GraphQLFormattedError): err is NestJsApolloError => {\n return Object.prototype.hasOwnProperty.call(err, 'graphQLErrors');\n};\n\nexport const isNestJsGraphQLError = (err: GraphQLFormattedError): err is NestJsGraphQLError => {\n const nestError = err as NestJsGraphQLError;\n return Boolean(nestError.extensions) && Boolean(nestError.extensions.context);\n};\n\nexport const getFirstNestJsGraphQLError = (err: GraphQLFormattedError): NestJsGraphQLError | null => {\n if (!isNestJsApolloError(err)) {\n return null;\n }\n\n return err.graphQLErrors[0] ?? null;\n};\n","import { type ApolloError } from '@apollo/client/core';\nimport { type ErrorResponse } from '@apollo/client/link/error';\nimport { print } from 'graphql';\n\nimport { isNestJsGraphQLError } from './tools';\n\nexport const getErrorMessages = (error: ErrorResponse | ApolloError) => {\n const messages: string[] = [];\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- Safe to use in Apollo Client 3.x\n const { graphQLErrors, networkError } = error;\n const operation = 'operation' in error ? error.operation : undefined;\n const stack = 'stack' in error ? error.stack : undefined;\n let printedQuery: string;\n\n if (operation) {\n printedQuery = print(operation.query);\n }\n\n if (graphQLErrors) {\n graphQLErrors.forEach((error) => {\n if (isNestJsGraphQLError(error)) {\n messages.push(`[NestJs GraphQL Error] ${error.message} (${error.extensions.key})`);\n } else {\n messages.push(`[GraphQL Error] ${error.message}`);\n }\n\n if (operation) {\n messages.push(logOperation(printedQuery, error.locations));\n if (Object.keys(operation.variables).length) {\n messages.push(`with variables: ${JSON.stringify(operation.variables, null, 2)}`);\n }\n }\n\n if (isNestJsGraphQLError(error)) {\n messages.push(`with context: ${JSON.stringify(error.extensions.context, null, 2)}`);\n\n if (error.extensions.errorStack) {\n messages.push(`with stack: ${JSON.stringify(error.extensions.errorStack, null, 2)}`);\n }\n }\n });\n }\n\n if (networkError) {\n messages.push(`[GraphQL Network Error] ${networkError}`);\n }\n\n if (stack) {\n messages.push(stack);\n }\n\n return messages;\n};\n\nexport const logErrorMessages = (error: ApolloError | ErrorResponse, printStack = true) => {\n getErrorMessages(error).forEach((message) => {\n const result = /\\[([\\w ]*)](.*)/.exec(message);\n if (result) {\n const [, tag, msg] = result;\n console.log(`%c${tag}`, 'color:white;border-radius:3px;background:#ff4400;font-weight:bold;padding:2px 6px;', msg);\n } else {\n console.log(message);\n }\n });\n\n if (printStack) {\n let stack = new Error().stack;\n if (stack == null) {\n return;\n }\n\n const newLineIndex = stack.indexOf('\\n');\n stack = stack.slice(stack.indexOf('\\n', newLineIndex + 1));\n console.log(`%c${stack}`, 'color:grey;');\n }\n};\n\ninterface ErrorLocation {\n line: number;\n column: number;\n}\n\nconst logOperation = (printedQuery: string, locations: readonly ErrorLocation[] | undefined) => {\n const lines = printedQuery.split('\\n');\n const l = lines.length;\n const result = lines.slice();\n const lineMap: Record<number, number> = {\n };\n for (let i = 0; i < l; i++) {\n lineMap[i] = i;\n }\n\n if (locations) {\n for (const { line, column } of locations) {\n const index = lineMap[line];\n result.splice(index, 0, '▲'.padStart(column, ' '));\n // Offset remaining lines\n for (let i = index + 1; i < l; i++) {\n lineMap[i]++;\n }\n }\n }\n\n return result.join('\\n');\n};\n","import { ApolloError } from '@apollo/client/core';\nimport { GraphQLError } from 'graphql';\n\nexport interface ErrorStackItem {\n key: string;\n message: string;\n context: Record<string, unknown>;\n stacktrace?: string;\n}\n\nexport class NestJsGraphQLError extends GraphQLError {\n declare extensions: {\n context: {\n scope?: string;\n action?: string;\n requestId?: string;\n userId?: string;\n [attributeName: string]: unknown;\n };\n key: string;\n statusCode: number;\n errorStack?: ErrorStackItem[];\n format: 'NESTJS';\n [attributeName: string]: unknown;\n };\n}\n\nexport type NestJsGraphQLErrors = readonly NestJsGraphQLError[];\n\nexport class NestJsApolloError extends ApolloError {\n declare graphQLErrors: NestJsGraphQLErrors;\n}\n"],"mappings":";;;;AAIA,MAAa,uBAAuB,QAAyD;AAC3F,QAAO,OAAO,UAAU,eAAe,KAAK,KAAK,gBAAgB;;AAGnE,MAAa,wBAAwB,QAA0D;CAC7F,MAAM,YAAY;AAClB,QAAO,QAAQ,UAAU,WAAW,IAAI,QAAQ,UAAU,WAAW,QAAQ;;AAG/E,MAAa,8BAA8B,QAA0D;AACnG,KAAI,CAAC,oBAAoB,IAAI,CAC3B,QAAO;AAGT,QAAO,IAAI,cAAc,MAAM;;;;;ACZjC,MAAa,oBAAoB,UAAuC;CACtE,MAAMA,WAAqB,EAAE;CAE7B,MAAM,EAAE,eAAe,iBAAiB;CACxC,MAAM,YAAY,eAAe,QAAQ,MAAM,YAAY;CAC3D,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ;CAC/C,IAAIC;AAEJ,KAAI,UACF,gBAAe,MAAM,UAAU,MAAM;AAGvC,KAAI,cACF,eAAc,SAAS,YAAU;AAC/B,MAAI,qBAAqBC,QAAM,CAC7B,UAAS,KAAK,0BAA0BA,QAAM,QAAQ,IAAIA,QAAM,WAAW,IAAI,GAAG;MAElF,UAAS,KAAK,mBAAmBA,QAAM,UAAU;AAGnD,MAAI,WAAW;AACb,YAAS,KAAK,aAAa,cAAcA,QAAM,UAAU,CAAC;AAC1D,OAAI,OAAO,KAAK,UAAU,UAAU,CAAC,OACnC,UAAS,KAAK,mBAAmB,KAAK,UAAU,UAAU,WAAW,MAAM,EAAE,GAAG;;AAIpF,MAAI,qBAAqBA,QAAM,EAAE;AAC/B,YAAS,KAAK,iBAAiB,KAAK,UAAUA,QAAM,WAAW,SAAS,MAAM,EAAE,GAAG;AAEnF,OAAIA,QAAM,WAAW,WACnB,UAAS,KAAK,eAAe,KAAK,UAAUA,QAAM,WAAW,YAAY,MAAM,EAAE,GAAG;;GAGxF;AAGJ,KAAI,aACF,UAAS,KAAK,2BAA2B,eAAe;AAG1D,KAAI,MACF,UAAS,KAAK,MAAM;AAGtB,QAAO;;AAGT,MAAa,oBAAoB,OAAoC,aAAa,SAAS;AACzF,kBAAiB,MAAM,CAAC,SAAS,YAAY;EAC3C,MAAM,SAAS,kBAAkB,KAAK,QAAQ;AAC9C,MAAI,QAAQ;GACV,MAAM,GAAG,KAAK,OAAO;AACrB,WAAQ,IAAI,KAAK,OAAO,sFAAsF,IAAI;QAElH,SAAQ,IAAI,QAAQ;GAEtB;AAEF,KAAI,YAAY;EACd,IAAI,yBAAQ,IAAI,OAAO,EAAC;AACxB,MAAI,SAAS,KACX;EAGF,MAAM,eAAe,MAAM,QAAQ,KAAK;AACxC,UAAQ,MAAM,MAAM,MAAM,QAAQ,MAAM,eAAe,EAAE,CAAC;AAC1D,UAAQ,IAAI,KAAK,SAAS,cAAc;;;AAS5C,MAAM,gBAAgB,cAAsB,cAAoD;CAC9F,MAAM,QAAQ,aAAa,MAAM,KAAK;CACtC,MAAM,IAAI,MAAM;CAChB,MAAM,SAAS,MAAM,OAAO;CAC5B,MAAMC,UAAkC,EACvC;AACD,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,IACrB,SAAQ,KAAK;AAGf,KAAI,UACF,MAAK,MAAM,EAAE,MAAM,YAAY,WAAW;EACxC,MAAM,QAAQ,QAAQ;AACtB,SAAO,OAAO,OAAO,GAAG,IAAI,SAAS,QAAQ,IAAI,CAAC;AAElD,OAAK,IAAI,IAAI,QAAQ,GAAG,IAAI,GAAG,IAC7B,SAAQ;;AAKd,QAAO,OAAO,KAAK,KAAK;;;;;AC7F1B,IAAa,qBAAb,cAAwC,aAAa;AAmBrD,IAAa,oBAAb,cAAuC,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pcg/graphql-kit",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.2",
|
|
4
4
|
"description": "GraphQL utilities and error handling for NestJS Apollo",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"type": "module",
|
|
15
15
|
"main": "dist/index.js",
|
|
16
16
|
"types": "dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
17
20
|
"dependencies": {
|
|
18
21
|
"@apollo/client": "^3.13.0",
|
|
19
22
|
"graphql": "^16.10.0"
|
package/.turbo/turbo-lint.log
DELETED
package/CHANGELOG.md
DELETED
package/eslint.config.js
DELETED
package/src/graphql-error-log.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { type ApolloError } from '@apollo/client/core';
|
|
2
|
-
import { type ErrorResponse } from '@apollo/client/link/error';
|
|
3
|
-
import { print } from 'graphql';
|
|
4
|
-
|
|
5
|
-
import { isNestJsGraphQLError } from './tools';
|
|
6
|
-
|
|
7
|
-
export const getErrorMessages = (error: ErrorResponse | ApolloError) => {
|
|
8
|
-
const messages: string[] = [];
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated -- Safe to use in Apollo Client 3.x
|
|
10
|
-
const { graphQLErrors, networkError } = error;
|
|
11
|
-
const operation = 'operation' in error ? error.operation : undefined;
|
|
12
|
-
const stack = 'stack' in error ? error.stack : undefined;
|
|
13
|
-
let printedQuery: string;
|
|
14
|
-
|
|
15
|
-
if (operation) {
|
|
16
|
-
printedQuery = print(operation.query);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (graphQLErrors) {
|
|
20
|
-
graphQLErrors.forEach((error) => {
|
|
21
|
-
if (isNestJsGraphQLError(error)) {
|
|
22
|
-
messages.push(`[NestJs GraphQL Error] ${error.message} (${error.extensions.key})`);
|
|
23
|
-
} else {
|
|
24
|
-
messages.push(`[GraphQL Error] ${error.message}`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (operation) {
|
|
28
|
-
messages.push(logOperation(printedQuery, error.locations));
|
|
29
|
-
if (Object.keys(operation.variables).length) {
|
|
30
|
-
messages.push(`with variables: ${JSON.stringify(operation.variables, null, 2)}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (isNestJsGraphQLError(error)) {
|
|
35
|
-
messages.push(`with context: ${JSON.stringify(error.extensions.context, null, 2)}`);
|
|
36
|
-
|
|
37
|
-
if (error.extensions.errorStack) {
|
|
38
|
-
messages.push(`with stack: ${JSON.stringify(error.extensions.errorStack, null, 2)}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (networkError) {
|
|
45
|
-
messages.push(`[GraphQL Network Error] ${networkError}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (stack) {
|
|
49
|
-
messages.push(stack);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return messages;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const logErrorMessages = (error: ApolloError | ErrorResponse, printStack = true) => {
|
|
56
|
-
getErrorMessages(error).forEach((message) => {
|
|
57
|
-
const result = /\[([\w ]*)](.*)/.exec(message);
|
|
58
|
-
if (result) {
|
|
59
|
-
const [, tag, msg] = result;
|
|
60
|
-
console.log(`%c${tag}`, 'color:white;border-radius:3px;background:#ff4400;font-weight:bold;padding:2px 6px;', msg);
|
|
61
|
-
} else {
|
|
62
|
-
console.log(message);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (printStack) {
|
|
67
|
-
let stack = new Error().stack;
|
|
68
|
-
if (stack == null) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const newLineIndex = stack.indexOf('\n');
|
|
73
|
-
stack = stack.slice(stack.indexOf('\n', newLineIndex + 1));
|
|
74
|
-
console.log(`%c${stack}`, 'color:grey;');
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
interface ErrorLocation {
|
|
79
|
-
line: number;
|
|
80
|
-
column: number;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const logOperation = (printedQuery: string, locations: readonly ErrorLocation[] | undefined) => {
|
|
84
|
-
const lines = printedQuery.split('\n');
|
|
85
|
-
const l = lines.length;
|
|
86
|
-
const result = lines.slice();
|
|
87
|
-
const lineMap: Record<number, number> = {
|
|
88
|
-
};
|
|
89
|
-
for (let i = 0; i < l; i++) {
|
|
90
|
-
lineMap[i] = i;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (locations) {
|
|
94
|
-
for (const { line, column } of locations) {
|
|
95
|
-
const index = lineMap[line];
|
|
96
|
-
result.splice(index, 0, '▲'.padStart(column, ' '));
|
|
97
|
-
// Offset remaining lines
|
|
98
|
-
for (let i = index + 1; i < l; i++) {
|
|
99
|
-
lineMap[i]++;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return result.join('\n');
|
|
105
|
-
};
|
package/src/index.ts
DELETED
package/src/tools.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type GraphQLFormattedError } from 'graphql';
|
|
2
|
-
|
|
3
|
-
import { type NestJsApolloError, type NestJsGraphQLError } from './types';
|
|
4
|
-
|
|
5
|
-
export const isNestJsApolloError = (err: GraphQLFormattedError): err is NestJsApolloError => {
|
|
6
|
-
return Object.prototype.hasOwnProperty.call(err, 'graphQLErrors');
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const isNestJsGraphQLError = (err: GraphQLFormattedError): err is NestJsGraphQLError => {
|
|
10
|
-
const nestError = err as NestJsGraphQLError;
|
|
11
|
-
return Boolean(nestError.extensions) && Boolean(nestError.extensions.context);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const getFirstNestJsGraphQLError = (err: GraphQLFormattedError): NestJsGraphQLError | null => {
|
|
15
|
-
if (!isNestJsApolloError(err)) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return err.graphQLErrors[0] ?? null;
|
|
20
|
-
};
|
package/src/types.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { ApolloError } from '@apollo/client/core';
|
|
2
|
-
import { GraphQLError } from 'graphql';
|
|
3
|
-
|
|
4
|
-
export interface ErrorStackItem {
|
|
5
|
-
key: string;
|
|
6
|
-
message: string;
|
|
7
|
-
context: Record<string, unknown>;
|
|
8
|
-
stacktrace?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class NestJsGraphQLError extends GraphQLError {
|
|
12
|
-
declare extensions: {
|
|
13
|
-
context: {
|
|
14
|
-
scope?: string;
|
|
15
|
-
action?: string;
|
|
16
|
-
requestId?: string;
|
|
17
|
-
userId?: string;
|
|
18
|
-
[attributeName: string]: unknown;
|
|
19
|
-
};
|
|
20
|
-
key: string;
|
|
21
|
-
statusCode: number;
|
|
22
|
-
errorStack?: ErrorStackItem[];
|
|
23
|
-
format: 'NESTJS';
|
|
24
|
-
[attributeName: string]: unknown;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type NestJsGraphQLErrors = readonly NestJsGraphQLError[];
|
|
29
|
-
|
|
30
|
-
export class NestJsApolloError extends ApolloError {
|
|
31
|
-
declare graphQLErrors: NestJsGraphQLErrors;
|
|
32
|
-
}
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { GraphQLError } from 'graphql';
|
|
3
|
-
import {
|
|
4
|
-
describe,
|
|
5
|
-
expect,
|
|
6
|
-
it,
|
|
7
|
-
vi,
|
|
8
|
-
} from 'vitest';
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
getErrorMessages,
|
|
12
|
-
logErrorMessages,
|
|
13
|
-
} from '@/graphql-error-log.js';
|
|
14
|
-
import { NestJsGraphQLError } from '@/types.js';
|
|
15
|
-
|
|
16
|
-
describe('graphql-error-log', () => {
|
|
17
|
-
describe('getErrorMessages', () => {
|
|
18
|
-
it('should return empty array for error without graphQLErrors and networkError', () => {
|
|
19
|
-
const error: any = {
|
|
20
|
-
graphQLErrors: undefined,
|
|
21
|
-
networkError: undefined,
|
|
22
|
-
};
|
|
23
|
-
const messages = getErrorMessages(error);
|
|
24
|
-
expect(messages).toEqual([]);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should handle graphQLErrors', () => {
|
|
28
|
-
const error: any = {
|
|
29
|
-
graphQLErrors: [new GraphQLError('Test GraphQL Error')],
|
|
30
|
-
networkError: undefined,
|
|
31
|
-
};
|
|
32
|
-
const messages = getErrorMessages(error);
|
|
33
|
-
expect(messages).toContain('[GraphQL Error] Test GraphQL Error');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should handle NestJsGraphQLError with key', () => {
|
|
37
|
-
const nestError = new NestJsGraphQLError('NestJs Error', {
|
|
38
|
-
extensions: {
|
|
39
|
-
context: {
|
|
40
|
-
userId: '123',
|
|
41
|
-
},
|
|
42
|
-
key: 'CUSTOM_ERROR',
|
|
43
|
-
statusCode: 400,
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
const error: any = {
|
|
47
|
-
graphQLErrors: [nestError],
|
|
48
|
-
networkError: undefined,
|
|
49
|
-
};
|
|
50
|
-
const messages = getErrorMessages(error);
|
|
51
|
-
expect(messages.some((msg: string) => msg.includes('[NestJs GraphQL Error]'))).toBe(true);
|
|
52
|
-
expect(messages.some((msg: string) => msg.includes('CUSTOM_ERROR'))).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should handle network errors', () => {
|
|
56
|
-
const networkError = new Error('Network failure');
|
|
57
|
-
const error: any = {
|
|
58
|
-
graphQLErrors: undefined,
|
|
59
|
-
networkError,
|
|
60
|
-
};
|
|
61
|
-
const messages = getErrorMessages(error);
|
|
62
|
-
expect(messages).toContain('[GraphQL Network Error] Error: Network failure');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should handle both graphQLErrors and networkError', () => {
|
|
66
|
-
const graphqlError = new GraphQLError('GraphQL Error');
|
|
67
|
-
const networkError = new Error('Network Error');
|
|
68
|
-
const error: any = {
|
|
69
|
-
graphQLErrors: [graphqlError],
|
|
70
|
-
networkError,
|
|
71
|
-
};
|
|
72
|
-
const messages = getErrorMessages(error);
|
|
73
|
-
expect(messages.some((msg: string) => msg.includes('GraphQL Error'))).toBe(true);
|
|
74
|
-
expect(messages.some((msg: string) => msg.includes('Network Error'))).toBe(true);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should handle multiple graphQLErrors', () => {
|
|
78
|
-
const error: any = {
|
|
79
|
-
graphQLErrors: [
|
|
80
|
-
new GraphQLError('Error 1'),
|
|
81
|
-
new GraphQLError('Error 2'),
|
|
82
|
-
new GraphQLError('Error 3'),
|
|
83
|
-
],
|
|
84
|
-
networkError: undefined,
|
|
85
|
-
};
|
|
86
|
-
const messages = getErrorMessages(error);
|
|
87
|
-
expect(messages.filter((msg: string) => msg.includes('[GraphQL Error]')).length).toBe(3);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should include context for NestJsGraphQLError', () => {
|
|
91
|
-
const nestError = new NestJsGraphQLError('NestJs Error', {
|
|
92
|
-
extensions: {
|
|
93
|
-
context: {
|
|
94
|
-
userId: '123',
|
|
95
|
-
scope: 'admin',
|
|
96
|
-
},
|
|
97
|
-
key: 'AUTH_ERROR',
|
|
98
|
-
statusCode: 401,
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
const error: any = {
|
|
102
|
-
graphQLErrors: [nestError],
|
|
103
|
-
networkError: undefined,
|
|
104
|
-
};
|
|
105
|
-
const messages = getErrorMessages(error);
|
|
106
|
-
expect(messages.some((msg: string) => msg.includes('with context'))).toBe(true);
|
|
107
|
-
expect(messages.some((msg: string) => msg.includes('userId'))).toBe(true);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should include errorStack for NestJsGraphQLError', () => {
|
|
111
|
-
const nestError = new NestJsGraphQLError('NestJs Error', {
|
|
112
|
-
extensions: {
|
|
113
|
-
context: {
|
|
114
|
-
userId: '123',
|
|
115
|
-
},
|
|
116
|
-
key: 'ERROR',
|
|
117
|
-
statusCode: 400,
|
|
118
|
-
errorStack: [
|
|
119
|
-
{
|
|
120
|
-
key: 'VALIDATION_ERROR',
|
|
121
|
-
message: 'Invalid input',
|
|
122
|
-
context: {
|
|
123
|
-
field: 'email',
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
],
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
const error: any = {
|
|
130
|
-
graphQLErrors: [nestError],
|
|
131
|
-
networkError: undefined,
|
|
132
|
-
};
|
|
133
|
-
const messages = getErrorMessages(error);
|
|
134
|
-
expect(messages.some((msg: string) => msg.includes('with stack'))).toBe(true);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
describe('logErrorMessages', () => {
|
|
139
|
-
it('should call console.log for each message', () => {
|
|
140
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
141
|
-
const error: any = {
|
|
142
|
-
graphQLErrors: [new GraphQLError('Test Error')],
|
|
143
|
-
networkError: undefined,
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
logErrorMessages(error, false);
|
|
147
|
-
|
|
148
|
-
expect(consoleSpy).toHaveBeenCalled();
|
|
149
|
-
consoleSpy.mockRestore();
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('should format error tags correctly', () => {
|
|
153
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
154
|
-
const error: any = {
|
|
155
|
-
graphQLErrors: [new GraphQLError('Test Error')],
|
|
156
|
-
networkError: undefined,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
logErrorMessages(error, false);
|
|
160
|
-
|
|
161
|
-
const calls = consoleSpy.mock.calls.map((call: any) => call[0]);
|
|
162
|
-
expect(calls.some((call: any) => typeof call === 'string' && call.includes('GraphQL Error'))).toBe(true);
|
|
163
|
-
|
|
164
|
-
consoleSpy.mockRestore();
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('should include stack trace when printStack is true', () => {
|
|
168
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
169
|
-
const error: any = {
|
|
170
|
-
graphQLErrors: [new GraphQLError('Test Error')],
|
|
171
|
-
networkError: undefined,
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
logErrorMessages(error, true);
|
|
175
|
-
|
|
176
|
-
const calls = consoleSpy.mock.calls;
|
|
177
|
-
expect(calls.length).toBeGreaterThan(0);
|
|
178
|
-
|
|
179
|
-
consoleSpy.mockRestore();
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('should handle NestJsGraphQLError tags correctly', () => {
|
|
183
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
184
|
-
const nestError = new NestJsGraphQLError('NestJs Error', {
|
|
185
|
-
extensions: {
|
|
186
|
-
context: {
|
|
187
|
-
},
|
|
188
|
-
key: 'CUSTOM_ERROR',
|
|
189
|
-
statusCode: 400,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
const error: any = {
|
|
193
|
-
graphQLErrors: [nestError],
|
|
194
|
-
networkError: undefined,
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
logErrorMessages(error, false);
|
|
198
|
-
|
|
199
|
-
const calls = consoleSpy.mock.calls.map((call: any) => call[0]);
|
|
200
|
-
expect(calls.some((call: any) => typeof call === 'string' && call.includes('NestJs GraphQL Error'))).toBe(true);
|
|
201
|
-
|
|
202
|
-
consoleSpy.mockRestore();
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('should handle default printStack value', () => {
|
|
206
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
207
|
-
const error: any = {
|
|
208
|
-
graphQLErrors: [new GraphQLError('Test Error')],
|
|
209
|
-
networkError: undefined,
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
logErrorMessages(error);
|
|
213
|
-
|
|
214
|
-
expect(consoleSpy).toHaveBeenCalled();
|
|
215
|
-
|
|
216
|
-
consoleSpy.mockRestore();
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
});
|
package/tests/tools.test.ts
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { GraphQLError } from 'graphql';
|
|
3
|
-
import {
|
|
4
|
-
describe,
|
|
5
|
-
expect,
|
|
6
|
-
it,
|
|
7
|
-
} from 'vitest';
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
getFirstNestJsGraphQLError,
|
|
11
|
-
isNestJsApolloError,
|
|
12
|
-
isNestJsGraphQLError,
|
|
13
|
-
} from '@/tools.js';
|
|
14
|
-
import { NestJsGraphQLError } from '@/types.js';
|
|
15
|
-
|
|
16
|
-
type TestError = GraphQLError | Record<string, unknown>;
|
|
17
|
-
|
|
18
|
-
describe('tools', () => {
|
|
19
|
-
describe('isNestJsApolloError', () => {
|
|
20
|
-
it('should identify apollo errors with graphQLErrors property', () => {
|
|
21
|
-
const apolloError: TestError = {
|
|
22
|
-
message: 'test',
|
|
23
|
-
graphQLErrors: [],
|
|
24
|
-
};
|
|
25
|
-
expect(isNestJsApolloError(apolloError as any)).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should return false for objects without graphQLErrors property', () => {
|
|
29
|
-
const notApolloError: TestError = {
|
|
30
|
-
message: 'test',
|
|
31
|
-
};
|
|
32
|
-
expect(isNestJsApolloError(notApolloError as any)).toBe(false);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should return true for errors with non-empty graphQLErrors', () => {
|
|
36
|
-
const apolloError: TestError = {
|
|
37
|
-
message: 'Apollo Error',
|
|
38
|
-
graphQLErrors: [new GraphQLError('Internal error')],
|
|
39
|
-
};
|
|
40
|
-
expect(isNestJsApolloError(apolloError as any)).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('isNestJsGraphQLError', () => {
|
|
45
|
-
it('should identify graphql errors with extensions.context', () => {
|
|
46
|
-
const graphqlError: TestError = {
|
|
47
|
-
message: 'test',
|
|
48
|
-
extensions: {
|
|
49
|
-
context: {
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
expect(isNestJsGraphQLError(graphqlError as any)).toBe(true);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should return false for errors without extensions', () => {
|
|
57
|
-
const graphqlError: TestError = {
|
|
58
|
-
message: 'test',
|
|
59
|
-
};
|
|
60
|
-
expect(isNestJsGraphQLError(graphqlError as any)).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should return false for errors without extensions.context', () => {
|
|
64
|
-
const graphqlError: TestError = {
|
|
65
|
-
message: 'test',
|
|
66
|
-
extensions: {
|
|
67
|
-
key: 'VALUE',
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
expect(isNestJsGraphQLError(graphqlError as any)).toBe(false);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should return true for errors with context and additional properties', () => {
|
|
74
|
-
const graphqlError: TestError = {
|
|
75
|
-
message: 'test',
|
|
76
|
-
extensions: {
|
|
77
|
-
context: {
|
|
78
|
-
scope: 'user',
|
|
79
|
-
action: 'login',
|
|
80
|
-
requestId: '123',
|
|
81
|
-
},
|
|
82
|
-
key: 'UNAUTHORIZED',
|
|
83
|
-
statusCode: 401,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
expect(isNestJsGraphQLError(graphqlError as any)).toBe(true);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should handle errors with null context', () => {
|
|
90
|
-
const graphqlError: TestError = {
|
|
91
|
-
message: 'test',
|
|
92
|
-
extensions: {
|
|
93
|
-
context: null,
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
expect(isNestJsGraphQLError(graphqlError as any)).toBe(false);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe('getFirstNestJsGraphQLError', () => {
|
|
101
|
-
it('should return null if error is not apollo error', () => {
|
|
102
|
-
const error: TestError = {
|
|
103
|
-
message: 'test',
|
|
104
|
-
};
|
|
105
|
-
expect(getFirstNestJsGraphQLError(error as any)).toBeNull();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should return null if graphQLErrors is empty', () => {
|
|
109
|
-
const error: TestError = {
|
|
110
|
-
message: 'test',
|
|
111
|
-
graphQLErrors: [],
|
|
112
|
-
};
|
|
113
|
-
expect(getFirstNestJsGraphQLError(error as any)).toBeNull();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should return first graphql error from apollo error', () => {
|
|
117
|
-
const firstError = new GraphQLError('First error');
|
|
118
|
-
const secondError = new GraphQLError('Second error');
|
|
119
|
-
const error: TestError = {
|
|
120
|
-
message: 'Apollo Error',
|
|
121
|
-
graphQLErrors: [firstError, secondError],
|
|
122
|
-
};
|
|
123
|
-
expect(getFirstNestJsGraphQLError(error as any)).toBe(firstError);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should return single graphql error from apollo error', () => {
|
|
127
|
-
const error = new GraphQLError('Single error');
|
|
128
|
-
const apolloError: TestError = {
|
|
129
|
-
message: 'Apollo Error',
|
|
130
|
-
graphQLErrors: [error],
|
|
131
|
-
};
|
|
132
|
-
expect(getFirstNestJsGraphQLError(apolloError as any)).toBe(error);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('should handle NestJsGraphQLError specifically', () => {
|
|
136
|
-
const nestError = new NestJsGraphQLError('NestJs error', {
|
|
137
|
-
extensions: {
|
|
138
|
-
context: {
|
|
139
|
-
userId: '123',
|
|
140
|
-
},
|
|
141
|
-
key: 'CUSTOM_ERROR',
|
|
142
|
-
statusCode: 400,
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
const apolloError: TestError = {
|
|
146
|
-
message: 'Apollo Error',
|
|
147
|
-
graphQLErrors: [nestError],
|
|
148
|
-
};
|
|
149
|
-
expect(getFirstNestJsGraphQLError(apolloError as any)).toBe(nestError);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
});
|
package/tsconfig.json
DELETED
package/tsconfig.lib.json
DELETED
package/tsdown.config.ts
DELETED
package/vitest.config.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// / <reference types="vitest" />
|
|
2
|
-
// eslint-disable-next-line node/no-unpublished-import
|
|
3
|
-
import { defineConfig } from 'vitest/config';
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
test: {
|
|
7
|
-
environment: 'node',
|
|
8
|
-
include: ['tests/**/*.test.ts'],
|
|
9
|
-
globals: true,
|
|
10
|
-
typecheck: {
|
|
11
|
-
tsconfig: './tsconfig.json',
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
resolve: {
|
|
15
|
-
alias: {
|
|
16
|
-
'@': new URL('./src', import.meta.url).pathname,
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
});
|