0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-03 22:15:32 -05:00

refactor(core): migrate connector library to factory mode

This commit is contained in:
Gao Sun 2023-01-09 23:51:38 +08:00
parent d0a81e76a8
commit 3b3b35b883
No known key found for this signature in database
GPG key ID: 13EBE123E4773688
18 changed files with 238 additions and 239 deletions

View file

@ -1,10 +1,7 @@
import type { Connector } from '@logto/schemas';
import { createMockUtils } from '@logto/shared/esm';
import RequestError from '#src/errors/RequestError/index.js';
const { jest } = import.meta;
const { mockEsmWithActual } = createMockUtils(jest);
import { MockQueries } from '#src/test-utils/tenant.js';
const connectors: Connector[] = [
{
@ -17,11 +14,10 @@ const connectors: Connector[] = [
},
];
await mockEsmWithActual('#src/queries/connector.js', () => ({
findAllConnectors: jest.fn(async () => connectors),
}));
const { getConnectorConfig } = await import('./connector.js');
const { createConnectorLibrary } = await import('./connector.js');
const { getConnectorConfig } = createConnectorLibrary(
new MockQueries({ connectors: { findAllConnectors: async () => connectors } })
);
it('getConnectorConfig() should return right config', async () => {
const config = await getConnectorConfig('id');

View file

@ -2,85 +2,102 @@ import type { AllConnector } from '@logto/connector-kit';
import { validateConfig } from '@logto/connector-kit';
import RequestError from '#src/errors/RequestError/index.js';
import { findAllConnectors } from '#src/queries/connector.js';
import type Queries from '#src/tenants/Queries.js';
import assertThat from '#src/utils/assert-that.js';
import { defaultConnectorMethods } from '#src/utils/connectors/consts.js';
import { loadConnectorFactories } from '#src/utils/connectors/factories.js';
import { validateConnectorModule, parseMetadata } from '#src/utils/connectors/index.js';
import type { LogtoConnector } from '#src/utils/connectors/types.js';
export const getConnectorConfig = async (id: string): Promise<unknown> => {
const connectors = await findAllConnectors();
const connector = connectors.find((connector) => connector.id === id);
import { defaultQueries } from './shared.js';
assertThat(connector, new RequestError({ code: 'entity.not_found', id, status: 404 }));
export type ConnectorLibrary = ReturnType<typeof createConnectorLibrary>;
return connector.config;
export const createConnectorLibrary = (queries: Queries) => {
const { findAllConnectors } = queries.connectors;
const getConnectorConfig = async (id: string): Promise<unknown> => {
const connectors = await findAllConnectors();
const connector = connectors.find((connector) => connector.id === id);
assertThat(connector, new RequestError({ code: 'entity.not_found', id, status: 404 }));
return connector.config;
};
const getLogtoConnectors = async (): Promise<LogtoConnector[]> => {
const databaseConnectors = await findAllConnectors();
const logtoConnectors = await Promise.all(
databaseConnectors.map(async (databaseConnector) => {
const { id, metadata, connectorId } = databaseConnector;
const connectorFactories = await loadConnectorFactories();
const connectorFactory = connectorFactories.find(
({ metadata }) => metadata.id === connectorId
);
if (!connectorFactory) {
return;
}
const { createConnector, path: packagePath } = connectorFactory;
try {
const rawConnector = await createConnector({
getConfig: async () => {
return getConnectorConfig(id);
},
});
validateConnectorModule(rawConnector);
const rawMetadata = await parseMetadata(rawConnector.metadata, packagePath);
const connector: AllConnector = {
...defaultConnectorMethods,
...rawConnector,
metadata: {
...rawMetadata,
...metadata,
},
};
return {
...connector,
validateConfig: (config: unknown) => {
validateConfig(config, rawConnector.configGuard);
},
dbEntry: databaseConnector,
};
} catch {}
})
);
return logtoConnectors.filter(
(logtoConnector): logtoConnector is LogtoConnector => logtoConnector !== undefined
);
};
const getLogtoConnectorById = async (id: string): Promise<LogtoConnector> => {
const connectors = await getLogtoConnectors();
const pickedConnector = connectors.find(({ dbEntry }) => dbEntry.id === id);
if (!pickedConnector) {
throw new RequestError({
code: 'entity.not_found',
id,
status: 404,
});
}
return pickedConnector;
};
return { getConnectorConfig, getLogtoConnectors, getLogtoConnectorById };
};
export const getLogtoConnectors = async (): Promise<LogtoConnector[]> => {
const databaseConnectors = await findAllConnectors();
/** @deprecated Don't use. This is for transition only and will be removed soon. */
export const defaultConnectorLibrary = createConnectorLibrary(defaultQueries);
const logtoConnectors = await Promise.all(
databaseConnectors.map(async (databaseConnector) => {
const { id, metadata, connectorId } = databaseConnector;
const connectorFactories = await loadConnectorFactories();
const connectorFactory = connectorFactories.find(
({ metadata }) => metadata.id === connectorId
);
if (!connectorFactory) {
return;
}
const { createConnector, path: packagePath } = connectorFactory;
try {
const rawConnector = await createConnector({
getConfig: async () => {
return getConnectorConfig(id);
},
});
validateConnectorModule(rawConnector);
const rawMetadata = await parseMetadata(rawConnector.metadata, packagePath);
const connector: AllConnector = {
...defaultConnectorMethods,
...rawConnector,
metadata: {
...rawMetadata,
...metadata,
},
};
return {
...connector,
validateConfig: (config: unknown) => {
validateConfig(config, rawConnector.configGuard);
},
dbEntry: databaseConnector,
};
} catch {}
})
);
return logtoConnectors.filter(
(logtoConnector): logtoConnector is LogtoConnector => logtoConnector !== undefined
);
};
export const getLogtoConnectorById = async (id: string): Promise<LogtoConnector> => {
const connectors = await getLogtoConnectors();
const pickedConnector = connectors.find(({ dbEntry }) => dbEntry.id === id);
if (!pickedConnector) {
throw new RequestError({
code: 'entity.not_found',
id,
status: 404,
});
}
return pickedConnector;
};
/** @deprecated Don't use. This is for transition only and will be removed soon. */
export const { getConnectorConfig, getLogtoConnectors, getLogtoConnectorById } =
defaultConnectorLibrary;

View file

@ -2,7 +2,6 @@ import type { LanguageTag } from '@logto/language-kit';
import { builtInLanguages } from '@logto/phrases-ui';
import type { CreateSignInExperience, SignInExperience } from '@logto/schemas';
import { BrandingStyle } from '@logto/schemas';
import { createMockUtils } from '@logto/shared/esm';
import {
socialTarget01,
@ -13,8 +12,9 @@ import {
} from '#src/__mocks__/index.js';
import RequestError from '#src/errors/RequestError/index.js';
import { createConnectorLibrary } from '../connector.js';
const { jest } = import.meta;
const { mockEsm } = createMockUtils(jest);
const allCustomLanguageTags: LanguageTag[] = [];
@ -23,10 +23,6 @@ const customPhrases = {
};
const { findAllCustomLanguageTags } = customPhrases;
const { getLogtoConnectors } = mockEsm('#src/libraries/connector.js', () => ({
getLogtoConnectors: jest.fn(),
}));
const signInExperiences = {
findDefaultSignInExperience: jest.fn(),
updateDefaultSignInExperience: jest.fn(
@ -43,10 +39,12 @@ const queries = new MockQueries({
customPhrases,
signInExperiences,
});
const connectorLibrary = createConnectorLibrary(queries);
const getLogtoConnectors = jest.spyOn(connectorLibrary, 'getLogtoConnectors');
const { validateBranding, createSignInExperienceLibrary } = await import('./index.js');
const { validateLanguageInfo, removeUnavailableSocialConnectorTargets } =
createSignInExperienceLibrary(queries);
createSignInExperienceLibrary(queries, connectorLibrary);
beforeEach(() => {
jest.clearAllMocks();

View file

@ -12,7 +12,8 @@ import { deduplicate } from '@silverhand/essentials';
import i18next from 'i18next';
import RequestError from '#src/errors/RequestError/index.js';
import { getLogtoConnectors } from '#src/libraries/connector.js';
import type { ConnectorLibrary } from '#src/libraries/connector.js';
import { defaultConnectorLibrary } from '#src/libraries/connector.js';
import type Queries from '#src/tenants/Queries.js';
import assertThat from '#src/utils/assert-that.js';
@ -29,7 +30,10 @@ export const validateBranding = (branding: Branding) => {
assertThat(branding.logoUrl.trim(), 'sign_in_experiences.empty_logo');
};
export const createSignInExperienceLibrary = (queries: Queries) => {
export const createSignInExperienceLibrary = (
queries: Queries,
connectorLibrary: ConnectorLibrary
) => {
const {
customPhrases: { findAllCustomLanguageTags },
signInExperiences: { findDefaultSignInExperience, updateDefaultSignInExperience },
@ -49,7 +53,7 @@ export const createSignInExperienceLibrary = (queries: Queries) => {
};
const removeUnavailableSocialConnectorTargets = async () => {
const connectors = await getLogtoConnectors();
const connectors = await connectorLibrary.getLogtoConnectors();
const availableSocialConnectorTargets = deduplicate(
connectors
.filter(({ type }) => type === ConnectorType.Social)
@ -113,4 +117,4 @@ export const {
validateLanguageInfo,
removeUnavailableSocialConnectorTargets,
getSignInExperienceForApplication,
} = createSignInExperienceLibrary(defaultQueries);
} = createSignInExperienceLibrary(defaultQueries, defaultConnectorLibrary);

View file

@ -1,7 +1,7 @@
import { UsersPasswordEncryptionMethod } from '@logto/schemas';
import { createMockPool } from 'slonik';
import Queries from '#src/tenants/Queries.js';
import { MockQueries } from '#src/test-utils/tenant.js';
const { jest } = import.meta;
@ -11,9 +11,8 @@ const pool = createMockPool({
const { encryptUserPassword, createUserLibrary } = await import('./user.js');
const queries = new Queries(pool);
const hasUserWithId = jest.spyOn(queries.users, 'hasUserWithId');
const hasUserWithId = jest.fn();
const queries = new MockQueries({ users: { hasUserWithId } });
describe('generateUserId()', () => {
const { generateUserId } = createUserLibrary(queries);

View file

@ -1,6 +1,7 @@
/* eslint-disable max-lines */
import type { EmailConnector, SmsConnector } from '@logto/connector-kit';
import { ConnectorPlatform, VerificationCodeType } from '@logto/connector-kit';
import type { Connector } from '@logto/schemas';
import { ConnectorType } from '@logto/schemas';
import { pickDefault, createMockUtils } from '@logto/shared/esm';
import { any } from 'zod';
@ -17,6 +18,8 @@ import {
mockLogtoConnector,
} from '#src/__mocks__/index.js';
import RequestError from '#src/errors/RequestError/index.js';
import Queries from '#src/tenants/Queries.js';
import { MockTenant } from '#src/test-utils/tenant.js';
import assertThat from '#src/utils/assert-that.js';
import { defaultConnectorMethods } from '#src/utils/connectors/consts.js';
import type { LogtoConnector } from '#src/utils/connectors/types.js';
@ -29,26 +32,22 @@ mockEsm('#src/utils/connectors/platform.js', () => ({
checkSocialConnectorTargetAndPlatformUniqueness: jest.fn(),
}));
const { removeUnavailableSocialConnectorTargets } = mockEsm(
'#src/libraries/sign-in-experience/index.js',
() => ({
removeUnavailableSocialConnectorTargets: jest.fn(),
})
);
const removeUnavailableSocialConnectorTargets = jest.fn();
const connectorQueries = {
findConnectorById: jest.fn(),
countConnectorByConnectorId: jest.fn(),
deleteConnectorById: jest.fn(),
deleteConnectorByIds: jest.fn(),
insertConnector: jest.fn(async (body) => body as Connector),
} satisfies Partial<Queries['connectors']>;
const {
findConnectorById,
countConnectorByConnectorId,
deleteConnectorById,
deleteConnectorByIds,
insertConnector,
} = await mockEsmWithActual('#src/queries/connector.js', () => ({
findConnectorById: jest.fn(),
countConnectorByConnectorId: jest.fn(),
deleteConnectorById: jest.fn(),
deleteConnectorByIds: jest.fn(),
insertConnector: jest.fn(async (body: unknown) => body),
}));
} = connectorQueries;
// eslint-disable-next-line @typescript-eslint/ban-types
const getLogtoConnectors = jest.fn<Promise<LogtoConnector[]>, []>();
@ -57,27 +56,35 @@ const { loadConnectorFactories } = mockEsm('#src/utils/connectors/factories.js',
loadConnectorFactories: jest.fn(),
}));
mockEsm('#src/libraries/connector.js', () => ({
getLogtoConnectors,
getLogtoConnectorById: async (connectorId: string) => {
const connectors = await getLogtoConnectors();
const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId);
assertThat(
connector,
new RequestError({
code: 'entity.not_found',
connectorId,
status: 404,
})
);
const tenantContext = new MockTenant(
undefined,
{ connectors: connectorQueries },
{
signInExperiences: { removeUnavailableSocialConnectorTargets },
connectors: {
getLogtoConnectors,
getLogtoConnectorById: async (connectorId: string) => {
const connectors = await getLogtoConnectors();
const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId);
assertThat(
connector,
new RequestError({
code: 'entity.not_found',
connectorId,
status: 404,
})
);
return connector;
},
},
}
);
return connector;
},
}));
const connectorRoutes = await pickDefault(import('./connector.js'));
describe('connector route', () => {
const connectorRequest = createRequester({ authedRoutes: connectorRoutes });
const connectorRequest = createRequester({ authedRoutes: connectorRoutes, tenantContext });
describe('GET /connectors', () => {
afterEach(() => {

View file

@ -6,17 +6,7 @@ import cleanDeep from 'clean-deep';
import { object, string } from 'zod';
import RequestError from '#src/errors/RequestError/index.js';
import { getLogtoConnectorById, getLogtoConnectors } from '#src/libraries/connector.js';
import { removeUnavailableSocialConnectorTargets } from '#src/libraries/sign-in-experience/index.js';
import koaGuard from '#src/middleware/koa-guard.js';
import {
findConnectorById,
countConnectorByConnectorId,
deleteConnectorById,
deleteConnectorByIds,
insertConnector,
updateConnector,
} from '#src/queries/connector.js';
import assertThat from '#src/utils/assert-that.js';
import { loadConnectorFactories } from '#src/utils/connectors/factories.js';
import { checkSocialConnectorTargetAndPlatformUniqueness } from '#src/utils/connectors/platform.js';
@ -36,7 +26,22 @@ const transpileLogtoConnector = ({
const generateConnectorId = buildIdGenerator(12);
export default function connectorRoutes<T extends AuthedRouter>(...[router]: RouterInitArgs<T>) {
export default function connectorRoutes<T extends AuthedRouter>(
...[router, { queries, libraries }]: RouterInitArgs<T>
) {
const {
findConnectorById,
countConnectorByConnectorId,
deleteConnectorById,
deleteConnectorByIds,
insertConnector,
updateConnector,
} = queries.connectors;
const {
connectors: { getLogtoConnectorById, getLogtoConnectors },
signInExperiences: { removeUnavailableSocialConnectorTargets },
} = libraries;
router.get(
'/connectors',
koaGuard({

View file

@ -1,6 +1,6 @@
import { ConnectorError, ConnectorErrorCodes } from '@logto/connector-kit';
import { ConnectorType } from '@logto/schemas';
import { pickDefault, createMockUtils } from '@logto/shared/esm';
import { pickDefault } from '@logto/shared/esm';
import {
mockMetadata,
@ -9,53 +9,56 @@ import {
mockLogtoConnector,
} from '#src/__mocks__/index.js';
import RequestError from '#src/errors/RequestError/index.js';
import { MockTenant } from '#src/test-utils/tenant.js';
import assertThat from '#src/utils/assert-that.js';
import type { LogtoConnector } from '#src/utils/connectors/types.js';
import { createRequester } from '#src/utils/test-utils.js';
const { jest } = import.meta;
const { mockEsm, mockEsmWithActual } = createMockUtils(jest);
const getLogtoConnectors = jest.fn() as jest.MockedFunction<() => Promise<LogtoConnector[]>>;
const getLogtoConnectorById = jest.fn(async (connectorId: string) => {
const connectors = await getLogtoConnectors();
const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId);
const getLogtoConnectors: jest.MockedFunction<() => Promise<LogtoConnector[]>> = jest.fn();
const getLogtoConnectorById: jest.MockedFunction<(connectorId: string) => Promise<LogtoConnector>> =
jest.fn(async (connectorId: string) => {
const connectors = await getLogtoConnectors();
const connector = connectors.find(({ dbEntry }) => dbEntry.id === connectorId);
assertThat(
connector,
new RequestError({
code: 'entity.not_found',
connectorId,
status: 404,
})
);
assertThat(
connector,
new RequestError({
code: 'entity.not_found',
connectorId,
status: 404,
})
);
return {
...connector,
sendMessage: sendMessagePlaceHolder,
};
}) as jest.MockedFunction<(connectorId: string) => Promise<LogtoConnector>>;
return {
...connector,
sendMessage: sendMessagePlaceHolder,
};
});
const sendMessagePlaceHolder = jest.fn();
const updateConnector = jest.fn();
const { updateConnector } = await mockEsmWithActual('#src/queries/connector.js', () => ({
updateConnector: jest.fn(),
}));
await mockEsmWithActual('#src/libraries/connector.js', () => ({
getLogtoConnectors,
getLogtoConnectorById,
}));
mockEsm('#src/libraries/sign-in-experience.js', () => ({
// eslint-disable-next-line @typescript-eslint/no-empty-function
removeUnavailableSocialConnectorTargets: async () => {},
}));
const tenantContext = new MockTenant(
undefined,
{ connectors: { updateConnector } },
{
connectors: {
getLogtoConnectors,
getLogtoConnectorById,
},
signInExperiences: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
removeUnavailableSocialConnectorTargets: async () => {},
},
}
);
const connectorRoutes = await pickDefault(import('./connector.js'));
describe('connector PATCH routes', () => {
const connectorRequest = createRequester({ authedRoutes: connectorRoutes });
const connectorRequest = createRequester({ authedRoutes: connectorRoutes, tenantContext });
describe('PATCH /connectors/:id', () => {
afterEach(() => {

View file

@ -3,7 +3,7 @@ import type { SocialUserInfo } from '@logto/connector-kit';
import type { User } from '@logto/schemas';
import Provider from 'oidc-provider';
import { mockLogtoConnectorList, mockSignInExperience, mockUser } from '#src/__mocks__/index.js';
import { mockSignInExperience, mockUser } from '#src/__mocks__/index.js';
import RequestError from '#src/errors/RequestError/index.js';
import { getLogtoConnectorById } from '#src/libraries/connector.js';
import { createRequester } from '#src/utils/test-utils.js';
@ -91,7 +91,6 @@ const getLogtoConnectorByIdHelper = jest.fn(async (connectorId: string) => {
});
jest.mock('#src/libraries/connector.js', () => ({
getLogtoConnectors: jest.fn(async () => mockLogtoConnectorList),
getLogtoConnectorById: jest.fn(async (connectorId: string) => {
const connector = await getLogtoConnectorByIdHelper(connectorId);

View file

@ -1,17 +1,11 @@
import type { CreateSignInExperience, SignInExperience } from '@logto/schemas';
import { BrandingStyle } from '@logto/schemas';
import { pickDefault, createMockUtils } from '@logto/shared/esm';
import { pickDefault } from '@logto/shared/esm';
import { mockBranding, mockSignInExperience } from '#src/__mocks__/index.js';
import { MockTenant } from '#src/test-utils/tenant.js';
import { createRequester } from '#src/utils/test-utils.js';
const { mockEsm } = createMockUtils(import.meta.jest);
mockEsm('#src/libraries/connector.js', () => ({
getLogtoConnectors: async () => [],
}));
const tenantContext = new MockTenant(undefined, {
signInExperiences: {
updateDefaultSignInExperience: async (

View file

@ -7,10 +7,6 @@ import { createRequester } from '#src/utils/test-utils.js';
const { mockEsm } = createMockUtils(import.meta.jest);
mockEsm('#src/libraries/connector.js', () => ({
getLogtoConnectors: async () => [],
}));
const signInExperiencesRoutes = await pickDefault(import('./index.js'));
const signInExperienceRequester = createRequester({
authedRoutes: signInExperiencesRoutes,

View file

@ -1,29 +1,10 @@
import type { CreateSignInExperience, SignInExperience } from '@logto/schemas';
import { pickDefault, createMockUtils } from '@logto/shared/esm';
import { pickDefault } from '@logto/shared/esm';
import {
mockAliyunDmConnector,
mockAliyunSmsConnector,
mockFacebookConnector,
mockGithubConnector,
mockGoogleConnector,
mockLanguageInfo,
mockSignInExperience,
} from '#src/__mocks__/index.js';
import { mockLanguageInfo, mockSignInExperience } from '#src/__mocks__/index.js';
import { MockTenant } from '#src/test-utils/tenant.js';
const { jest } = import.meta;
const { mockEsm } = createMockUtils(jest);
mockEsm('#src/libraries/connector.js', () => ({
getLogtoConnectors: jest.fn(async () => [
mockAliyunDmConnector,
mockAliyunSmsConnector,
mockFacebookConnector,
mockGithubConnector,
mockGoogleConnector,
]),
}));
const validateLanguageInfo = jest.fn();

View file

@ -29,10 +29,6 @@ const logtoConnectors = [
mockAliyunSmsConnector,
];
await mockEsmWithActual('#src/libraries/connector.js', () => ({
getLogtoConnectors: async () => logtoConnectors,
}));
const { validateBranding, validateSignIn, validateSignUp } = await mockEsmWithActual(
'#src/libraries/sign-in-experience/index.js',
() => ({
@ -58,7 +54,10 @@ const validateLanguageInfo = jest.fn();
const tenantContext = new MockTenant(
undefined,
{ signInExperiences, customPhrases: { findAllCustomLanguageTags: async () => [] } },
{ signInExperiences: { validateLanguageInfo } }
{
signInExperiences: { validateLanguageInfo },
connectors: { getLogtoConnectors: async () => logtoConnectors },
}
);
const signInExperiencesRoutes = await pickDefault(import('./index.js'));

View file

@ -1,7 +1,6 @@
import { ConnectorType, SignInExperiences } from '@logto/schemas';
import { literal, object, string } from 'zod';
import { getLogtoConnectors } from '#src/libraries/connector.js';
import {
validateBranding,
validateSignUp,
@ -15,7 +14,10 @@ export default function signInExperiencesRoutes<T extends AuthedRouter>(
...[router, { queries, libraries }]: RouterInitArgs<T>
) {
const { findDefaultSignInExperience, updateDefaultSignInExperience } = queries.signInExperiences;
const { validateLanguageInfo } = libraries.signInExperiences;
const {
signInExperiences: { validateLanguageInfo },
connectors: { getLogtoConnectors },
} = libraries;
/**
* As we only support single signInExperience settings for V1

View file

@ -17,7 +17,7 @@ import {
} from '#src/__mocks__/index.js';
const { jest } = import.meta;
const { mockEsm, mockEsmWithActual } = createMockUtils(jest);
const { mockEsmWithActual } = createMockUtils(jest);
await mockEsmWithActual('i18next', () => ({
default: {
@ -31,18 +31,6 @@ const sieQueries = {
};
const { findDefaultSignInExperience } = sieQueries;
mockEsm('#src/libraries/connector.js', () => ({
getLogtoConnectors: jest.fn(async () => [
mockAliyunDmConnector,
mockAliyunSmsConnector,
mockFacebookConnector,
mockGithubConnector,
mockGoogleConnector,
mockWechatConnector,
mockWechatNativeConnector,
]),
}));
const wellKnownRoutes = await pickDefault(import('#src/routes/well-known.js'));
const { createMockProvider } = await import('#src/test-utils/oidc-provider.js');
const { MockTenant } = await import('#src/test-utils/tenant.js');
@ -56,10 +44,26 @@ describe('GET /.well-known/sign-in-exp', () => {
const provider = createMockProvider();
const sessionRequest = createRequester({
anonymousRoutes: wellKnownRoutes,
tenantContext: new MockTenant(provider, {
signInExperiences: sieQueries,
users: { hasActiveUsers: jest.fn().mockResolvedValue(true) },
}),
tenantContext: new MockTenant(
provider,
{
signInExperiences: sieQueries,
users: { hasActiveUsers: jest.fn().mockResolvedValue(true) },
},
{
connectors: {
getLogtoConnectors: jest.fn(async () => [
mockAliyunDmConnector,
mockAliyunSmsConnector,
mockFacebookConnector,
mockGithubConnector,
mockGoogleConnector,
mockWechatConnector,
mockWechatNativeConnector,
]),
},
}
),
middlewares: [
async (ctx, next) => {
ctx.addLogContext = jest.fn();

View file

@ -3,7 +3,6 @@ import { ConnectorType } from '@logto/connector-kit';
import { adminConsoleApplicationId } from '@logto/schemas';
import etag from 'etag';
import { getLogtoConnectors } from '#src/libraries/connector.js';
import { getApplicationIdFromInteraction } from '#src/libraries/session.js';
import type { AnonymousRouter, RouterInitArgs } from './types.js';
@ -11,7 +10,10 @@ import type { AnonymousRouter, RouterInitArgs } from './types.js';
export default function wellKnownRoutes<T extends AnonymousRouter>(
...[router, { provider, libraries }]: RouterInitArgs<T>
) {
const { getSignInExperienceForApplication } = libraries.signInExperiences;
const {
signInExperiences: { getSignInExperienceForApplication },
connectors: { getLogtoConnectors },
} = libraries;
router.get(
'/.well-known/sign-in-exp',

View file

@ -1,11 +1,13 @@
import { createConnectorLibrary } from '#src/libraries/connector.js';
import { createSignInExperienceLibrary } from '#src/libraries/sign-in-experience/index.js';
import { createUserLibrary } from '#src/libraries/user.js';
import type Queries from './Queries.js';
export default class Libraries {
connectors = createConnectorLibrary(this.queries);
users = createUserLibrary(this.queries);
signInExperiences = createSignInExperienceLibrary(this.queries);
signInExperiences = createSignInExperienceLibrary(this.queries, this.connectors);
constructor(public readonly queries: Queries) {}
}

View file

@ -6,15 +6,6 @@ import type TenantContext from '#src/tenants/TenantContext.js';
import { createMockProvider } from './oidc-provider.js';
export const createQueriesWithMockPool = () =>
new Queries(
createMockPool({
query: async (sql, values) => {
return createMockQueryResult([]);
},
})
);
export class MockQueries extends Queries {
constructor(queriesOverride?: Partial2<Queries>) {
super(