@unchainedshop/api 4.8.24 → 4.8.26
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/lib/errors.d.ts +1 -0
- package/lib/errors.js +1 -0
- package/lib/mcp/tools/assortment/schemas.d.ts +13 -13
- package/lib/mcp/tools/filter/schemas.d.ts +2 -2
- package/lib/mcp/tools/localization/schemas.d.ts +5 -5
- package/lib/mcp/tools/order/schemas.d.ts +7 -7
- package/lib/mcp/tools/product/schemas.d.ts +44 -44
- package/lib/mcp/tools/quotation/schemas.d.ts +2 -2
- package/lib/mcp/tools/system/handlers/allocateWork.js +2 -2
- package/lib/mcp/tools/system/schemas.d.ts +6 -6
- package/lib/mcp/tools/users/schemas.d.ts +10 -10
- package/lib/mcp/utils/sharedSchemas.d.ts +4 -4
- package/lib/resolvers/mutations/orders/checkoutCart.js +1 -1
- package/lib/resolvers/mutations/users/removeUser.js +9 -2
- package/lib/resolvers/mutations/users/setRoles.js +9 -2
- package/lib/resolvers/mutations/worker/allocateWork.d.ts +1 -1
- package/lib/resolvers/mutations/worker/allocateWork.js +4 -3
- package/package.json +1 -1
- package/lib/adminUiPlugins.d.ts +0 -97
- package/lib/adminUiPlugins.js +0 -164
- package/lib/auth.d.ts +0 -36
- package/lib/auth.js +0 -167
- package/lib/express/mountPluginRoutes.d.ts +0 -3
- package/lib/express/mountPluginRoutes.js +0 -59
- package/lib/express/mountRoutes.d.ts +0 -3
- package/lib/express/mountRoutes.js +0 -57
- package/lib/fastify/mountPluginRoutes.d.ts +0 -3
- package/lib/fastify/mountPluginRoutes.js +0 -62
- package/lib/fastify/mountRoutes.d.ts +0 -3
- package/lib/fastify/mountRoutes.js +0 -60
- package/lib/handlers/createBackchannelLogoutHandler.d.ts +0 -4
- package/lib/handlers/createBackchannelLogoutHandler.js +0 -170
- package/lib/middleware/createAuthMiddleware.d.ts +0 -29
- package/lib/middleware/createAuthMiddleware.js +0 -89
- package/lib/resolvers/mutations/accounts/logoutAllSessions.d.ts +0 -4
- package/lib/resolvers/mutations/accounts/logoutAllSessions.js +0 -11
- package/lib/resolvers/type/order/order-payment-base.d.ts +0 -7
- package/lib/resolvers/type/order/order-payment-base.js +0 -14
- package/lib/schema/types/common.d.ts +0 -2
- package/lib/schema/types/common.js +0 -12
- package/lib/utils/mapServiceError.d.ts +0 -1
- package/lib/utils/mapServiceError.js +0 -59
- package/lib/utils/maskError.d.ts +0 -1
- package/lib/utils/maskError.js +0 -22
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { pluginRegistry } from '@unchainedshop/core';
|
|
2
|
-
import { createServerAdapter } from '@whatwg-node/server';
|
|
3
|
-
export function mountPluginRoutes(fastify, unchainedAPI) {
|
|
4
|
-
const routes = pluginRegistry.getRoutes();
|
|
5
|
-
if (routes.length === 0)
|
|
6
|
-
return;
|
|
7
|
-
const endpoints = routes.map((r) => `${r.method} ${r.path}`).join(', ');
|
|
8
|
-
fastify.log.info(`Mounting ${routes.length} plugin route(s): ${endpoints}`);
|
|
9
|
-
fastify.register((scope, opts, registered) => {
|
|
10
|
-
scope.removeAllContentTypeParsers();
|
|
11
|
-
scope.addContentTypeParser('*', function (request, payload, done) {
|
|
12
|
-
done(null);
|
|
13
|
-
});
|
|
14
|
-
for (const route of routes) {
|
|
15
|
-
const adapter = createServerAdapter(async (request, serverContext) => {
|
|
16
|
-
const context = {
|
|
17
|
-
...unchainedAPI,
|
|
18
|
-
...serverContext.unchainedContext,
|
|
19
|
-
params: serverContext.params || {},
|
|
20
|
-
rawRequest: serverContext.rawRequest,
|
|
21
|
-
};
|
|
22
|
-
try {
|
|
23
|
-
return await route.handler(request, context);
|
|
24
|
-
}
|
|
25
|
-
catch (error) {
|
|
26
|
-
fastify.log.error(`Error in plugin route handler ${route.method} ${route.path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
27
|
-
return new Response(JSON.stringify({
|
|
28
|
-
error: error instanceof Error ? error.message : 'Internal Server Error',
|
|
29
|
-
}), {
|
|
30
|
-
status: 500,
|
|
31
|
-
headers: { 'Content-Type': 'application/json' },
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
let methods;
|
|
36
|
-
if (route.method === 'ALL') {
|
|
37
|
-
methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
methods = [route.method];
|
|
41
|
-
}
|
|
42
|
-
scope.route({
|
|
43
|
-
url: route.path,
|
|
44
|
-
method: methods,
|
|
45
|
-
handler: async (req, reply) => {
|
|
46
|
-
const response = await adapter.handleNodeRequestAndResponse(req.raw, reply.raw, {
|
|
47
|
-
unchainedContext: req.unchainedContext,
|
|
48
|
-
params: req.params,
|
|
49
|
-
rawRequest: req.raw,
|
|
50
|
-
});
|
|
51
|
-
response.headers.forEach((value, key) => {
|
|
52
|
-
reply.header(key, value);
|
|
53
|
-
});
|
|
54
|
-
reply.status(response.status);
|
|
55
|
-
reply.send(response.body || undefined);
|
|
56
|
-
return reply;
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
registered();
|
|
61
|
-
});
|
|
62
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { createServerAdapter } from '@whatwg-node/server';
|
|
2
|
-
export function mountRoutes(fastify, unchainedAPI, routes) {
|
|
3
|
-
if (routes.length === 0)
|
|
4
|
-
return;
|
|
5
|
-
const endpoints = routes.map((r) => `${r.method} ${r.path}`).join(', ');
|
|
6
|
-
fastify.log.info(`Mounting ${routes.length} route(s): ${endpoints}`);
|
|
7
|
-
fastify.register((scope, opts, registered) => {
|
|
8
|
-
scope.removeAllContentTypeParsers();
|
|
9
|
-
scope.addContentTypeParser('*', function (request, payload, done) {
|
|
10
|
-
done(null);
|
|
11
|
-
});
|
|
12
|
-
for (const route of routes) {
|
|
13
|
-
const adapter = createServerAdapter(async (request, serverContext) => {
|
|
14
|
-
const context = {
|
|
15
|
-
...unchainedAPI,
|
|
16
|
-
...serverContext.unchainedContext,
|
|
17
|
-
params: serverContext.params || {},
|
|
18
|
-
rawRequest: serverContext.rawRequest,
|
|
19
|
-
};
|
|
20
|
-
try {
|
|
21
|
-
return await route.handler(request, context);
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
fastify.log.error(`Error in route handler ${route.method} ${route.path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
25
|
-
return new Response(JSON.stringify({
|
|
26
|
-
error: error instanceof Error ? error.message : 'Internal Server Error',
|
|
27
|
-
}), {
|
|
28
|
-
status: 500,
|
|
29
|
-
headers: { 'Content-Type': 'application/json' },
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
let methods;
|
|
34
|
-
if (route.method === 'ALL') {
|
|
35
|
-
methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
methods = [route.method];
|
|
39
|
-
}
|
|
40
|
-
scope.route({
|
|
41
|
-
url: route.path,
|
|
42
|
-
method: methods,
|
|
43
|
-
handler: async (req, reply) => {
|
|
44
|
-
const response = await adapter.handleNodeRequestAndResponse(req.raw, reply.raw, {
|
|
45
|
-
unchainedContext: req.unchainedContext,
|
|
46
|
-
params: req.params,
|
|
47
|
-
rawRequest: req.raw,
|
|
48
|
-
});
|
|
49
|
-
response.headers.forEach((value, key) => {
|
|
50
|
-
reply.header(key, value);
|
|
51
|
-
});
|
|
52
|
-
reply.status(response.status);
|
|
53
|
-
reply.send(response.body || undefined);
|
|
54
|
-
return reply;
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
registered();
|
|
59
|
-
});
|
|
60
|
-
}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import * as jose from 'jose';
|
|
2
|
-
import { createLogger } from '@unchainedshop/logger';
|
|
3
|
-
const logger = createLogger('unchained:api:backchannel-logout');
|
|
4
|
-
function normalizeIssuer(url) {
|
|
5
|
-
try {
|
|
6
|
-
const parsed = new URL(url);
|
|
7
|
-
return parsed.origin + parsed.pathname.replace(/\/$/, '');
|
|
8
|
-
}
|
|
9
|
-
catch {
|
|
10
|
-
return url;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
const jwksCache = new Map();
|
|
14
|
-
function getJWKS(jwksUri) {
|
|
15
|
-
let jwks = jwksCache.get(jwksUri);
|
|
16
|
-
if (!jwks) {
|
|
17
|
-
jwks = jose.createRemoteJWKSet(new URL(jwksUri), {
|
|
18
|
-
cooldownDuration: 30000,
|
|
19
|
-
cacheMaxAge: 600000,
|
|
20
|
-
});
|
|
21
|
-
jwksCache.set(jwksUri, jwks);
|
|
22
|
-
}
|
|
23
|
-
return jwks;
|
|
24
|
-
}
|
|
25
|
-
export function createBackchannelLogoutRoute(providers) {
|
|
26
|
-
return {
|
|
27
|
-
path: '/backchannel-logout',
|
|
28
|
-
method: 'ALL',
|
|
29
|
-
handler: async (request, context) => {
|
|
30
|
-
if (request.method !== 'POST') {
|
|
31
|
-
return new Response(JSON.stringify({ error: 'method_not_allowed' }), {
|
|
32
|
-
status: 405,
|
|
33
|
-
headers: { 'Content-Type': 'application/json' },
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
let logoutToken = null;
|
|
38
|
-
const contentType = request.headers.get('content-type') || '';
|
|
39
|
-
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
40
|
-
const formData = await request.formData();
|
|
41
|
-
logoutToken = formData.get('logout_token');
|
|
42
|
-
}
|
|
43
|
-
else if (contentType.includes('application/json')) {
|
|
44
|
-
const body = (await request.json());
|
|
45
|
-
logoutToken = body.logout_token || null;
|
|
46
|
-
}
|
|
47
|
-
if (!logoutToken) {
|
|
48
|
-
logger.warn('Back-channel logout request missing logout_token');
|
|
49
|
-
return new Response(JSON.stringify({ error: 'missing_logout_token' }), {
|
|
50
|
-
status: 400,
|
|
51
|
-
headers: { 'Content-Type': 'application/json' },
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
let decodedPayload;
|
|
55
|
-
try {
|
|
56
|
-
const parts = logoutToken.split('.');
|
|
57
|
-
if (parts.length !== 3) {
|
|
58
|
-
logger.warn('Invalid logout token format: not a valid JWT');
|
|
59
|
-
return new Response(JSON.stringify({ error: 'invalid_token' }), {
|
|
60
|
-
status: 400,
|
|
61
|
-
headers: { 'Content-Type': 'application/json' },
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
decodedPayload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
logger.warn('Failed to decode logout token');
|
|
68
|
-
return new Response(JSON.stringify({ error: 'invalid_token' }), {
|
|
69
|
-
status: 400,
|
|
70
|
-
headers: { 'Content-Type': 'application/json' },
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
const { iss } = decodedPayload;
|
|
74
|
-
if (!iss || typeof iss !== 'string') {
|
|
75
|
-
logger.warn('Logout token missing issuer (iss)');
|
|
76
|
-
return new Response(JSON.stringify({ error: 'invalid_token' }), {
|
|
77
|
-
status: 400,
|
|
78
|
-
headers: { 'Content-Type': 'application/json' },
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
const normalizedIss = normalizeIssuer(iss);
|
|
82
|
-
const provider = providers.find((p) => normalizeIssuer(p.issuer) === normalizedIss);
|
|
83
|
-
if (!provider) {
|
|
84
|
-
logger.warn('Unknown issuer in logout token:', { iss });
|
|
85
|
-
return new Response(JSON.stringify({ error: 'unknown_issuer' }), {
|
|
86
|
-
status: 400,
|
|
87
|
-
headers: { 'Content-Type': 'application/json' },
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
const jwksUri = provider.jwksUri || `${provider.issuer}/.well-known/jwks.json`;
|
|
91
|
-
let verifiedPayload;
|
|
92
|
-
try {
|
|
93
|
-
const JWKS = getJWKS(jwksUri);
|
|
94
|
-
const verifyOptions = {
|
|
95
|
-
issuer: provider.issuer,
|
|
96
|
-
};
|
|
97
|
-
if (provider.audience) {
|
|
98
|
-
verifyOptions.audience = provider.audience;
|
|
99
|
-
}
|
|
100
|
-
const { payload } = await jose.jwtVerify(logoutToken, JWKS, verifyOptions);
|
|
101
|
-
verifiedPayload = payload;
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
if (error instanceof jose.errors.JWTExpired) {
|
|
105
|
-
logger.warn('Logout token expired');
|
|
106
|
-
return new Response(JSON.stringify({ error: 'token_expired' }), {
|
|
107
|
-
status: 400,
|
|
108
|
-
headers: { 'Content-Type': 'application/json' },
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
else if (error instanceof jose.errors.JWTClaimValidationFailed) {
|
|
112
|
-
logger.warn('Logout token claim validation failed:', { message: error.message });
|
|
113
|
-
return new Response(JSON.stringify({ error: 'invalid_claims' }), {
|
|
114
|
-
status: 400,
|
|
115
|
-
headers: { 'Content-Type': 'application/json' },
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
else if (error instanceof jose.errors.JWSSignatureVerificationFailed) {
|
|
119
|
-
logger.warn('Logout token signature verification failed - possible forgery attempt');
|
|
120
|
-
return new Response(JSON.stringify({ error: 'invalid_signature' }), {
|
|
121
|
-
status: 400,
|
|
122
|
-
headers: { 'Content-Type': 'application/json' },
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
logger.error('Logout token verification failed:', { error });
|
|
127
|
-
return new Response(JSON.stringify({ error: 'verification_failed' }), {
|
|
128
|
-
status: 400,
|
|
129
|
-
headers: { 'Content-Type': 'application/json' },
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const { sub, events } = verifiedPayload;
|
|
134
|
-
if (!events?.['http://schemas.openid.net/event/backchannel-logout']) {
|
|
135
|
-
logger.warn('Token is not a back-channel logout token (missing events claim)');
|
|
136
|
-
return new Response(JSON.stringify({ error: 'invalid_token_type' }), {
|
|
137
|
-
status: 400,
|
|
138
|
-
headers: { 'Content-Type': 'application/json' },
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
if (!sub) {
|
|
142
|
-
logger.warn('Logout token missing subject (sub)');
|
|
143
|
-
return new Response(JSON.stringify({ error: 'missing_subject' }), {
|
|
144
|
-
status: 400,
|
|
145
|
-
headers: { 'Content-Type': 'application/json' },
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
const user = await context.modules.users.findUserById(sub);
|
|
149
|
-
if (!user) {
|
|
150
|
-
logger.info('User not found for back-channel logout:', { sub });
|
|
151
|
-
return new Response('', { status: 200 });
|
|
152
|
-
}
|
|
153
|
-
await context.modules.users.updateOidcLogoutAt(user._id, new Date());
|
|
154
|
-
logger.info('Back-channel logout processed successfully:', {
|
|
155
|
-
userId: user._id,
|
|
156
|
-
issuer: iss,
|
|
157
|
-
});
|
|
158
|
-
return new Response('', { status: 200 });
|
|
159
|
-
}
|
|
160
|
-
catch (error) {
|
|
161
|
-
logger.error('Back-channel logout error:', { error });
|
|
162
|
-
return new Response(JSON.stringify({ error: 'internal_error' }), {
|
|
163
|
-
status: 500,
|
|
164
|
-
headers: { 'Content-Type': 'application/json' },
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
export default createBackchannelLogoutRoute;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { type AuthConfig } from '../auth.ts';
|
|
2
|
-
import type { LoginFn, LogoutFn } from '../context.ts';
|
|
3
|
-
export interface AuthContextParams {
|
|
4
|
-
getHeader: (key: string) => string | undefined;
|
|
5
|
-
setHeader: (key: string, value: string) => void;
|
|
6
|
-
getCookie: (name: string) => string | undefined;
|
|
7
|
-
setCookie: (name: string, value: string, options: CookieOptions) => void;
|
|
8
|
-
clearCookie: (name: string, options: CookieOptions) => void;
|
|
9
|
-
remoteAddress?: string;
|
|
10
|
-
remotePort?: number;
|
|
11
|
-
}
|
|
12
|
-
export interface CookieOptions {
|
|
13
|
-
domain?: string;
|
|
14
|
-
path?: string;
|
|
15
|
-
secure?: boolean;
|
|
16
|
-
httpOnly?: boolean;
|
|
17
|
-
sameSite?: 'strict' | 'lax' | 'none' | boolean;
|
|
18
|
-
maxAge?: number;
|
|
19
|
-
expires?: Date;
|
|
20
|
-
}
|
|
21
|
-
export interface AuthContext {
|
|
22
|
-
userId?: string;
|
|
23
|
-
tokenVersion?: number;
|
|
24
|
-
impersonatorId?: string;
|
|
25
|
-
accessToken?: string;
|
|
26
|
-
login: LoginFn;
|
|
27
|
-
logout: LogoutFn;
|
|
28
|
-
}
|
|
29
|
-
export declare function createAuthContext(params: AuthContextParams, authConfig?: AuthConfig): Promise<AuthContext>;
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { emit } from '@unchainedshop/events';
|
|
2
|
-
import { signAccessToken, createAuthHandler } from "../auth.js";
|
|
3
|
-
import { API_EVENTS } from "../events.js";
|
|
4
|
-
import { createLogger } from '@unchainedshop/logger';
|
|
5
|
-
const logger = createLogger('unchained:api:auth-middleware');
|
|
6
|
-
const { UNCHAINED_COOKIE_NAME = 'unchained_token', UNCHAINED_COOKIE_PATH = '/', UNCHAINED_COOKIE_DOMAIN, UNCHAINED_COOKIE_SAMESITE = 'lax', UNCHAINED_COOKIE_INSECURE, UNCHAINED_TOKEN_EXPIRY_SECONDS = '3600', } = process.env;
|
|
7
|
-
function getTokenCookieOptions(expires) {
|
|
8
|
-
const secure = !UNCHAINED_COOKIE_INSECURE;
|
|
9
|
-
const sameSite = {
|
|
10
|
-
none: 'none',
|
|
11
|
-
lax: 'lax',
|
|
12
|
-
strict: 'strict',
|
|
13
|
-
'1': true,
|
|
14
|
-
'0': false,
|
|
15
|
-
}[UNCHAINED_COOKIE_SAMESITE?.trim()?.toLowerCase()] || 'lax';
|
|
16
|
-
if (!secure && process.env.NODE_ENV === 'production') {
|
|
17
|
-
logger.warn('SECURITY WARNING: Running with UNCHAINED_COOKIE_INSECURE in production is not recommended');
|
|
18
|
-
}
|
|
19
|
-
if (sameSite === 'none' && !secure) {
|
|
20
|
-
logger.warn('SECURITY WARNING: SameSite=None requires Secure flag to be effective');
|
|
21
|
-
}
|
|
22
|
-
const expirySeconds = parseInt(UNCHAINED_TOKEN_EXPIRY_SECONDS, 10);
|
|
23
|
-
return {
|
|
24
|
-
domain: UNCHAINED_COOKIE_DOMAIN,
|
|
25
|
-
path: UNCHAINED_COOKIE_PATH,
|
|
26
|
-
secure,
|
|
27
|
-
httpOnly: true,
|
|
28
|
-
sameSite: sameSite,
|
|
29
|
-
maxAge: expires ? undefined : expirySeconds * 1000,
|
|
30
|
-
expires,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function extractBearerToken(authHeader) {
|
|
34
|
-
if (!authHeader)
|
|
35
|
-
return undefined;
|
|
36
|
-
const parts = authHeader.split(' ');
|
|
37
|
-
if (parts.length !== 2)
|
|
38
|
-
return undefined;
|
|
39
|
-
const [scheme, token] = parts;
|
|
40
|
-
if (scheme.toLowerCase() !== 'bearer') {
|
|
41
|
-
logger.debug('Authorization header present but not Bearer scheme');
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
return token;
|
|
45
|
-
}
|
|
46
|
-
export async function createAuthContext(params, authConfig) {
|
|
47
|
-
const { getHeader, getCookie, setCookie, clearCookie } = params;
|
|
48
|
-
const authHeader = getHeader('authorization');
|
|
49
|
-
const headerToken = extractBearerToken(authHeader);
|
|
50
|
-
const cookieToken = getCookie(UNCHAINED_COOKIE_NAME);
|
|
51
|
-
const token = headerToken || cookieToken;
|
|
52
|
-
const verifyToken = createAuthHandler(authConfig);
|
|
53
|
-
const authResult = token ? await verifyToken(token) : {};
|
|
54
|
-
const login = async (user, options = {}) => {
|
|
55
|
-
const { impersonator } = options;
|
|
56
|
-
const tokenVersion = user.tokenVersion ?? 1;
|
|
57
|
-
const { token: newToken, expires } = await signAccessToken(user._id, tokenVersion, {
|
|
58
|
-
impersonatorId: impersonator?._id,
|
|
59
|
-
});
|
|
60
|
-
setCookie(UNCHAINED_COOKIE_NAME, newToken, getTokenCookieOptions(expires));
|
|
61
|
-
const tokenObject = {
|
|
62
|
-
_id: crypto.randomUUID(),
|
|
63
|
-
userId: user._id,
|
|
64
|
-
tokenExpires: expires,
|
|
65
|
-
};
|
|
66
|
-
await emit(API_EVENTS.API_LOGIN_TOKEN_CREATED, tokenObject);
|
|
67
|
-
user._inLoginMethodResponse = true;
|
|
68
|
-
return { user, ...tokenObject };
|
|
69
|
-
};
|
|
70
|
-
const logout = async () => {
|
|
71
|
-
clearCookie(UNCHAINED_COOKIE_NAME, getTokenCookieOptions());
|
|
72
|
-
if (authResult.userId) {
|
|
73
|
-
const tokenObject = {
|
|
74
|
-
_id: crypto.randomUUID(),
|
|
75
|
-
userId: authResult.userId,
|
|
76
|
-
};
|
|
77
|
-
await emit(API_EVENTS.API_LOGOUT, tokenObject);
|
|
78
|
-
}
|
|
79
|
-
return true;
|
|
80
|
-
};
|
|
81
|
-
return {
|
|
82
|
-
userId: authResult.userId,
|
|
83
|
-
tokenVersion: authResult.tokenVersion,
|
|
84
|
-
impersonatorId: authResult.impersonatorId,
|
|
85
|
-
accessToken: authResult.isApiKey ? authResult.accessToken : undefined,
|
|
86
|
-
login,
|
|
87
|
-
logout,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { log } from '@unchainedshop/logger';
|
|
2
|
-
export default async function logoutAllSessions(root, _, context) {
|
|
3
|
-
const { userId, modules } = context;
|
|
4
|
-
log('mutation logoutAllSessions', { userId });
|
|
5
|
-
const result = await modules.users.incrementTokenVersion(userId);
|
|
6
|
-
if (!result) {
|
|
7
|
-
throw new Error('Failed to logout all sessions', { cause: 'LOGOUT_FAILED' });
|
|
8
|
-
}
|
|
9
|
-
await context.logout();
|
|
10
|
-
return { success: true };
|
|
11
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { OrderPayment } from '@unchainedshop/core-orders';
|
|
2
|
-
import type { Context } from '../../../context.ts';
|
|
3
|
-
export declare const OrderPaymentBase: {
|
|
4
|
-
status(obj: OrderPayment, _: never, { modules }: Context): import("@unchainedshop/core-orders").OrderPaymentStatus;
|
|
5
|
-
provider(obj: OrderPayment, _: never, { loaders }: Context): Promise<import("@unchainedshop/core-payment").PaymentProvider>;
|
|
6
|
-
discounts(obj: OrderPayment, _: never, { loaders, services }: Context): Promise<import("@unchainedshop/core/lib/services/getPaymentDiscounts.js").PaymentDiscountPrice[]>;
|
|
7
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export const OrderPaymentBase = {
|
|
2
|
-
status(obj, _, { modules }) {
|
|
3
|
-
return modules.orders.payments.normalizedStatus(obj);
|
|
4
|
-
},
|
|
5
|
-
async provider(obj, _, { loaders }) {
|
|
6
|
-
return loaders.paymentProviderLoader.load({
|
|
7
|
-
paymentProviderId: obj.paymentProviderId,
|
|
8
|
-
});
|
|
9
|
-
},
|
|
10
|
-
async discounts(obj, _, { loaders, services }) {
|
|
11
|
-
const order = await loaders.orderLoader.load({ orderId: obj.orderId });
|
|
12
|
-
return services.payment.getPaymentDiscounts(obj, order.currencyCode);
|
|
13
|
-
},
|
|
14
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function mapServiceError(error: unknown): never;
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { GraphQLError } from 'graphql';
|
|
2
|
-
import * as errors from "../errors.js";
|
|
3
|
-
const errorMap = {
|
|
4
|
-
ProductNotFoundError: errors.ProductNotFoundError,
|
|
5
|
-
ProductWrongStatusError: errors.ProductWrongStatusError,
|
|
6
|
-
ProductWrongTypeError: errors.ProductWrongTypeError,
|
|
7
|
-
CyclicProductBundlingNotSupportedError: errors.CyclicProductBundlingNotSupportedError,
|
|
8
|
-
ProductVariationInfinityLoop: errors.ProductVariationInfinityLoop,
|
|
9
|
-
ProductVariationVectorInvalid: errors.ProductVariationVectorInvalid,
|
|
10
|
-
ProductVariationVectorAlreadySet: errors.ProductVariationVectorAlreadySet,
|
|
11
|
-
ProductLinkedToActiveBundleError: errors.ProductLinkedToActiveBundleError,
|
|
12
|
-
ProductLinkedToActiveVariationError: errors.ProductLinkedToActiveVariationError,
|
|
13
|
-
ProductLinkedToQuotationError: errors.ProductLinkedToQuotationError,
|
|
14
|
-
ProductLinkedToEnrollmentError: errors.ProductLinkedToEnrollmentError,
|
|
15
|
-
EnrollmentNotFoundError: errors.EnrollmentNotFoundError,
|
|
16
|
-
EnrollmentWrongStatusError: errors.EnrollmentWrongStatusError,
|
|
17
|
-
EnrollmentPlanUpdateNotAllowedError: errors.EnrollmentWrongStatusError,
|
|
18
|
-
OrderNotFoundError: errors.OrderNotFoundError,
|
|
19
|
-
OrderWrongStatusError: errors.OrderWrongStatusError,
|
|
20
|
-
OrderItemNotFoundError: errors.OrderItemNotFoundError,
|
|
21
|
-
OrderQuantityTooLowError: errors.OrderQuantityTooLowError,
|
|
22
|
-
OrderPaymentNotFoundError: errors.OrderPaymentNotFoundError,
|
|
23
|
-
OrderWrongPaymentStatusError: errors.OrderWrongPaymentStatusError,
|
|
24
|
-
OrderDeliveryNotFoundError: errors.OrderDeliveryNotFoundError,
|
|
25
|
-
OrderWrongDeliveryStatusError: errors.OrderWrongDeliveryStatusError,
|
|
26
|
-
QuotationNotFoundError: errors.QuotationNotFoundError,
|
|
27
|
-
QuotationWrongStatusError: errors.QuotationWrongStatusError,
|
|
28
|
-
QuotationItemConfigurationError: errors.QuotationItemConfigurationError,
|
|
29
|
-
BookmarkNotFoundError: errors.BookmarkNotFoundError,
|
|
30
|
-
MultipleBookmarksFound: errors.MultipleBookmarksFound,
|
|
31
|
-
BookmarkAlreadyExistsError: errors.BookmarkAlreadyExistsError,
|
|
32
|
-
OrderDiscountCodeAlreadyPresentError: errors.OrderDiscountCodeAlreadyPresentError,
|
|
33
|
-
OrderDiscountCodeNotValidError: errors.OrderDiscountCodeNotValidError,
|
|
34
|
-
UserNotFoundError: errors.UserNotFoundError,
|
|
35
|
-
ImpersonatingAdminUserError: errors.ImpersonatingAdminUserError,
|
|
36
|
-
InvalidEmailVerificationTokenError: errors.InvalidEmailVerificationTokenError,
|
|
37
|
-
UsernameOrEmailRequiredError: errors.UsernameOrEmailRequiredError,
|
|
38
|
-
PasswordOrWebAuthnPublicKeyRequiredError: errors.PasswordOrWebAuthnPublicKeyRequiredError,
|
|
39
|
-
EmailAlreadyExistsError: errors.EmailAlreadyExistsError,
|
|
40
|
-
UsernameAlreadyExistsError: errors.UsernameAlreadyExistsError,
|
|
41
|
-
PasswordInvalidError: errors.PasswordInvalidError,
|
|
42
|
-
WebAuthnVerificationFailedError: errors.WebAuthnVerificationFailedError,
|
|
43
|
-
AuthOperationFailedError: errors.AuthOperationFailedError,
|
|
44
|
-
InvalidCredentialsError: errors.InvalidCredentialsError,
|
|
45
|
-
InvalidResetTokenError: errors.InvalidResetTokenError,
|
|
46
|
-
InvalidIdError: errors.InvalidIdError,
|
|
47
|
-
ProviderConfigurationInvalid: errors.ProviderConfigurationInvalid,
|
|
48
|
-
};
|
|
49
|
-
export function mapServiceError(error) {
|
|
50
|
-
if (error instanceof GraphQLError) {
|
|
51
|
-
throw error;
|
|
52
|
-
}
|
|
53
|
-
const serviceError = error;
|
|
54
|
-
const ErrorClass = serviceError.code ? errorMap[serviceError.code] : undefined;
|
|
55
|
-
if (ErrorClass) {
|
|
56
|
-
throw new ErrorClass(serviceError.data);
|
|
57
|
-
}
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
package/lib/utils/maskError.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function createMaskError(isDev: boolean): (error: unknown, message: string) => Error;
|
package/lib/utils/maskError.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { GraphQLError } from 'graphql';
|
|
2
|
-
import { maskError as yogaMaskError } from 'graphql-yoga';
|
|
3
|
-
function isKnownError(error) {
|
|
4
|
-
return error instanceof Error && 'code' in error && typeof error.code === 'string';
|
|
5
|
-
}
|
|
6
|
-
export function createMaskError(isDev) {
|
|
7
|
-
return function maskError(error, message) {
|
|
8
|
-
const originalError = error instanceof GraphQLError ? error.originalError || error : error;
|
|
9
|
-
if (error instanceof GraphQLError && error.extensions?.code) {
|
|
10
|
-
return error;
|
|
11
|
-
}
|
|
12
|
-
if (isKnownError(originalError)) {
|
|
13
|
-
return new GraphQLError(originalError.message, {
|
|
14
|
-
extensions: {
|
|
15
|
-
code: originalError.code,
|
|
16
|
-
...(originalError.data || {}),
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
return yogaMaskError(error, message, isDev);
|
|
21
|
-
};
|
|
22
|
-
}
|