@cosmneo/onion-lasagna 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-XWKHOLIP.js → chunk-4HMXTGHK.js} +2 -2
- package/dist/chunk-4RFWJ5XZ.js +192 -0
- package/dist/chunk-4RFWJ5XZ.js.map +1 -0
- package/dist/{chunk-4BVOLXDJ.js → chunk-4YBAV6LZ.js} +2 -2
- package/dist/chunk-ANLXZHUS.js +230 -0
- package/dist/chunk-ANLXZHUS.js.map +1 -0
- package/dist/chunk-BG2FY27M.js +36 -0
- package/dist/chunk-BG2FY27M.js.map +1 -0
- package/dist/chunk-FEY2GSVT.js +1 -0
- package/dist/chunk-FEY2GSVT.js.map +1 -0
- package/dist/{chunk-2BVCU32G.js → chunk-HNEAH6OZ.js} +121 -2
- package/dist/chunk-HNEAH6OZ.js.map +1 -0
- package/dist/chunk-NQMFWI6Q.js +1 -0
- package/dist/chunk-NQMFWI6Q.js.map +1 -0
- package/dist/chunk-TZRBETT3.js +127 -0
- package/dist/chunk-TZRBETT3.js.map +1 -0
- package/dist/{chunk-MF2JDREK.js → chunk-UNVB4INM.js} +1 -1
- package/dist/{chunk-MF2JDREK.js.map → chunk-UNVB4INM.js.map} +1 -1
- package/dist/chunk-VBG3UYQR.js +119 -0
- package/dist/chunk-VBG3UYQR.js.map +1 -0
- package/dist/events/index.js +3 -4
- package/dist/events/server/index.js +3 -4
- package/dist/events/shared/index.js +2 -3
- package/dist/graphql/field/index.cjs +189 -0
- package/dist/graphql/field/index.cjs.map +1 -0
- package/dist/graphql/field/index.d.cts +214 -0
- package/dist/graphql/field/index.d.ts +214 -0
- package/dist/graphql/field/index.js +25 -0
- package/dist/graphql/field/index.js.map +1 -0
- package/dist/graphql/index.cjs +1148 -0
- package/dist/graphql/index.cjs.map +1 -0
- package/dist/graphql/index.d.cts +8 -0
- package/dist/graphql/index.d.ts +8 -0
- package/dist/graphql/index.js +49 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/sdl/index.cjs +241 -0
- package/dist/graphql/sdl/index.cjs.map +1 -0
- package/dist/graphql/sdl/index.d.cts +77 -0
- package/dist/graphql/sdl/index.d.ts +77 -0
- package/dist/graphql/sdl/index.js +8 -0
- package/dist/graphql/sdl/index.js.map +1 -0
- package/dist/graphql/server/index.cjs +505 -0
- package/dist/graphql/server/index.cjs.map +1 -0
- package/dist/graphql/server/index.d.cts +268 -0
- package/dist/graphql/server/index.d.ts +268 -0
- package/dist/graphql/server/index.js +15 -0
- package/dist/graphql/server/index.js.map +1 -0
- package/dist/graphql/shared/index.cjs +586 -0
- package/dist/graphql/shared/index.cjs.map +1 -0
- package/dist/graphql/shared/index.d.cts +82 -0
- package/dist/graphql/shared/index.d.ts +82 -0
- package/dist/graphql/shared/index.js +16 -0
- package/dist/graphql/shared/index.js.map +1 -0
- package/dist/http/index.cjs.map +1 -1
- package/dist/http/index.js +2 -3
- package/dist/http/route/index.cjs.map +1 -1
- package/dist/http/route/index.d.cts +4 -0
- package/dist/http/route/index.d.ts +4 -0
- package/dist/http/route/index.js +1 -1
- package/dist/http/shared/index.js +1 -2
- package/dist/index.cjs +672 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +43 -1
- package/dist/index.js.map +1 -1
- package/dist/schema-definition.type-C9PntBVc.d.cts +166 -0
- package/dist/schema-definition.type-CuhQLDr0.d.ts +166 -0
- package/package.json +31 -1
- package/dist/chunk-2BVCU32G.js.map +0 -1
- package/dist/chunk-H5TNDC5U.js +0 -138
- package/dist/chunk-H5TNDC5U.js.map +0 -1
- /package/dist/{chunk-XWKHOLIP.js.map → chunk-4HMXTGHK.js.map} +0 -0
- /package/dist/{chunk-4BVOLXDJ.js.map → chunk-4YBAV6LZ.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -56,7 +56,22 @@ __export(src_exports, {
|
|
|
56
56
|
UnauthorizedError: () => UnauthorizedError,
|
|
57
57
|
UnprocessableError: () => UnprocessableError,
|
|
58
58
|
UseCaseError: () => UseCaseError,
|
|
59
|
+
collectFields: () => collectFields,
|
|
60
|
+
defineGraphQLSchema: () => defineGraphQLSchema,
|
|
61
|
+
defineMutation: () => defineMutation,
|
|
62
|
+
defineQuery: () => defineQuery,
|
|
63
|
+
defineSubscription: () => defineSubscription,
|
|
59
64
|
fieldChanged: () => fieldChanged,
|
|
65
|
+
generateFieldId: () => generateFieldId,
|
|
66
|
+
generateGraphQLSDL: () => generateGraphQLSDL,
|
|
67
|
+
getGraphQLErrorCode: () => getGraphQLErrorCode,
|
|
68
|
+
graphqlRoutes: () => graphqlRoutes,
|
|
69
|
+
isFieldDefinition: () => isFieldDefinition,
|
|
70
|
+
isSchemaDefinition: () => isSchemaDefinition,
|
|
71
|
+
isSimpleGraphQLHandlerConfig: () => isSimpleGraphQLHandlerConfig,
|
|
72
|
+
mapErrorToGraphQLError: () => mapErrorToGraphQLError,
|
|
73
|
+
mergeGraphQLSchemas: () => mergeGraphQLSchemas,
|
|
74
|
+
shouldMaskGraphQLError: () => shouldMaskGraphQLError,
|
|
60
75
|
wrapError: () => wrapError,
|
|
61
76
|
wrapErrorAsync: () => wrapErrorAsync,
|
|
62
77
|
wrapErrorUnless: () => wrapErrorUnless,
|
|
@@ -1719,6 +1734,648 @@ var InvalidRequestError = class _InvalidRequestError extends CodedError {
|
|
|
1719
1734
|
}
|
|
1720
1735
|
};
|
|
1721
1736
|
|
|
1737
|
+
// src/presentation/graphql/field/define-field.ts
|
|
1738
|
+
function createFieldDefinition(operation, input) {
|
|
1739
|
+
const definition = {
|
|
1740
|
+
operation,
|
|
1741
|
+
input: input.input ?? void 0,
|
|
1742
|
+
output: input.output ?? void 0,
|
|
1743
|
+
context: input.context ?? void 0,
|
|
1744
|
+
docs: {
|
|
1745
|
+
summary: input.docs?.summary,
|
|
1746
|
+
description: input.docs?.description,
|
|
1747
|
+
tags: input.docs?.tags,
|
|
1748
|
+
deprecated: input.docs?.deprecated ?? false,
|
|
1749
|
+
deprecationReason: input.docs?.deprecationReason
|
|
1750
|
+
},
|
|
1751
|
+
_isGraphQLField: true,
|
|
1752
|
+
_types: void 0
|
|
1753
|
+
};
|
|
1754
|
+
return Object.freeze(definition);
|
|
1755
|
+
}
|
|
1756
|
+
function defineQuery(config = {}) {
|
|
1757
|
+
return createFieldDefinition("query", config);
|
|
1758
|
+
}
|
|
1759
|
+
function defineMutation(config = {}) {
|
|
1760
|
+
return createFieldDefinition("mutation", config);
|
|
1761
|
+
}
|
|
1762
|
+
function defineSubscription(config = {}) {
|
|
1763
|
+
return createFieldDefinition("subscription", config);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
// src/presentation/graphql/field/types/schema-definition.type.ts
|
|
1767
|
+
function isFieldDefinition(value) {
|
|
1768
|
+
return typeof value === "object" && value !== null && "_isGraphQLField" in value && value._isGraphQLField === true;
|
|
1769
|
+
}
|
|
1770
|
+
function isSchemaDefinition(value) {
|
|
1771
|
+
return typeof value === "object" && value !== null && "_isGraphQLSchema" in value && value._isGraphQLSchema === true;
|
|
1772
|
+
}
|
|
1773
|
+
function collectFields(config, basePath = "") {
|
|
1774
|
+
const fields = [];
|
|
1775
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1776
|
+
const fullKey = basePath ? `${basePath}.${key}` : key;
|
|
1777
|
+
if (isFieldDefinition(value)) {
|
|
1778
|
+
fields.push({ key: fullKey, field: value });
|
|
1779
|
+
} else if (isSchemaDefinition(value)) {
|
|
1780
|
+
fields.push(...collectFields(value.fields, fullKey));
|
|
1781
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1782
|
+
fields.push(...collectFields(value, fullKey));
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return fields;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// src/presentation/graphql/field/define-schema.ts
|
|
1789
|
+
function defineGraphQLSchema(fields, options) {
|
|
1790
|
+
const defaults = options?.defaults;
|
|
1791
|
+
const processedFields = defaults?.context || defaults?.tags ? applySchemaDefaults(fields, defaults) : fields;
|
|
1792
|
+
const definition = {
|
|
1793
|
+
fields: processedFields,
|
|
1794
|
+
defaults,
|
|
1795
|
+
_isGraphQLSchema: true
|
|
1796
|
+
};
|
|
1797
|
+
return deepFreeze(definition);
|
|
1798
|
+
}
|
|
1799
|
+
function applySchemaDefaults(config, defaults) {
|
|
1800
|
+
const result = {};
|
|
1801
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1802
|
+
if (isFieldDefinition(value)) {
|
|
1803
|
+
result[key] = applyDefaultsToField(value, defaults);
|
|
1804
|
+
} else if (isSchemaDefinition(value)) {
|
|
1805
|
+
result[key] = {
|
|
1806
|
+
...value,
|
|
1807
|
+
fields: applySchemaDefaults(value.fields, defaults)
|
|
1808
|
+
};
|
|
1809
|
+
} else if (typeof value === "object" && value !== null) {
|
|
1810
|
+
result[key] = applySchemaDefaults(value, defaults);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
return result;
|
|
1814
|
+
}
|
|
1815
|
+
function applyDefaultsToField(field, defaults) {
|
|
1816
|
+
const needsContext = defaults.context && !field.context;
|
|
1817
|
+
const needsTags = defaults.tags && defaults.tags.length > 0;
|
|
1818
|
+
if (!needsContext && !needsTags) return field;
|
|
1819
|
+
return Object.freeze({
|
|
1820
|
+
...field,
|
|
1821
|
+
context: field.context ?? defaults.context ?? void 0,
|
|
1822
|
+
docs: {
|
|
1823
|
+
...field.docs,
|
|
1824
|
+
tags: mergeTags(defaults.tags, field.docs.tags)
|
|
1825
|
+
}
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
function mergeTags(schemaTags, fieldTags) {
|
|
1829
|
+
if (!schemaTags || schemaTags.length === 0) return fieldTags;
|
|
1830
|
+
if (!fieldTags || fieldTags.length === 0) return schemaTags;
|
|
1831
|
+
const merged = [...schemaTags];
|
|
1832
|
+
for (const tag of fieldTags) {
|
|
1833
|
+
if (!merged.includes(tag)) {
|
|
1834
|
+
merged.push(tag);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
return merged;
|
|
1838
|
+
}
|
|
1839
|
+
function deepFreeze(obj) {
|
|
1840
|
+
const propNames = Object.getOwnPropertyNames(obj);
|
|
1841
|
+
for (const name of propNames) {
|
|
1842
|
+
const value = obj[name];
|
|
1843
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
1844
|
+
deepFreeze(value);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
return Object.freeze(obj);
|
|
1848
|
+
}
|
|
1849
|
+
function extractFields(input) {
|
|
1850
|
+
return isSchemaDefinition(input) ? input.fields : input;
|
|
1851
|
+
}
|
|
1852
|
+
function isSubGroup(value) {
|
|
1853
|
+
return typeof value === "object" && value !== null && !isFieldDefinition(value) && !isSchemaDefinition(value);
|
|
1854
|
+
}
|
|
1855
|
+
function deepMergeConfigs(a, b) {
|
|
1856
|
+
const result = { ...a };
|
|
1857
|
+
for (const key of Object.keys(b)) {
|
|
1858
|
+
const aVal = result[key];
|
|
1859
|
+
const bVal = b[key];
|
|
1860
|
+
if (isSubGroup(aVal) && isSubGroup(bVal)) {
|
|
1861
|
+
result[key] = deepMergeConfigs(aVal, bVal);
|
|
1862
|
+
} else {
|
|
1863
|
+
result[key] = bVal;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
return result;
|
|
1867
|
+
}
|
|
1868
|
+
function mergeGraphQLSchemas(...schemas) {
|
|
1869
|
+
const merged = schemas.map(extractFields).reduce(deepMergeConfigs);
|
|
1870
|
+
return defineGraphQLSchema(merged);
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
// src/presentation/graphql/field/utils.ts
|
|
1874
|
+
function generateFieldId(key) {
|
|
1875
|
+
return key.split(".").map(
|
|
1876
|
+
(segment, index) => index === 0 ? segment : segment.charAt(0).toUpperCase() + segment.slice(1)
|
|
1877
|
+
).join("");
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
// src/presentation/http/shared/error-mapping.ts
|
|
1881
|
+
function isErrorType(error, typeName) {
|
|
1882
|
+
if (!error || typeof error !== "object") return false;
|
|
1883
|
+
const constructor = Object.prototype.hasOwnProperty.call(error, "constructor") ? error.constructor : Object.getPrototypeOf(error)?.constructor;
|
|
1884
|
+
if (!constructor) return false;
|
|
1885
|
+
const name = constructor.name;
|
|
1886
|
+
return name === typeName || name === `_${typeName}`;
|
|
1887
|
+
}
|
|
1888
|
+
function hasValidationErrors(error) {
|
|
1889
|
+
if (!error || typeof error !== "object") return false;
|
|
1890
|
+
return "validationErrors" in error && Array.isArray(error.validationErrors);
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
// src/presentation/graphql/shared/error-mapping.ts
|
|
1894
|
+
var MASKED_ERROR = {
|
|
1895
|
+
message: "An unexpected error occurred",
|
|
1896
|
+
extensions: { code: "INTERNAL_ERROR" }
|
|
1897
|
+
};
|
|
1898
|
+
var INTERNAL_ERROR_TYPES = [
|
|
1899
|
+
"DomainError",
|
|
1900
|
+
"InfraError",
|
|
1901
|
+
"ControllerError",
|
|
1902
|
+
"NetworkError",
|
|
1903
|
+
"PersistenceError",
|
|
1904
|
+
"ExternalServiceError",
|
|
1905
|
+
"InvariantViolationError"
|
|
1906
|
+
];
|
|
1907
|
+
function getGraphQLErrorCode(error) {
|
|
1908
|
+
if (error instanceof ObjectValidationError) return "VALIDATION_ERROR";
|
|
1909
|
+
if (error instanceof UnauthorizedError) return "FORBIDDEN";
|
|
1910
|
+
if (error instanceof ForbiddenError) return "FORBIDDEN";
|
|
1911
|
+
if (error instanceof AccessDeniedError) return "FORBIDDEN";
|
|
1912
|
+
if (error instanceof NotFoundError) return "NOT_FOUND";
|
|
1913
|
+
if (error instanceof ConflictError) return "CONFLICT";
|
|
1914
|
+
if (error instanceof UnprocessableError) return "UNPROCESSABLE";
|
|
1915
|
+
if (error instanceof UseCaseError) return "BAD_REQUEST";
|
|
1916
|
+
if (isErrorType(error, "ObjectValidationError")) return "VALIDATION_ERROR";
|
|
1917
|
+
if (isErrorType(error, "UnauthorizedError")) return "FORBIDDEN";
|
|
1918
|
+
if (isErrorType(error, "ForbiddenError")) return "FORBIDDEN";
|
|
1919
|
+
if (isErrorType(error, "AccessDeniedError")) return "FORBIDDEN";
|
|
1920
|
+
if (isErrorType(error, "NotFoundError")) return "NOT_FOUND";
|
|
1921
|
+
if (isErrorType(error, "ConflictError")) return "CONFLICT";
|
|
1922
|
+
if (isErrorType(error, "UnprocessableError")) return "UNPROCESSABLE";
|
|
1923
|
+
if (isErrorType(error, "UseCaseError")) return "BAD_REQUEST";
|
|
1924
|
+
return "INTERNAL_ERROR";
|
|
1925
|
+
}
|
|
1926
|
+
function shouldMaskGraphQLError(error) {
|
|
1927
|
+
if (error instanceof DomainError || error instanceof InfraError) {
|
|
1928
|
+
return true;
|
|
1929
|
+
}
|
|
1930
|
+
for (const errorType of INTERNAL_ERROR_TYPES) {
|
|
1931
|
+
if (isErrorType(error, errorType)) {
|
|
1932
|
+
return true;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
return false;
|
|
1936
|
+
}
|
|
1937
|
+
function mapErrorToGraphQLError(error) {
|
|
1938
|
+
if (shouldMaskGraphQLError(error)) {
|
|
1939
|
+
return MASKED_ERROR;
|
|
1940
|
+
}
|
|
1941
|
+
const code = getGraphQLErrorCode(error);
|
|
1942
|
+
if (error instanceof ObjectValidationError) {
|
|
1943
|
+
return buildValidationError(error.message, code, error.code, error.validationErrors);
|
|
1944
|
+
}
|
|
1945
|
+
if (isErrorType(error, "ObjectValidationError") && hasValidationErrors(error)) {
|
|
1946
|
+
return buildValidationError(error.message, code, error.code, error.validationErrors);
|
|
1947
|
+
}
|
|
1948
|
+
if (error instanceof CodedError) {
|
|
1949
|
+
return {
|
|
1950
|
+
message: error.message,
|
|
1951
|
+
extensions: { code, originalCode: error.code }
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
if (isErrorType(error, "CodedError")) {
|
|
1955
|
+
return {
|
|
1956
|
+
message: error.message,
|
|
1957
|
+
extensions: { code, originalCode: error.code }
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
if (error && typeof error === "object" && "message" in error && "code" in error && typeof error.message === "string" && typeof error.code === "string") {
|
|
1961
|
+
return {
|
|
1962
|
+
message: error.message,
|
|
1963
|
+
extensions: { code, originalCode: error.code }
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
return MASKED_ERROR;
|
|
1967
|
+
}
|
|
1968
|
+
function buildValidationError(message, code, originalCode, validationErrors) {
|
|
1969
|
+
return {
|
|
1970
|
+
message,
|
|
1971
|
+
extensions: {
|
|
1972
|
+
code,
|
|
1973
|
+
originalCode,
|
|
1974
|
+
validationErrors: validationErrors.map(
|
|
1975
|
+
(e) => ({
|
|
1976
|
+
field: e.field,
|
|
1977
|
+
message: e.message
|
|
1978
|
+
})
|
|
1979
|
+
)
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// src/presentation/graphql/server/types.ts
|
|
1985
|
+
function isSimpleGraphQLHandlerConfig(config) {
|
|
1986
|
+
return "handler" in config && typeof config.handler === "function";
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
// src/presentation/graphql/server/create-graphql-routes.ts
|
|
1990
|
+
function createGraphQLRoutesInternal(schema, handlers, options) {
|
|
1991
|
+
const config = isSchemaDefinition(schema) ? schema.fields : schema;
|
|
1992
|
+
const collectedFields = collectFields(config);
|
|
1993
|
+
const result = [];
|
|
1994
|
+
const resolvedOptions = {
|
|
1995
|
+
...options,
|
|
1996
|
+
validateInput: options?.validateInput ?? true,
|
|
1997
|
+
validateOutput: options?.validateOutput ?? true,
|
|
1998
|
+
allowPartial: options?.allowPartial ?? false
|
|
1999
|
+
};
|
|
2000
|
+
for (const { key, field } of collectedFields) {
|
|
2001
|
+
const handlerConfig = handlers[key];
|
|
2002
|
+
if (!handlerConfig) {
|
|
2003
|
+
if (resolvedOptions.allowPartial) {
|
|
2004
|
+
continue;
|
|
2005
|
+
}
|
|
2006
|
+
throw new Error(
|
|
2007
|
+
`Missing handler for field "${key}". All fields must have a handler configuration.`
|
|
2008
|
+
);
|
|
2009
|
+
}
|
|
2010
|
+
result.push(createFieldHandler(key, field, handlerConfig, resolvedOptions));
|
|
2011
|
+
}
|
|
2012
|
+
return result;
|
|
2013
|
+
}
|
|
2014
|
+
function createFieldHandler(key, field, config, options) {
|
|
2015
|
+
const middleware = config.middleware ?? [];
|
|
2016
|
+
const globalMiddleware = options?.middleware ?? [];
|
|
2017
|
+
const allMiddleware = [...globalMiddleware, ...middleware];
|
|
2018
|
+
const shouldValidateInput = options.validateInput ?? true;
|
|
2019
|
+
const shouldValidateOutput = options.validateOutput ?? true;
|
|
2020
|
+
return {
|
|
2021
|
+
key,
|
|
2022
|
+
operation: field.operation,
|
|
2023
|
+
metadata: {
|
|
2024
|
+
fieldId: generateFieldId(key),
|
|
2025
|
+
description: field.docs.description,
|
|
2026
|
+
tags: field.docs.tags,
|
|
2027
|
+
deprecated: field.docs.deprecated,
|
|
2028
|
+
deprecationReason: field.docs.deprecationReason
|
|
2029
|
+
},
|
|
2030
|
+
handler: async (rawArgs, rawContext) => {
|
|
2031
|
+
const context = options?.createContext ? options.createContext(rawContext) : rawContext ?? { requestId: generateRequestId() };
|
|
2032
|
+
let validatedContext = context;
|
|
2033
|
+
if (field.context) {
|
|
2034
|
+
const contextResult = validateContextData(field, context);
|
|
2035
|
+
if (!contextResult.success) {
|
|
2036
|
+
throw new UnauthorizedError({
|
|
2037
|
+
message: "Authentication required"
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
validatedContext = contextResult.data;
|
|
2041
|
+
}
|
|
2042
|
+
let validatedInput = rawArgs;
|
|
2043
|
+
if (shouldValidateInput && field.input) {
|
|
2044
|
+
const inputResult = validateInputData(field, rawArgs);
|
|
2045
|
+
if (!inputResult.success) {
|
|
2046
|
+
const errors = inputResult.errors ?? [];
|
|
2047
|
+
throw new ObjectValidationError({
|
|
2048
|
+
message: "Input validation failed",
|
|
2049
|
+
validationErrors: errors.map((e) => ({
|
|
2050
|
+
field: e.path.join("."),
|
|
2051
|
+
message: e.message
|
|
2052
|
+
}))
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
validatedInput = inputResult.data;
|
|
2056
|
+
}
|
|
2057
|
+
const validatedArgs = {
|
|
2058
|
+
input: validatedInput,
|
|
2059
|
+
raw: rawArgs
|
|
2060
|
+
};
|
|
2061
|
+
const executePipeline = async () => {
|
|
2062
|
+
if (isSimpleGraphQLHandlerConfig(config)) {
|
|
2063
|
+
return config.handler(
|
|
2064
|
+
validatedArgs,
|
|
2065
|
+
validatedContext
|
|
2066
|
+
);
|
|
2067
|
+
} else {
|
|
2068
|
+
const { argsMapper, useCase, responseMapper } = config;
|
|
2069
|
+
const input = argsMapper(
|
|
2070
|
+
validatedArgs,
|
|
2071
|
+
validatedContext
|
|
2072
|
+
);
|
|
2073
|
+
const output = await useCase.execute(input);
|
|
2074
|
+
return responseMapper(output);
|
|
2075
|
+
}
|
|
2076
|
+
};
|
|
2077
|
+
let result;
|
|
2078
|
+
if (allMiddleware.length === 0) {
|
|
2079
|
+
result = await executePipeline();
|
|
2080
|
+
} else {
|
|
2081
|
+
let index = 0;
|
|
2082
|
+
let called = false;
|
|
2083
|
+
const next = async () => {
|
|
2084
|
+
if (index >= allMiddleware.length) {
|
|
2085
|
+
if (called) throw new Error("next() called after pipeline already executed");
|
|
2086
|
+
called = true;
|
|
2087
|
+
return executePipeline();
|
|
2088
|
+
}
|
|
2089
|
+
const currentIndex = index++;
|
|
2090
|
+
const mw = allMiddleware[currentIndex];
|
|
2091
|
+
return mw(rawArgs, context, next);
|
|
2092
|
+
};
|
|
2093
|
+
result = await next();
|
|
2094
|
+
}
|
|
2095
|
+
if (shouldValidateOutput && field.output) {
|
|
2096
|
+
const outputResult = validateOutputData(field, result);
|
|
2097
|
+
if (!outputResult.success) {
|
|
2098
|
+
const details = outputResult.errors?.map((e) => `${e.path.join(".")}: ${e.message}`).join("; ");
|
|
2099
|
+
throw new ObjectValidationError({
|
|
2100
|
+
message: `Output validation failed for field "${key}": ${details}`,
|
|
2101
|
+
validationErrors: (outputResult.errors ?? []).map((e) => ({
|
|
2102
|
+
field: e.path.join("."),
|
|
2103
|
+
message: e.message
|
|
2104
|
+
}))
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
return result;
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
function validateInputData(field, args) {
|
|
2113
|
+
const schema = field.input;
|
|
2114
|
+
if (!schema) return { success: true, data: args };
|
|
2115
|
+
const result = schema.validate(args);
|
|
2116
|
+
if (result.success) {
|
|
2117
|
+
return { success: true, data: result.data };
|
|
2118
|
+
}
|
|
2119
|
+
const errors = result.issues.map((issue) => ({
|
|
2120
|
+
...issue,
|
|
2121
|
+
path: ["input", ...issue.path]
|
|
2122
|
+
}));
|
|
2123
|
+
return { success: false, errors };
|
|
2124
|
+
}
|
|
2125
|
+
function validateOutputData(field, data) {
|
|
2126
|
+
const schema = field.output;
|
|
2127
|
+
if (!schema) return { success: true, data };
|
|
2128
|
+
const result = schema.validate(data);
|
|
2129
|
+
if (result.success) {
|
|
2130
|
+
return { success: true, data: result.data };
|
|
2131
|
+
}
|
|
2132
|
+
const errors = result.issues.map((issue) => ({
|
|
2133
|
+
...issue,
|
|
2134
|
+
path: ["output", ...issue.path]
|
|
2135
|
+
}));
|
|
2136
|
+
return { success: false, errors };
|
|
2137
|
+
}
|
|
2138
|
+
function validateContextData(field, context) {
|
|
2139
|
+
const schema = field.context;
|
|
2140
|
+
if (!schema) return { success: true, data: context };
|
|
2141
|
+
const result = schema.validate(context);
|
|
2142
|
+
if (result.success) {
|
|
2143
|
+
return { success: true, data: result.data };
|
|
2144
|
+
}
|
|
2145
|
+
const errors = result.issues.map((issue) => ({
|
|
2146
|
+
...issue,
|
|
2147
|
+
path: ["context", ...issue.path]
|
|
2148
|
+
}));
|
|
2149
|
+
return { success: false, errors };
|
|
2150
|
+
}
|
|
2151
|
+
function generateRequestId() {
|
|
2152
|
+
return `gql_${crypto.randomUUID()}`;
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
// src/presentation/graphql/server/graphql-routes-builder.ts
|
|
2156
|
+
var GraphQLRoutesBuilderImpl = class _GraphQLRoutesBuilderImpl {
|
|
2157
|
+
schema;
|
|
2158
|
+
handlers;
|
|
2159
|
+
constructor(schema, handlers) {
|
|
2160
|
+
this.schema = schema;
|
|
2161
|
+
this.handlers = handlers ?? /* @__PURE__ */ new Map();
|
|
2162
|
+
}
|
|
2163
|
+
handle(key, handlerOrConfig) {
|
|
2164
|
+
const config = typeof handlerOrConfig === "function" ? { handler: handlerOrConfig } : handlerOrConfig;
|
|
2165
|
+
const newHandlers = new Map(this.handlers);
|
|
2166
|
+
newHandlers.set(key, config);
|
|
2167
|
+
return new _GraphQLRoutesBuilderImpl(
|
|
2168
|
+
this.schema,
|
|
2169
|
+
newHandlers
|
|
2170
|
+
);
|
|
2171
|
+
}
|
|
2172
|
+
handleWithUseCase(key, config) {
|
|
2173
|
+
const newHandlers = new Map(this.handlers);
|
|
2174
|
+
newHandlers.set(
|
|
2175
|
+
key,
|
|
2176
|
+
config
|
|
2177
|
+
);
|
|
2178
|
+
return new _GraphQLRoutesBuilderImpl(
|
|
2179
|
+
this.schema,
|
|
2180
|
+
newHandlers
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
build(options) {
|
|
2184
|
+
return createGraphQLRoutesInternal(this.schema, Object.fromEntries(this.handlers), options);
|
|
2185
|
+
}
|
|
2186
|
+
buildPartial(options) {
|
|
2187
|
+
return createGraphQLRoutesInternal(this.schema, Object.fromEntries(this.handlers), {
|
|
2188
|
+
...options,
|
|
2189
|
+
allowPartial: true
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2192
|
+
};
|
|
2193
|
+
function graphqlRoutes(schema) {
|
|
2194
|
+
return new GraphQLRoutesBuilderImpl(schema);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
// src/presentation/graphql/sdl/generate.ts
|
|
2198
|
+
function generateGraphQLSDL(schema, config) {
|
|
2199
|
+
const fields = isSchemaDefinition(schema) ? schema.fields : schema;
|
|
2200
|
+
const collectedFields = collectFields(fields);
|
|
2201
|
+
const includeDescriptions = config?.includeDescriptions ?? true;
|
|
2202
|
+
const includeDeprecations = config?.includeDeprecations ?? true;
|
|
2203
|
+
const queries = [];
|
|
2204
|
+
const mutations = [];
|
|
2205
|
+
const subscriptions = [];
|
|
2206
|
+
for (const { key, field } of collectedFields) {
|
|
2207
|
+
const fieldId = generateFieldId(key);
|
|
2208
|
+
if (field.operation === "query") {
|
|
2209
|
+
queries.push({ fieldId, field });
|
|
2210
|
+
} else if (field.operation === "mutation") {
|
|
2211
|
+
mutations.push({ fieldId, field });
|
|
2212
|
+
} else if (field.operation === "subscription") {
|
|
2213
|
+
subscriptions.push({ fieldId, field });
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
const namedTypes = /* @__PURE__ */ new Map();
|
|
2217
|
+
const lines = [];
|
|
2218
|
+
if (config?.preamble) {
|
|
2219
|
+
lines.push(config.preamble);
|
|
2220
|
+
lines.push("");
|
|
2221
|
+
}
|
|
2222
|
+
if (queries.length > 0) {
|
|
2223
|
+
lines.push("type Query {");
|
|
2224
|
+
for (const { fieldId, field } of queries) {
|
|
2225
|
+
const fieldLine = buildFieldLine(
|
|
2226
|
+
fieldId,
|
|
2227
|
+
field,
|
|
2228
|
+
namedTypes,
|
|
2229
|
+
includeDescriptions,
|
|
2230
|
+
includeDeprecations
|
|
2231
|
+
);
|
|
2232
|
+
lines.push(fieldLine);
|
|
2233
|
+
}
|
|
2234
|
+
lines.push("}");
|
|
2235
|
+
lines.push("");
|
|
2236
|
+
}
|
|
2237
|
+
if (mutations.length > 0) {
|
|
2238
|
+
lines.push("type Mutation {");
|
|
2239
|
+
for (const { fieldId, field } of mutations) {
|
|
2240
|
+
const fieldLine = buildFieldLine(
|
|
2241
|
+
fieldId,
|
|
2242
|
+
field,
|
|
2243
|
+
namedTypes,
|
|
2244
|
+
includeDescriptions,
|
|
2245
|
+
includeDeprecations
|
|
2246
|
+
);
|
|
2247
|
+
lines.push(fieldLine);
|
|
2248
|
+
}
|
|
2249
|
+
lines.push("}");
|
|
2250
|
+
lines.push("");
|
|
2251
|
+
}
|
|
2252
|
+
if (subscriptions.length > 0) {
|
|
2253
|
+
lines.push("type Subscription {");
|
|
2254
|
+
for (const { fieldId, field } of subscriptions) {
|
|
2255
|
+
const fieldLine = buildFieldLine(
|
|
2256
|
+
fieldId,
|
|
2257
|
+
field,
|
|
2258
|
+
namedTypes,
|
|
2259
|
+
includeDescriptions,
|
|
2260
|
+
includeDeprecations
|
|
2261
|
+
);
|
|
2262
|
+
lines.push(fieldLine);
|
|
2263
|
+
}
|
|
2264
|
+
lines.push("}");
|
|
2265
|
+
lines.push("");
|
|
2266
|
+
}
|
|
2267
|
+
for (const [, typeBody] of namedTypes) {
|
|
2268
|
+
lines.push(typeBody);
|
|
2269
|
+
lines.push("");
|
|
2270
|
+
}
|
|
2271
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
2272
|
+
}
|
|
2273
|
+
function buildFieldLine(fieldId, field, namedTypes, includeDescriptions, includeDeprecations) {
|
|
2274
|
+
const parts = [];
|
|
2275
|
+
if (includeDescriptions && field.docs.description) {
|
|
2276
|
+
const escaped = field.docs.description.replace(/"""/g, '\\"""');
|
|
2277
|
+
parts.push(` """${escaped}"""`);
|
|
2278
|
+
}
|
|
2279
|
+
const inputTypeName = field.input ? `${capitalize(fieldId)}Input` : void 0;
|
|
2280
|
+
const outputTypeName = field.output ? `${capitalize(fieldId)}Output` : void 0;
|
|
2281
|
+
if (field.input && inputTypeName) {
|
|
2282
|
+
const jsonSchema = field.input.toJsonSchema();
|
|
2283
|
+
namedTypes.set(inputTypeName, buildInputType(inputTypeName, jsonSchema));
|
|
2284
|
+
}
|
|
2285
|
+
if (field.output && outputTypeName) {
|
|
2286
|
+
const jsonSchema = field.output.toJsonSchema();
|
|
2287
|
+
namedTypes.set(outputTypeName, buildOutputType(outputTypeName, jsonSchema));
|
|
2288
|
+
}
|
|
2289
|
+
let signature = ` ${fieldId}`;
|
|
2290
|
+
if (inputTypeName) {
|
|
2291
|
+
signature += `(input: ${inputTypeName}!)`;
|
|
2292
|
+
}
|
|
2293
|
+
signature += ": ";
|
|
2294
|
+
signature += outputTypeName ?? "JSON";
|
|
2295
|
+
if (includeDeprecations && field.docs.deprecated) {
|
|
2296
|
+
const reason = field.docs.deprecationReason;
|
|
2297
|
+
signature += reason ? ` @deprecated(reason: "${escapeSDLString(reason)}")` : " @deprecated";
|
|
2298
|
+
}
|
|
2299
|
+
if (parts.length > 0) {
|
|
2300
|
+
return parts.join("\n") + "\n" + signature;
|
|
2301
|
+
}
|
|
2302
|
+
return signature;
|
|
2303
|
+
}
|
|
2304
|
+
function buildInputType(typeName, jsonSchema) {
|
|
2305
|
+
const lines = [`input ${typeName} {`];
|
|
2306
|
+
if (jsonSchema.properties && typeof jsonSchema.properties === "object") {
|
|
2307
|
+
const required = new Set(
|
|
2308
|
+
Array.isArray(jsonSchema.required) ? jsonSchema.required : []
|
|
2309
|
+
);
|
|
2310
|
+
for (const [propName, propSchema] of Object.entries(
|
|
2311
|
+
jsonSchema.properties
|
|
2312
|
+
)) {
|
|
2313
|
+
const graphqlType = jsonSchemaToGraphQLType(propSchema);
|
|
2314
|
+
const isRequired = required.has(propName);
|
|
2315
|
+
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
lines.push("}");
|
|
2319
|
+
return lines.join("\n");
|
|
2320
|
+
}
|
|
2321
|
+
function buildOutputType(typeName, jsonSchema) {
|
|
2322
|
+
const lines = [`type ${typeName} {`];
|
|
2323
|
+
if (jsonSchema.properties && typeof jsonSchema.properties === "object") {
|
|
2324
|
+
const required = new Set(
|
|
2325
|
+
Array.isArray(jsonSchema.required) ? jsonSchema.required : []
|
|
2326
|
+
);
|
|
2327
|
+
for (const [propName, propSchema] of Object.entries(
|
|
2328
|
+
jsonSchema.properties
|
|
2329
|
+
)) {
|
|
2330
|
+
const graphqlType = jsonSchemaToGraphQLType(propSchema);
|
|
2331
|
+
const isRequired = required.has(propName);
|
|
2332
|
+
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
lines.push("}");
|
|
2336
|
+
return lines.join("\n");
|
|
2337
|
+
}
|
|
2338
|
+
function jsonSchemaToGraphQLType(schema) {
|
|
2339
|
+
if (!schema || typeof schema !== "object") return "JSON";
|
|
2340
|
+
if (schema.enum && Array.isArray(schema.enum)) {
|
|
2341
|
+
return "String";
|
|
2342
|
+
}
|
|
2343
|
+
const type = schema.type;
|
|
2344
|
+
switch (type) {
|
|
2345
|
+
case "string":
|
|
2346
|
+
return "String";
|
|
2347
|
+
case "integer":
|
|
2348
|
+
return "Int";
|
|
2349
|
+
case "number":
|
|
2350
|
+
return "Float";
|
|
2351
|
+
case "boolean":
|
|
2352
|
+
return "Boolean";
|
|
2353
|
+
case "array": {
|
|
2354
|
+
const items = schema.items;
|
|
2355
|
+
if (items) {
|
|
2356
|
+
return `[${jsonSchemaToGraphQLType(items)}]`;
|
|
2357
|
+
}
|
|
2358
|
+
return "[JSON]";
|
|
2359
|
+
}
|
|
2360
|
+
case "object":
|
|
2361
|
+
return "JSON";
|
|
2362
|
+
default:
|
|
2363
|
+
if (schema.oneOf || schema.anyOf || schema.allOf) {
|
|
2364
|
+
return "JSON";
|
|
2365
|
+
}
|
|
2366
|
+
if (schema.properties) {
|
|
2367
|
+
return "JSON";
|
|
2368
|
+
}
|
|
2369
|
+
return "JSON";
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
function capitalize(str) {
|
|
2373
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2374
|
+
}
|
|
2375
|
+
function escapeSDLString(str) {
|
|
2376
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
2377
|
+
}
|
|
2378
|
+
|
|
1722
2379
|
// src/global/utils/field-changed.util.ts
|
|
1723
2380
|
function fieldChanged({
|
|
1724
2381
|
value,
|
|
@@ -1766,7 +2423,22 @@ function fieldChanged({
|
|
|
1766
2423
|
UnauthorizedError,
|
|
1767
2424
|
UnprocessableError,
|
|
1768
2425
|
UseCaseError,
|
|
2426
|
+
collectFields,
|
|
2427
|
+
defineGraphQLSchema,
|
|
2428
|
+
defineMutation,
|
|
2429
|
+
defineQuery,
|
|
2430
|
+
defineSubscription,
|
|
1769
2431
|
fieldChanged,
|
|
2432
|
+
generateFieldId,
|
|
2433
|
+
generateGraphQLSDL,
|
|
2434
|
+
getGraphQLErrorCode,
|
|
2435
|
+
graphqlRoutes,
|
|
2436
|
+
isFieldDefinition,
|
|
2437
|
+
isSchemaDefinition,
|
|
2438
|
+
isSimpleGraphQLHandlerConfig,
|
|
2439
|
+
mapErrorToGraphQLError,
|
|
2440
|
+
mergeGraphQLSchemas,
|
|
2441
|
+
shouldMaskGraphQLError,
|
|
1770
2442
|
wrapError,
|
|
1771
2443
|
wrapErrorAsync,
|
|
1772
2444
|
wrapErrorUnless,
|