0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor(toolkit,core,connector): add connector switch for WIP features

This commit is contained in:
Darcy Ye 2023-07-08 14:19:04 +08:00
parent 3efd6485fc
commit 26466e6542
No known key found for this signature in database
GPG key ID: B46F4C07EDEFC610
10 changed files with 51 additions and 27 deletions

View file

@ -1,5 +1,3 @@
import { getEnv } from '@silverhand/essentials';
import type { ConnectorMetadata } from '@logto/connector-kit'; import type { ConnectorMetadata } from '@logto/connector-kit';
import { ConnectorConfigFormItemType } from '@logto/connector-kit'; import { ConnectorConfigFormItemType } from '@logto/connector-kit';
@ -102,11 +100,9 @@ export const defaultMetadata: ConnectorMetadata = {
export const scope = ['send:email']; export const scope = ['send:email'];
export const defaultTimeout = 5000; export const defaultTimeout = 10_000;
export const oldEmailEndpoint = '/services/send-email'; export const oldEmailEndpoint = '/services/send-email';
export const newEmailEndpoint = '/services/mails'; export const newEmailEndpoint = '/services/mails';
export const emailEndpoint =
getEnv('NODE_ENV') === 'production' ? oldEmailEndpoint : newEmailEndpoint;
export const usageEndpoint = '/services/mails/usage'; export const usageEndpoint = '/services/mails/usage';

View file

@ -2,7 +2,7 @@ import nock from 'nock';
import { VerificationCodeType } from '@logto/connector-kit'; import { VerificationCodeType } from '@logto/connector-kit';
import { emailEndpoint } from './constant.js'; import { newEmailEndpoint } from './constant.js';
import { mockedAccessTokenResponse, mockedConfig } from './mock.js'; import { mockedAccessTokenResponse, mockedConfig } from './mock.js';
const { jest } = import.meta; const { jest } = import.meta;
@ -17,14 +17,18 @@ describe('sendMessage()', () => {
}); });
it('should send message successfully', async () => { it('should send message successfully', async () => {
nock(mockedConfig.endpoint).post(emailEndpoint).reply(200); nock(mockedConfig.endpoint).post(newEmailEndpoint).reply(200);
const connector = await createConnector({ getConfig }); const connector = await createConnector({ getConfig });
await expect( await expect(
connector.sendMessage({ connector.sendMessage(
to: 'wangsijie94@gmail.com', {
type: VerificationCodeType.SignIn, to: 'wangsijie94@gmail.com',
payload: { code: '1234' }, type: VerificationCodeType.SignIn,
}) payload: { code: '1234' },
},
undefined,
false // Set to `false` since this is not production env.
)
).resolves.not.toThrow(); ).resolves.not.toThrow();
}); });
}); });

View file

@ -15,7 +15,13 @@ import {
ConnectorErrorCodes, ConnectorErrorCodes,
} from '@logto/connector-kit'; } from '@logto/connector-kit';
import { defaultMetadata, defaultTimeout, emailEndpoint, usageEndpoint } from './constant.js'; import {
defaultMetadata,
defaultTimeout,
oldEmailEndpoint,
newEmailEndpoint,
usageEndpoint,
} from './constant.js';
import { grantAccessToken } from './grant-access-token.js'; import { grantAccessToken } from './grant-access-token.js';
import type { LogtoEmailConfig } from './types.js'; import type { LogtoEmailConfig } from './types.js';
import { logtoEmailConfigGuard } from './types.js'; import { logtoEmailConfigGuard } from './types.js';
@ -24,9 +30,10 @@ export type { EmailServiceBasicConfig } from './types.js';
const sendMessage = const sendMessage =
(getConfig: GetConnectorConfig): SendMessageFunction => (getConfig: GetConnectorConfig): SendMessageFunction =>
async (data, inputConfig) => { async (data, inputConfig, isDevelopment) => {
const config = inputConfig ?? (await getConfig(defaultMetadata.id)); const config = inputConfig ?? (await getConfig(defaultMetadata.id));
validateConfig<LogtoEmailConfig>(config, logtoEmailConfigGuard); validateConfig<LogtoEmailConfig>(config, logtoEmailConfigGuard);
const emailEndpoint = isDevelopment ? oldEmailEndpoint : newEmailEndpoint;
const { const {
endpoint, endpoint,

View file

@ -15,7 +15,8 @@ export type ConnectorLibrary = ReturnType<typeof createConnectorLibrary>;
export const createConnectorLibrary = ( export const createConnectorLibrary = (
queries: Queries, queries: Queries,
cloudConnection: CloudConnectionLibrary cloudConnection: CloudConnectionLibrary,
isProduction: boolean
) => { ) => {
const { findAllConnectors, findAllConnectorsWellKnown } = queries.connectors; const { findAllConnectors, findAllConnectorsWellKnown } = queries.connectors;
const { getCloudConnectionData } = cloudConnection; const { getCloudConnectionData } = cloudConnection;
@ -99,6 +100,7 @@ export const createConnectorLibrary = (
validateConfig(config, rawConnector.configGuard); validateConfig(config, rawConnector.configGuard);
}, },
dbEntry: databaseConnector, dbEntry: databaseConnector,
isDevelopment: isProduction && ServiceConnector.Email === connectorFactory.metadata.id,
}; };
} catch {} } catch {}
}) })

View file

@ -83,7 +83,7 @@ export const createPasscodeLibrary = (queries: Queries, connectorLibrary: Connec
}) })
); );
const { dbEntry, metadata, sendMessage } = connector; const { dbEntry, metadata, sendMessage, isDevelopment } = connector;
const messageTypeResult = verificationCodeTypeGuard.safeParse(passcode.type); const messageTypeResult = verificationCodeTypeGuard.safeParse(passcode.type);
@ -91,13 +91,17 @@ export const createPasscodeLibrary = (queries: Queries, connectorLibrary: Connec
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig); throw new ConnectorError(ConnectorErrorCodes.InvalidConfig);
} }
const response = await sendMessage({ const response = await sendMessage(
to: emailOrPhone, {
type: messageTypeResult.data, to: emailOrPhone,
payload: { type: messageTypeResult.data,
code: passcode.code, payload: {
code: passcode.code,
},
}, },
}); undefined,
isDevelopment
);
return { dbEntry, metadata, response }; return { dbEntry, metadata, response };
}; };

View file

@ -11,6 +11,7 @@ import { phoneRegEx, emailRegEx } from '@logto/core-kit';
import { jsonObjectGuard, ConnectorType } from '@logto/schemas'; import { jsonObjectGuard, ConnectorType } from '@logto/schemas';
import { string, object } from 'zod'; import { string, object } from 'zod';
import { EnvSet } from '#src/env-set/index.js';
import RequestError from '#src/errors/RequestError/index.js'; import RequestError from '#src/errors/RequestError/index.js';
import koaGuard from '#src/middleware/koa-guard.js'; import koaGuard from '#src/middleware/koa-guard.js';
import assertThat from '#src/utils/assert-that.js'; import assertThat from '#src/utils/assert-that.js';
@ -84,7 +85,8 @@ export default function connectorConfigTestingRoutes<T extends AuthedRouter>(
code: '000000', code: '000000',
}, },
}, },
config config,
ServiceConnector.Email === connectorFactory.metadata.id && EnvSet.values.isProduction
); );
ctx.status = 204; ctx.status = 204;

View file

@ -56,7 +56,11 @@ export default class Tenant implements TenantContext {
public readonly queries = new Queries(envSet.pool, wellKnownCache), public readonly queries = new Queries(envSet.pool, wellKnownCache),
public readonly logtoConfigs = createLogtoConfigLibrary(queries), public readonly logtoConfigs = createLogtoConfigLibrary(queries),
public readonly cloudConnection = createCloudConnectionLibrary(logtoConfigs), public readonly cloudConnection = createCloudConnectionLibrary(logtoConfigs),
public readonly connectors = createConnectorLibrary(queries, cloudConnection), public readonly connectors = createConnectorLibrary(
queries,
cloudConnection,
EnvSet.values.isProduction
),
public readonly libraries = new Libraries(id, queries, connectors) public readonly libraries = new Libraries(id, queries, connectors)
) { ) {
const isAdminTenant = id === adminTenantId; const isAdminTenant = id === adminTenantId;

View file

@ -76,7 +76,8 @@ export class MockTenant implements TenantContext {
this.logtoConfigs = createLogtoConfigLibrary(this.queries); this.logtoConfigs = createLogtoConfigLibrary(this.queries);
this.cloudConnection = createCloudConnectionLibrary(this.logtoConfigs); this.cloudConnection = createCloudConnectionLibrary(this.logtoConfigs);
this.connectors = { this.connectors = {
...createConnectorLibrary(this.queries, this.cloudConnection), // Manually set the third argument `isDevelopment` to `false` since this is not a production environment.
...createConnectorLibrary(this.queries, this.cloudConnection, false),
...connectorsOverride, ...connectorsOverride,
}; };
this.libraries = new Libraries(this.id, this.queries, this.connectors); this.libraries = new Libraries(this.id, this.queries, this.connectors);

View file

@ -9,7 +9,7 @@ export { ConnectorType } from '@logto/schemas';
*/ */
export type LogtoConnector<T extends AllConnector = AllConnector> = T & { export type LogtoConnector<T extends AllConnector = AllConnector> = T & {
validateConfig: (config: unknown) => void; validateConfig: (config: unknown) => void;
} & { dbEntry: Connector }; } & { dbEntry: Connector; isDevelopment: boolean };
export const connectorWellKnownGuard = Connectors.guard.pick({ export const connectorWellKnownGuard = Connectors.guard.pick({
id: true, id: true,

View file

@ -240,7 +240,11 @@ export const sendMessagePayloadGuard = z.object({
export type SendMessagePayload = z.infer<typeof sendMessagePayloadGuard>; export type SendMessagePayload = z.infer<typeof sendMessagePayloadGuard>;
export type SendMessageFunction = (data: SendMessagePayload, config?: unknown) => Promise<unknown>; export type SendMessageFunction = (
data: SendMessagePayload,
config?: unknown,
isDevelopment?: boolean
) => Promise<unknown>;
export type GetUsageFunction = (startFrom?: Date) => Promise<number>; export type GetUsageFunction = (startFrom?: Date) => Promise<number>;