mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
feat(connector): add line connector (#7039)
This commit is contained in:
parent
695fb6f090
commit
3d4f74675f
11 changed files with 576 additions and 95 deletions
5
.changeset/itchy-impalas-remain.md
Normal file
5
.changeset/itchy-impalas-remain.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@logto/connector-line": minor
|
||||
---
|
||||
|
||||
add Line social connector
|
57
packages/connectors/connector-line/README.md
Normal file
57
packages/connectors/connector-line/README.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Line connector
|
||||
|
||||
The official Logto connector for Line social sign-in.
|
||||
|
||||
**Table of contents**
|
||||
- [Line connector](#line-connector)
|
||||
- [Get started](#get-started)
|
||||
- [Setup a Line channel](#setup-a-line-channel)
|
||||
- [Configure your connector](#configure-your-connector)
|
||||
- [Config types](#config-types)
|
||||
- [Test Line connector](#test-line-connector)
|
||||
- [Reference](#reference)
|
||||
|
||||
## Get started
|
||||
|
||||
The Line connector enables end-users to sign in to your application using their own Line accounts via the Line OAuth 2.0 authentication protocol.
|
||||
|
||||
## Setup a Line channel
|
||||
|
||||
Go to the [Line Developers](https://developers.line.biz/console/) and sign in with your Line business account. If you don’t have an account, you can register for one.
|
||||
|
||||
Then, go to [this link](https://developers.line.biz/console/register/line-login/provider/) to create a channel.
|
||||
|
||||
**Step 1:** Fill in the Channel Details.
|
||||
|
||||
Complete the form and create the channel.
|
||||
|
||||
**Step 2:** Setup callback URLs.
|
||||
|
||||
Go to channel details page and find "LINE login" tab and edit the "Callback URL" field.
|
||||
|
||||
In our case, this will be `${your_logto_endpoint}/callback/${connector_id}`. e.g. `https://foo.logto.app/callback/${connector_id}`. The `connector_id` can be found on the top bar of the Logto Admin Console connector details page.
|
||||
|
||||
## Configure your connector
|
||||
|
||||
In your Logto connector configuration, fill out the following fields with the values obtained from your App's "Auth" tab, "Application credentials" section:
|
||||
|
||||
- **clientId:** Your App's Channel ID.
|
||||
- **clientSecret:** Your App's Channel Secret.
|
||||
|
||||
`scope` is a space-delimited list of OIDC scopes. If not provided, the default scope is `openid profile`.
|
||||
|
||||
### Config types
|
||||
|
||||
| Name | Type |
|
||||
| ------------ | ------ |
|
||||
| clientId | string |
|
||||
| clientSecret | string |
|
||||
| scope | string |
|
||||
|
||||
## Test Line connector
|
||||
|
||||
That's it! The Line connector should now be available for end-users to sign in with their Line accounts. Don't forget to [Enable the connector in the sign-in experience](https://docs.logto.io/docs/recipes/configure-connectors/social-connector/enable-social-sign-in/).
|
||||
|
||||
## Reference
|
||||
|
||||
- [Line Developer Documentation](https://developers.line.biz/en/docs/line-login/overview/)
|
3
packages/connectors/connector-line/logo.svg
Normal file
3
packages/connectors/connector-line/logo.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 48 48">
|
||||
<path fill="#00c300" d="M12.5,42h23c3.59,0,6.5-2.91,6.5-6.5v-23C42,8.91,39.09,6,35.5,6h-23C8.91,6,6,8.91,6,12.5v23C6,39.09,8.91,42,12.5,42z"></path><path fill="#fff" d="M37.113,22.417c0-5.865-5.88-10.637-13.107-10.637s-13.108,4.772-13.108,10.637c0,5.258,4.663,9.662,10.962,10.495c0.427,0.092,1.008,0.282,1.155,0.646c0.132,0.331,0.086,0.85,0.042,1.185c0,0-0.153,0.925-0.187,1.122c-0.057,0.331-0.263,1.296,1.135,0.707c1.399-0.589,7.548-4.445,10.298-7.611h-0.001C36.203,26.879,37.113,24.764,37.113,22.417z M18.875,25.907h-2.604c-0.379,0-0.687-0.308-0.687-0.688V20.01c0-0.379,0.308-0.687,0.687-0.687c0.379,0,0.687,0.308,0.687,0.687v4.521h1.917c0.379,0,0.687,0.308,0.687,0.687C19.562,25.598,19.254,25.907,18.875,25.907z M21.568,25.219c0,0.379-0.308,0.688-0.687,0.688s-0.687-0.308-0.687-0.688V20.01c0-0.379,0.308-0.687,0.687-0.687s0.687,0.308,0.687,0.687V25.219z M27.838,25.219c0,0.297-0.188,0.559-0.47,0.652c-0.071,0.024-0.145,0.036-0.218,0.036c-0.215,0-0.42-0.103-0.549-0.275l-2.669-3.635v3.222c0,0.379-0.308,0.688-0.688,0.688c-0.379,0-0.688-0.308-0.688-0.688V20.01c0-0.296,0.189-0.558,0.47-0.652c0.071-0.024,0.144-0.035,0.218-0.035c0.214,0,0.42,0.103,0.549,0.275l2.67,3.635V20.01c0-0.379,0.309-0.687,0.688-0.687c0.379,0,0.687,0.308,0.687,0.687V25.219z M32.052,21.927c0.379,0,0.688,0.308,0.688,0.688c0,0.379-0.308,0.687-0.688,0.687h-1.917v1.23h1.917c0.379,0,0.688,0.308,0.688,0.687c0,0.379-0.309,0.688-0.688,0.688h-2.604c-0.378,0-0.687-0.308-0.687-0.688v-2.603c0-0.001,0-0.001,0-0.001c0,0,0-0.001,0-0.001v-2.601c0-0.001,0-0.001,0-0.002c0-0.379,0.308-0.687,0.687-0.687h2.604c0.379,0,0.688,0.308,0.688,0.687s-0.308,0.687-0.688,0.687h-1.917v1.23H32.052z"></path>
|
||||
</svg>
|
After (image error) Size: 1.7 KiB |
70
packages/connectors/connector-line/package.json
Normal file
70
packages/connectors/connector-line/package.json
Normal file
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"name": "@logto/connector-line",
|
||||
"version": "0.0.0",
|
||||
"description": "Line web connector implementation.",
|
||||
"author": "Silverhand Inc. <contact@silverhand.io>",
|
||||
"dependencies": {
|
||||
"@logto/connector-kit": "workspace:^4.0.0",
|
||||
"@silverhand/essentials": "^2.9.1",
|
||||
"ky": "^1.2.3",
|
||||
"query-string": "^9.0.0",
|
||||
"snakecase-keys": "^8.0.1",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"main": "./lib/index.js",
|
||||
"module": "./lib/index.js",
|
||||
"exports": "./lib/index.js",
|
||||
"license": "MPL-2.0",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"lib",
|
||||
"docs",
|
||||
"logo.svg",
|
||||
"logo-dark.svg"
|
||||
],
|
||||
"scripts": {
|
||||
"precommit": "lint-staged",
|
||||
"check": "tsc --noEmit",
|
||||
"build": "tsup",
|
||||
"dev": "tsup --watch",
|
||||
"lint": "eslint --ext .ts src",
|
||||
"lint:report": "pnpm lint --format json --output-file report.json",
|
||||
"test": "vitest src",
|
||||
"test:ci": "pnpm run test --silent --coverage",
|
||||
"prepublishOnly": "pnpm build"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.9.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "@silverhand",
|
||||
"settings": {
|
||||
"import/core-modules": [
|
||||
"@silverhand/essentials",
|
||||
"got",
|
||||
"nock",
|
||||
"snakecase-keys",
|
||||
"zod"
|
||||
]
|
||||
}
|
||||
},
|
||||
"prettier": "@silverhand/eslint-config/.prettierrc",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@silverhand/eslint-config": "6.0.1",
|
||||
"@silverhand/ts-config": "6.0.0",
|
||||
"@types/node": "^20.11.20",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@vitest/coverage-v8": "^2.1.8",
|
||||
"eslint": "^8.56.0",
|
||||
"lint-staged": "^15.0.2",
|
||||
"nock": "14.0.0-beta.15",
|
||||
"prettier": "^3.0.0",
|
||||
"supertest": "^7.0.0",
|
||||
"tsup": "^8.3.0",
|
||||
"typescript": "^5.5.3",
|
||||
"vitest": "^2.1.8"
|
||||
}
|
||||
}
|
54
packages/connectors/connector-line/src/constant.ts
Normal file
54
packages/connectors/connector-line/src/constant.ts
Normal file
|
@ -0,0 +1,54 @@
|
|||
import type { ConnectorMetadata } from '@logto/connector-kit';
|
||||
import { ConnectorPlatform, ConnectorConfigFormItemType } from '@logto/connector-kit';
|
||||
|
||||
// See https://developers.line.biz/en/docs/line-login/overview/
|
||||
export const authorizationEndpoint = 'https://access.line.me/oauth2/v2.1/authorize';
|
||||
export const defaultScope = 'openid profile';
|
||||
export const accessTokenEndpoint = 'https://api.line.me/oauth2/v2.1/token';
|
||||
export const userInfoEndpoint = 'https://api.line.me/v2/profile';
|
||||
|
||||
export const defaultMetadata: ConnectorMetadata = {
|
||||
id: 'line-universal',
|
||||
target: 'line',
|
||||
platform: ConnectorPlatform.Universal,
|
||||
name: {
|
||||
en: 'Line',
|
||||
'zh-CN': 'Line',
|
||||
'tr-TR': 'Line',
|
||||
ko: 'Line',
|
||||
},
|
||||
logo: './logo.svg',
|
||||
logoDark: null,
|
||||
description: {
|
||||
en: 'Line is a social media platform for sharing information and connecting with friends.',
|
||||
'zh-CN': 'Line是一个分享信息和与朋友连接的社交媒体平台。',
|
||||
'tr-TR':
|
||||
'Line, bilgi paylaşma ve arkadaşlarınızla bağlantı kurma için bir sosyal medya platformudur.',
|
||||
ko: 'Line은 정보 공유와 친구들과의 연결을 위한 소셜 미디어 플랫폼입니다.',
|
||||
},
|
||||
readme: './README.md',
|
||||
formItems: [
|
||||
{
|
||||
key: 'clientId',
|
||||
type: ConnectorConfigFormItemType.Text,
|
||||
label: 'Client ID (Channel ID)',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
key: 'clientSecret',
|
||||
type: ConnectorConfigFormItemType.Text,
|
||||
label: 'Client Secret (Channel Secret)',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
key: 'scope',
|
||||
type: ConnectorConfigFormItemType.Text,
|
||||
label: 'Scope',
|
||||
required: false,
|
||||
description:
|
||||
"The `scope` determines permissions granted by the user's authorization. If you are not sure what to enter, do not worry, just leave it blank.",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const defaultTimeout = 5000;
|
92
packages/connectors/connector-line/src/index.test.ts
Normal file
92
packages/connectors/connector-line/src/index.test.ts
Normal file
|
@ -0,0 +1,92 @@
|
|||
import nock from 'nock';
|
||||
|
||||
import { accessTokenEndpoint, authorizationEndpoint, userInfoEndpoint } from './constant.js';
|
||||
import createConnector, { getAccessToken } from './index.js';
|
||||
import { mockedConfig } from './mock.js';
|
||||
|
||||
const getConfig = vi.fn().mockResolvedValue(mockedConfig);
|
||||
const setSession = vi.fn();
|
||||
const getSession = vi.fn().mockResolvedValue({
|
||||
redirectUri: 'http://localhost:3000/callback',
|
||||
});
|
||||
|
||||
describe('getAuthorizationUri', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should get a valid uri by redirectUri and state', async () => {
|
||||
const connector = await createConnector({ getConfig });
|
||||
const authorizationUri = await connector.getAuthorizationUri(
|
||||
{
|
||||
state: 'some_state',
|
||||
redirectUri: 'http://localhost:3000/callback',
|
||||
connectorId: 'some_connector_id',
|
||||
connectorFactoryId: 'some_connector_factory_id',
|
||||
jti: 'some_jti',
|
||||
headers: {},
|
||||
},
|
||||
setSession
|
||||
);
|
||||
expect(setSession).toHaveBeenCalledWith({
|
||||
redirectUri: 'http://localhost:3000/callback',
|
||||
});
|
||||
expect(authorizationUri).toEqual(
|
||||
`${authorizationEndpoint}?response_type=code&client_id=%3Cclient-id%3E&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&scope=openid+profile&state=some_state`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAccessToken', () => {
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should get an accessToken by exchanging with code', async () => {
|
||||
nock(accessTokenEndpoint).post('').reply(200, {
|
||||
access_token: 'access_token',
|
||||
});
|
||||
const { access_token } = await getAccessToken(mockedConfig, 'code', 'redirectUri');
|
||||
expect(access_token).toEqual('access_token');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUserInfo', () => {
|
||||
beforeEach(() => {
|
||||
nock(accessTokenEndpoint).post('').query(true).reply(200, {
|
||||
access_token: 'access_token',
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should get valid SocialUserInfo', async () => {
|
||||
nock(userInfoEndpoint).get('').reply(200, {
|
||||
userId: '1',
|
||||
displayName: 'monalisa',
|
||||
});
|
||||
const connector = await createConnector({ getConfig });
|
||||
const socialUserInfo = await connector.getUserInfo(
|
||||
{ code: 'code', redirectUri: 'http://localhost:3000/callback' },
|
||||
getSession
|
||||
);
|
||||
expect(socialUserInfo).toStrictEqual({
|
||||
id: '1',
|
||||
name: 'monalisa',
|
||||
rawData: {
|
||||
userId: '1',
|
||||
displayName: 'monalisa',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('throws unrecognized error', async () => {
|
||||
nock(userInfoEndpoint).get('').reply(500);
|
||||
const connector = await createConnector({ getConfig });
|
||||
await expect(connector.getUserInfo({ code: 'code' }, vi.fn())).rejects.toThrow();
|
||||
});
|
||||
});
|
145
packages/connectors/connector-line/src/index.ts
Normal file
145
packages/connectors/connector-line/src/index.ts
Normal file
|
@ -0,0 +1,145 @@
|
|||
import { conditional } from '@silverhand/essentials';
|
||||
|
||||
import {
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
validateConfig,
|
||||
ConnectorType,
|
||||
jsonGuard,
|
||||
} from '@logto/connector-kit';
|
||||
import type {
|
||||
GetAuthorizationUri,
|
||||
GetUserInfo,
|
||||
SocialConnector,
|
||||
CreateConnector,
|
||||
GetConnectorConfig,
|
||||
} from '@logto/connector-kit';
|
||||
import ky, { HTTPError } from 'ky';
|
||||
|
||||
import {
|
||||
authorizationEndpoint,
|
||||
accessTokenEndpoint,
|
||||
defaultMetadata,
|
||||
defaultTimeout,
|
||||
defaultScope,
|
||||
userInfoEndpoint,
|
||||
} from './constant.js';
|
||||
import type { LineConfig } from './types.js';
|
||||
import {
|
||||
lineConfigGuard,
|
||||
userInfoResponseGuard,
|
||||
authResponseGuard,
|
||||
accessTokenResponseGuard,
|
||||
} from './types.js';
|
||||
|
||||
const getAuthorizationUri =
|
||||
(getConfig: GetConnectorConfig): GetAuthorizationUri =>
|
||||
async ({ state, redirectUri }, setSession) => {
|
||||
const config = await getConfig(defaultMetadata.id);
|
||||
validateConfig(config, lineConfigGuard);
|
||||
|
||||
await setSession({ redirectUri });
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
client_id: config.clientId,
|
||||
redirect_uri: redirectUri,
|
||||
scope: config.scope ?? defaultScope,
|
||||
state,
|
||||
});
|
||||
|
||||
return `${authorizationEndpoint}?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
export const getAccessToken = async (config: LineConfig, code: string, redirectUri: string) => {
|
||||
const response = await ky
|
||||
.post(accessTokenEndpoint, {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
code,
|
||||
redirect_uri: redirectUri,
|
||||
client_id: config.clientId,
|
||||
client_secret: config.clientSecret,
|
||||
}).toString(),
|
||||
timeout: defaultTimeout,
|
||||
})
|
||||
.json();
|
||||
|
||||
return accessTokenResponseGuard.parse(response);
|
||||
};
|
||||
|
||||
const getUserInfo =
|
||||
(getConfig: GetConnectorConfig): GetUserInfo =>
|
||||
async (data, getSession) => {
|
||||
const config = await getConfig(defaultMetadata.id);
|
||||
validateConfig(config, lineConfigGuard);
|
||||
|
||||
const authResponseResult = authResponseGuard.safeParse(data);
|
||||
|
||||
if (!authResponseResult.success) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(data));
|
||||
}
|
||||
|
||||
const { code } = authResponseResult.data;
|
||||
const { redirectUri } = await getSession();
|
||||
|
||||
if (!redirectUri) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.General, {
|
||||
message: 'Cannot find `redirectUri` from connector session.',
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const { access_token } = await getAccessToken(config, code, redirectUri);
|
||||
|
||||
const userInfo = await ky
|
||||
.get(userInfoEndpoint, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${access_token}`,
|
||||
},
|
||||
timeout: defaultTimeout,
|
||||
})
|
||||
.json();
|
||||
|
||||
const userInfoResult = userInfoResponseGuard.safeParse(userInfo);
|
||||
|
||||
if (!userInfoResult.success) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, userInfoResult.error);
|
||||
}
|
||||
|
||||
const { userId, displayName } = userInfoResult.data;
|
||||
|
||||
return {
|
||||
id: userId,
|
||||
name: conditional(displayName),
|
||||
rawData: jsonGuard.parse(userInfo),
|
||||
};
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof HTTPError) {
|
||||
const { status, body: rawBody } = error.response;
|
||||
|
||||
if (status === 401) {
|
||||
throw new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid);
|
||||
}
|
||||
|
||||
throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(rawBody));
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const createLineConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {
|
||||
return {
|
||||
metadata: defaultMetadata,
|
||||
type: ConnectorType.Social,
|
||||
configGuard: lineConfigGuard,
|
||||
getAuthorizationUri: getAuthorizationUri(getConfig),
|
||||
getUserInfo: getUserInfo(getConfig),
|
||||
};
|
||||
};
|
||||
|
||||
export default createLineConnector;
|
4
packages/connectors/connector-line/src/mock.ts
Normal file
4
packages/connectors/connector-line/src/mock.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export const mockedConfig = {
|
||||
clientId: '<client-id>',
|
||||
clientSecret: '<client-secret>',
|
||||
};
|
24
packages/connectors/connector-line/src/types.ts
Normal file
24
packages/connectors/connector-line/src/types.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
export const lineConfigGuard = z.object({
|
||||
clientId: z.string(),
|
||||
clientSecret: z.string(),
|
||||
scope: z.string().optional(),
|
||||
});
|
||||
|
||||
export type LineConfig = z.infer<typeof lineConfigGuard>;
|
||||
|
||||
export const userInfoResponseGuard = z.object({
|
||||
userId: z.string(),
|
||||
displayName: z.string().nullish(),
|
||||
});
|
||||
|
||||
export type UserInfoResponse = z.infer<typeof userInfoResponseGuard>;
|
||||
|
||||
export const authResponseGuard = z.object({
|
||||
code: z.string(),
|
||||
});
|
||||
|
||||
export const accessTokenResponseGuard = z.object({
|
||||
access_token: z.string(),
|
||||
});
|
12
packages/connectors/connector-line/src/utils.ts
Normal file
12
packages/connectors/connector-line/src/utils.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import crypto from 'node:crypto';
|
||||
|
||||
export const generateCodeVerifier = () => {
|
||||
const buffer = crypto.randomBytes(32);
|
||||
return buffer.toString('base64url');
|
||||
};
|
||||
|
||||
export const generateCodeChallenge = (verifier: string) => {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(verifier);
|
||||
return hash.digest('base64url');
|
||||
};
|
205
pnpm-lock.yaml
generated
205
pnpm-lock.yaml
generated
|
@ -1440,6 +1440,67 @@ importers:
|
|||
specifier: ^2.1.9
|
||||
version: 2.1.9(@types/node@20.12.7)(jsdom@20.0.2)(lightningcss@1.25.1)(sass@1.77.8)
|
||||
|
||||
packages/connectors/connector-line:
|
||||
dependencies:
|
||||
'@logto/connector-kit':
|
||||
specifier: workspace:^4.0.0
|
||||
version: link:../../toolkit/connector-kit
|
||||
'@silverhand/essentials':
|
||||
specifier: ^2.9.1
|
||||
version: 2.9.2
|
||||
ky:
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3
|
||||
query-string:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
snakecase-keys:
|
||||
specifier: ^8.0.1
|
||||
version: 8.0.1
|
||||
zod:
|
||||
specifier: ^3.23.8
|
||||
version: 3.23.8
|
||||
devDependencies:
|
||||
'@silverhand/eslint-config':
|
||||
specifier: 6.0.1
|
||||
version: 6.0.1(eslint@8.57.0)(prettier@3.0.0)(typescript@5.5.3)
|
||||
'@silverhand/ts-config':
|
||||
specifier: 6.0.0
|
||||
version: 6.0.0(typescript@5.5.3)
|
||||
'@types/node':
|
||||
specifier: ^20.11.20
|
||||
version: 20.12.7
|
||||
'@types/supertest':
|
||||
specifier: ^6.0.2
|
||||
version: 6.0.2
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^2.1.8
|
||||
version: 2.1.9(vitest@2.1.9(@types/node@20.12.7)(jsdom@20.0.2)(lightningcss@1.25.1)(sass@1.77.8))
|
||||
eslint:
|
||||
specifier: ^8.56.0
|
||||
version: 8.57.0
|
||||
lint-staged:
|
||||
specifier: ^15.0.2
|
||||
version: 15.0.2
|
||||
nock:
|
||||
specifier: 14.0.0-beta.15
|
||||
version: 14.0.0-beta.15
|
||||
prettier:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
supertest:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
tsup:
|
||||
specifier: ^8.3.0
|
||||
version: 8.3.0(@swc/core@1.3.52(@swc/helpers@0.5.1))(jiti@1.21.0)(postcss@8.5.1)(typescript@5.5.3)(yaml@2.4.5)
|
||||
typescript:
|
||||
specifier: ^5.5.3
|
||||
version: 5.5.3
|
||||
vitest:
|
||||
specifier: ^2.1.8
|
||||
version: 2.1.9(@types/node@20.12.7)(jsdom@20.0.2)(lightningcss@1.25.1)(sass@1.77.8)
|
||||
|
||||
packages/connectors/connector-linkedin:
|
||||
dependencies:
|
||||
'@logto/connector-kit':
|
||||
|
@ -9600,10 +9661,6 @@ packages:
|
|||
for-each@0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
|
||||
foreground-child@3.1.1:
|
||||
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
foreground-child@3.3.0:
|
||||
resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
|
||||
engines: {node: '>=14'}
|
||||
|
@ -9777,11 +9834,6 @@ packages:
|
|||
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
glob@10.4.2:
|
||||
resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
hasBin: true
|
||||
|
||||
glob@10.4.5:
|
||||
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
|
||||
hasBin: true
|
||||
|
@ -10508,10 +10560,6 @@ packages:
|
|||
iterator.prototype@1.1.2:
|
||||
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
|
||||
|
||||
jackspeak@3.4.0:
|
||||
resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
jackspeak@3.4.3:
|
||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||
|
||||
|
@ -11585,10 +11633,6 @@ packages:
|
|||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
minimatch@9.0.4:
|
||||
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
@ -11994,9 +12038,6 @@ packages:
|
|||
resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
package-json-from-dist@1.0.0:
|
||||
resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==}
|
||||
|
||||
package-json-from-dist@1.0.1:
|
||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||
|
||||
|
@ -15044,12 +15085,12 @@ snapshots:
|
|||
'@babel/helper-compilation-targets': 7.23.6
|
||||
'@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4)
|
||||
'@babel/helpers': 7.24.4
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/template': 7.24.0
|
||||
'@babel/traverse': 7.24.1
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 6.3.1
|
||||
|
@ -15078,20 +15119,20 @@ snapshots:
|
|||
|
||||
'@babel/generator@7.20.4':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
jsesc: 2.5.2
|
||||
|
||||
'@babel/generator@7.24.10':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 2.5.2
|
||||
|
||||
'@babel/generator@7.24.4':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
'@jridgewell/gen-mapping': 0.3.5
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
jsesc: 2.5.2
|
||||
|
@ -15116,34 +15157,34 @@ snapshots:
|
|||
|
||||
'@babel/helper-environment-visitor@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-function-name@7.23.0':
|
||||
dependencies:
|
||||
'@babel/template': 7.24.0
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-function-name@7.24.7':
|
||||
dependencies:
|
||||
'@babel/template': 7.24.7
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-hoist-variables@7.22.5':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-hoist-variables@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-module-imports@7.24.3':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-module-imports@7.24.7':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -15173,22 +15214,22 @@ snapshots:
|
|||
|
||||
'@babel/helper-simple-access@7.22.5':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-simple-access@7.24.7':
|
||||
dependencies:
|
||||
'@babel/traverse': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helper-split-export-declaration@7.22.6':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-split-export-declaration@7.24.7':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/helper-string-parser@7.23.4': {}
|
||||
|
||||
|
@ -15212,14 +15253,14 @@ snapshots:
|
|||
dependencies:
|
||||
'@babel/template': 7.24.0
|
||||
'@babel/traverse': 7.24.1
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/helpers@7.24.8':
|
||||
dependencies:
|
||||
'@babel/template': 7.24.7
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/highlight@7.22.5':
|
||||
dependencies:
|
||||
|
@ -15250,11 +15291,11 @@ snapshots:
|
|||
|
||||
'@babel/parser@7.24.4':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.0
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/parser@7.24.8':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/parser@7.26.3':
|
||||
dependencies:
|
||||
|
@ -15359,20 +15400,20 @@ snapshots:
|
|||
'@babel/template@7.18.10':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.22.5
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/template@7.24.0':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.24.2
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/template@7.24.7':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.24.7
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@babel/traverse@7.24.1':
|
||||
dependencies:
|
||||
|
@ -15382,9 +15423,9 @@ snapshots:
|
|||
'@babel/helper-function-name': 7.23.0
|
||||
'@babel/helper-hoist-variables': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
debug: 4.3.4
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
debug: 4.4.0
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -15397,9 +15438,9 @@ snapshots:
|
|||
'@babel/helper-function-name': 7.24.7
|
||||
'@babel/helper-hoist-variables': 7.24.7
|
||||
'@babel/helper-split-export-declaration': 7.24.7
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
debug: 4.3.4
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
debug: 4.4.0
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -15616,7 +15657,7 @@ snapshots:
|
|||
'@commitlint/is-ignored@19.0.3':
|
||||
dependencies:
|
||||
'@commitlint/types': 19.0.3
|
||||
semver: 7.6.0
|
||||
semver: 7.6.3
|
||||
|
||||
'@commitlint/lint@19.0.3':
|
||||
dependencies:
|
||||
|
@ -16411,7 +16452,7 @@ snapshots:
|
|||
'@types/shimmer': 1.0.2
|
||||
import-in-the-middle: 1.4.2
|
||||
require-in-the-middle: 7.2.0
|
||||
semver: 7.6.0
|
||||
semver: 7.6.3
|
||||
shimmer: 1.2.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -17427,8 +17468,8 @@ snapshots:
|
|||
|
||||
'@types/babel__core@7.1.19':
|
||||
dependencies:
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
'@types/babel__generator': 7.6.4
|
||||
'@types/babel__template': 7.4.1
|
||||
'@types/babel__traverse': 7.18.2
|
||||
|
@ -17443,16 +17484,16 @@ snapshots:
|
|||
|
||||
'@types/babel__generator@7.6.4':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.0
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@types/babel__template@7.4.1':
|
||||
dependencies:
|
||||
'@babel/parser': 7.24.4
|
||||
'@babel/types': 7.24.0
|
||||
'@babel/parser': 7.26.3
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@types/babel__traverse@7.18.2':
|
||||
dependencies:
|
||||
'@babel/types': 7.24.0
|
||||
'@babel/types': 7.26.3
|
||||
|
||||
'@types/body-parser@1.19.2':
|
||||
dependencies:
|
||||
|
@ -18844,7 +18885,7 @@ snapshots:
|
|||
babel-plugin-jest-hoist@29.6.3:
|
||||
dependencies:
|
||||
'@babel/template': 7.18.10
|
||||
'@babel/types': 7.24.9
|
||||
'@babel/types': 7.26.3
|
||||
'@types/babel__core': 7.1.19
|
||||
'@types/babel__traverse': 7.18.2
|
||||
|
||||
|
@ -20728,11 +20769,6 @@ snapshots:
|
|||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
|
||||
foreground-child@3.1.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
signal-exit: 4.1.0
|
||||
|
||||
foreground-child@3.3.0:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
|
@ -20934,15 +20970,6 @@ snapshots:
|
|||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
|
||||
glob@10.4.2:
|
||||
dependencies:
|
||||
foreground-child: 3.1.1
|
||||
jackspeak: 3.4.0
|
||||
minimatch: 9.0.4
|
||||
minipass: 7.1.2
|
||||
package-json-from-dist: 1.0.0
|
||||
path-scurry: 1.11.1
|
||||
|
||||
glob@10.4.5:
|
||||
dependencies:
|
||||
foreground-child: 3.3.0
|
||||
|
@ -21694,7 +21721,7 @@ snapshots:
|
|||
istanbul-lib-instrument@5.2.1:
|
||||
dependencies:
|
||||
'@babel/core': 7.24.9
|
||||
'@babel/parser': 7.24.8
|
||||
'@babel/parser': 7.26.3
|
||||
'@istanbuljs/schema': 0.1.3
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
semver: 6.3.1
|
||||
|
@ -21746,12 +21773,6 @@ snapshots:
|
|||
reflect.getprototypeof: 1.0.6
|
||||
set-function-name: 2.0.2
|
||||
|
||||
jackspeak@3.4.0:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
jackspeak@3.4.3:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
|
@ -22151,7 +22172,7 @@ snapshots:
|
|||
'@babel/generator': 7.20.4
|
||||
'@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.24.4)
|
||||
'@babel/plugin-syntax-typescript': 7.18.6(@babel/core@7.24.4)
|
||||
'@babel/types': 7.24.0
|
||||
'@babel/types': 7.26.3
|
||||
'@jest/expect-utils': 29.7.0
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
|
@ -22166,7 +22187,7 @@ snapshots:
|
|||
jest-util: 29.7.0
|
||||
natural-compare: 1.4.0
|
||||
pretty-format: 29.7.0
|
||||
semver: 7.6.0
|
||||
semver: 7.6.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -23488,7 +23509,7 @@ snapshots:
|
|||
micromark@3.2.0:
|
||||
dependencies:
|
||||
'@types/debug': 4.1.7
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
decode-named-character-reference: 1.0.2
|
||||
micromark-core-commonmark: 1.1.0
|
||||
micromark-factory-space: 1.1.0
|
||||
|
@ -23510,7 +23531,7 @@ snapshots:
|
|||
micromark@4.0.0:
|
||||
dependencies:
|
||||
'@types/debug': 4.1.7
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0
|
||||
decode-named-character-reference: 1.0.1
|
||||
devlop: 1.1.0
|
||||
micromark-core-commonmark: 2.0.0
|
||||
|
@ -23562,10 +23583,6 @@ snapshots:
|
|||
dependencies:
|
||||
brace-expansion: 1.1.11
|
||||
|
||||
minimatch@9.0.4:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
@ -23729,7 +23746,7 @@ snapshots:
|
|||
dependencies:
|
||||
hosted-git-info: 4.1.0
|
||||
is-core-module: 2.13.1
|
||||
semver: 7.6.0
|
||||
semver: 7.6.3
|
||||
validate-npm-package-license: 3.0.4
|
||||
|
||||
normalize-path@3.0.0: {}
|
||||
|
@ -23994,8 +24011,6 @@ snapshots:
|
|||
degenerator: 5.0.1
|
||||
netmask: 2.0.2
|
||||
|
||||
package-json-from-dist@1.0.0: {}
|
||||
|
||||
package-json-from-dist@1.0.1: {}
|
||||
|
||||
packet-reader@1.0.0: {}
|
||||
|
@ -25029,7 +25044,7 @@ snapshots:
|
|||
|
||||
rimraf@5.0.5:
|
||||
dependencies:
|
||||
glob: 10.4.2
|
||||
glob: 10.4.5
|
||||
|
||||
roarr@7.11.0:
|
||||
dependencies:
|
||||
|
|
Loading…
Add table
Reference in a new issue