From 2f500fd84622f20325b76fc66d7dd73e60e00b71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 11:56:36 +0000 Subject: [PATCH 01/43] build(deps): bump word-wrap from 1.2.3 to 1.2.4 in /client Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] --- client/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/yarn.lock b/client/yarn.lock index fe4c4e94c..75b684641 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -18235,9 +18235,9 @@ __metadata: linkType: hard "word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f + version: 1.2.4 + resolution: "word-wrap@npm:1.2.4" + checksum: 8f1f2e0a397c0e074ca225ba9f67baa23f99293bc064e31355d426ae91b8b3f6b5f6c1fc9ae5e9141178bb362d563f55e62fd8d5c31f2a77e3ade56cb3e35bd1 languageName: node linkType: hard From 726b77fffd021dfa1c881102f89a5f9622fe30a4 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Thu, 21 Sep 2023 22:40:42 +0500 Subject: [PATCH 02/43] login/register through third party oauth --- client/packages/lowcoder/src/api/configApi.ts | 10 ++++-- client/packages/lowcoder/src/api/inviteApi.ts | 3 +- client/packages/lowcoder/src/api/userApi.ts | 5 +-- client/packages/lowcoder/src/app.tsx | 4 ++- .../lowcoder/src/constants/authConstants.ts | 3 +- .../src/pages/common/inviteLanding.tsx | 17 +++++++-- .../src/pages/userAuth/authComponents.tsx | 17 +++++++-- .../lowcoder/src/pages/userAuth/authUtils.ts | 4 ++- .../lowcoder/src/pages/userAuth/formLogin.tsx | 13 ++++++- .../lowcoder/src/pages/userAuth/register.tsx | 36 +++++++++++-------- .../userAuth/thirdParty/authRedirect.tsx | 10 ++++-- .../authenticator/abstractAuthenticator.ts | 4 ++- .../authenticator/oAuthAuthenticator.ts | 11 +++--- .../userAuth/thirdParty/thirdPartyAuth.tsx | 19 +++++++--- .../src/redux/reduxActions/configActions.ts | 9 ++++- .../lowcoder/src/redux/sagas/configSagas.ts | 14 ++++++-- 16 files changed, 134 insertions(+), 45 deletions(-) diff --git a/client/packages/lowcoder/src/api/configApi.ts b/client/packages/lowcoder/src/api/configApi.ts index 8c4e31e95..42d315279 100644 --- a/client/packages/lowcoder/src/api/configApi.ts +++ b/client/packages/lowcoder/src/api/configApi.ts @@ -8,10 +8,14 @@ export interface ConfigResponse extends ApiResponse { } class ConfigApi extends Api { - static configURL = "/v1/configs"; + static configURL = "/configs"; - static fetchConfig(): AxiosPromise { - return Api.get(ConfigApi.configURL); + static fetchConfig(orgId?: string): AxiosPromise { + let authConfigURL = ConfigApi.configURL; + if(orgId?.length) { + authConfigURL += `?orgId?=${orgId}`; + } + return Api.get(authConfigURL); } } diff --git a/client/packages/lowcoder/src/api/inviteApi.ts b/client/packages/lowcoder/src/api/inviteApi.ts index 27b9944c1..f2a85caa1 100644 --- a/client/packages/lowcoder/src/api/inviteApi.ts +++ b/client/packages/lowcoder/src/api/inviteApi.ts @@ -14,10 +14,11 @@ export type InviteInfo = { inviteCode: string; createUserName: string; invitedOrganizationName: string; + invitedOrganizationId: string; }; class InviteApi extends Api { - static getInviteURL = "/v1/invitation"; + static getInviteURL = "/invitation"; static acceptInviteURL = (invitationId: string) => `/v1/invitation/${invitationId}/invite`; // generate invitation diff --git a/client/packages/lowcoder/src/api/userApi.ts b/client/packages/lowcoder/src/api/userApi.ts index 8cd666444..36df3685b 100644 --- a/client/packages/lowcoder/src/api/userApi.ts +++ b/client/packages/lowcoder/src/api/userApi.ts @@ -9,6 +9,7 @@ export interface CommonLoginParam { invitationId?: string; authId?: string; source?: string; + orgId?: string; } export interface CommonBindParam { @@ -17,8 +18,8 @@ export interface CommonBindParam { source?: string; } -interface ThirdPartyAuthRequest { - state: string; +export interface ThirdPartyAuthRequest { + state?: string; code: string; redirectUrl: string; } diff --git a/client/packages/lowcoder/src/app.tsx b/client/packages/lowcoder/src/app.tsx index 04c6c1bf8..68742a6fc 100644 --- a/client/packages/lowcoder/src/app.tsx +++ b/client/packages/lowcoder/src/app.tsx @@ -83,7 +83,9 @@ type AppIndexProps = { class AppIndex extends React.Component { componentDidMount() { this.props.getCurrentUser(); - this.props.fetchConfig(); + if (!history.location.pathname.startsWith("/invite/")) { + this.props.fetchConfig(); + } if (history.location.pathname === BASE_URL) { this.props.fetchHome(); } diff --git a/client/packages/lowcoder/src/constants/authConstants.ts b/client/packages/lowcoder/src/constants/authConstants.ts index d7b35abe4..7e0e074d9 100644 --- a/client/packages/lowcoder/src/constants/authConstants.ts +++ b/client/packages/lowcoder/src/constants/authConstants.ts @@ -56,6 +56,7 @@ export type AuthSessionStoreParams = { afterLoginRedirect: string | null; sourceType: string; invitationId?: string; + invitedOrganizationId?: string; routeLink?: boolean; name: string; authId?: string; @@ -65,7 +66,7 @@ export type AuthSessionStoreParams = { * action after third party auth * bind & innerBind has different redirect action */ -export type ThirdPartyAuthGoal = "login" | "bind" | "innerBind"; +export type ThirdPartyAuthGoal = "register" | "login" | "bind" | "innerBind"; export const AuthRoutes: Array<{ path: string; component: React.ComponentType }> = [ { path: AUTH_LOGIN_URL, component: Login }, diff --git a/client/packages/lowcoder/src/pages/common/inviteLanding.tsx b/client/packages/lowcoder/src/pages/common/inviteLanding.tsx index abd84231b..0d0d09d32 100644 --- a/client/packages/lowcoder/src/pages/common/inviteLanding.tsx +++ b/client/packages/lowcoder/src/pages/common/inviteLanding.tsx @@ -8,15 +8,17 @@ import { RouteComponentProps } from "react-router-dom"; import { AppState } from "redux/reducers"; import history from "util/history"; import { isFetchUserFinished } from "redux/selectors/usersSelectors"; +import { fetchConfigAction } from "redux/reduxActions/configActions"; import { trans } from "i18n"; import { messageInstance } from "lowcoder-design"; type InviteLandingProp = RouteComponentProps<{ invitationId: string }, StaticContext, any> & { invitationId: string; + fetchConfig: (orgId?: string) => void; }; function InviteLanding(props: InviteLandingProp) { - const { invitationId } = props; + const { invitationId, fetchConfig } = props; const fetchUserFinished = useSelector(isFetchUserFinished); useEffect(() => { if (!fetchUserFinished) { @@ -27,6 +29,7 @@ function InviteLanding(props: InviteLandingProp) { history.push(BASE_URL); return; } + let orgId:string | undefined = undefined; // accept the invitation InviteApi.acceptInvite({ invitationId }) .then((resp) => { @@ -39,6 +42,7 @@ function InviteLanding(props: InviteLandingProp) { resp?.status === API_STATUS_CODES.REQUEST_NOT_AUTHORISED ) { const inviteInfo = resp.data.data; + orgId = inviteInfo.invitedOrganizationId; const inviteState = inviteInfo ? { ...inviteInfo, invitationId } : { invitationId }; history.push({ pathname: AUTH_LOGIN_URL, @@ -53,8 +57,10 @@ function InviteLanding(props: InviteLandingProp) { .catch((errorResp) => { messageInstance.error(errorResp.message); history.push(BASE_URL); + }).finally(() => { + fetchConfig(orgId); }); - }, [fetchUserFinished, invitationId]); + }, [fetchUserFinished, invitationId, fetchConfig]); return null; } @@ -64,4 +70,9 @@ const mapStateToProps = (state: AppState, props: InviteLandingProp) => { }; }; -export default connect(mapStateToProps)(InviteLanding); +const mapDispatchToProps = (dispatch: any) => ({ + fetchConfig: (orgId?: string) => dispatch(fetchConfigAction(orgId)), +}); + + +export default connect(mapStateToProps, mapDispatchToProps)(InviteLanding); diff --git a/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx b/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx index 5dc599391..5625708ae 100644 --- a/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx @@ -199,10 +199,23 @@ export const LoginLogoStyle = styled.img` margin-right: 8px; width: 32px; height: 32px; + position: absolute; + left: 6px; `; -export const StyledLoginButton = styled.button` - padding: 0; +export const LoginLabelStyle = styled.p` + font-size: 16px; + color: #333333; + line-height: 16px; + margin: 0px; +`; + +export const StyledLoginButton = styled(TacoButton)` + position: relative; + height: 48px; + border: 1px solid lightgray !important; + border-radius: 8px; + padding: 8px; white-space: nowrap; word-break: keep-all; outline: 0; diff --git a/client/packages/lowcoder/src/pages/userAuth/authUtils.ts b/client/packages/lowcoder/src/pages/userAuth/authUtils.ts index 6cec13bd2..497528022 100644 --- a/client/packages/lowcoder/src/pages/userAuth/authUtils.ts +++ b/client/packages/lowcoder/src/pages/userAuth/authUtils.ts @@ -125,7 +125,8 @@ export const geneAuthStateAndSaveParam = ( authGoal: ThirdPartyAuthGoal, config: ThirdPartyConfigType, afterLoginRedirect: string | null, - invitationId?: string + invitationId?: string, + invitedOrganizationId?: string, ) => { const state = Math.floor(Math.random() * 0xffffffff).toString(16); const params: AuthSessionStoreParams = { @@ -135,6 +136,7 @@ export const geneAuthStateAndSaveParam = ( afterLoginRedirect: afterLoginRedirect || null, sourceType: config.sourceType, invitationId: invitationId, + invitedOrganizationId: invitedOrganizationId, routeLink: config.routeLink, name: config.name, authId: config.id, diff --git a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx index ffd9dd1b9..55cdb95ee 100644 --- a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx @@ -17,6 +17,7 @@ import { AuthContext, useAuthSubmit } from "pages/userAuth/authUtils"; import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; import { AUTH_REGISTER_URL } from "constants/routesURL"; import { useLocation } from "react-router-dom"; +import { Divider } from "antd"; const AccountLoginWrapper = styled(FormWrapperMobile)` display: flex; @@ -30,6 +31,7 @@ export default function FormLogin() { const redirectUrl = useRedirectUrl(); const { systemConfig, inviteInfo } = useContext(AuthContext); const invitationId = inviteInfo?.invitationId; + const invitedOrganizationId = inviteInfo?.invitedOrganizationId; const authId = systemConfig?.form.id; const location = useLocation(); @@ -69,9 +71,18 @@ export default function FormLogin() { {trans("userAuth.login")} + {Boolean(invitationId) && ( + <> + + + + )} - {systemConfig.form.enableRegister && ( {trans("userAuth.register")} diff --git a/client/packages/lowcoder/src/pages/userAuth/register.tsx b/client/packages/lowcoder/src/pages/userAuth/register.tsx index b1b82d0f9..2f33f693e 100644 --- a/client/packages/lowcoder/src/pages/userAuth/register.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/register.tsx @@ -18,6 +18,8 @@ import { useLocation } from "react-router-dom"; import { UserConnectionSource } from "@lowcoder-ee/constants/userConstants"; import { trans } from "i18n"; import { AuthContext, checkPassWithMsg, useAuthSubmit } from "pages/userAuth/authUtils"; +import { Divider } from "antd"; +import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; const StyledFormInput = styled(FormInput)` margin-bottom: 16px; @@ -30,16 +32,10 @@ const StyledPasswordInput = styled(PasswordInput)` const RegisterContent = styled(FormWrapperMobile)` display: flex; flex-direction: column; + margin-bottom: 106px; button { - margin: 20px 0 16px 0; - } -`; - -const TermsAndPrivacyInfoWrapper = styled.div` - margin-bottom: 80px; - @media screen and (max-width: 640px) { - margin: 10px 0 64px 0; + margin-bottom: 16px; } `; @@ -50,6 +46,8 @@ function UserRegister() { const redirectUrl = useRedirectUrl(); const location = useLocation(); const { systemConfig, inviteInfo } = useContext(AuthContext); + const invitationId = inviteInfo?.invitationId; + const invitedOrganizationId = inviteInfo?.invitedOrganizationId; const authId = systemConfig.form.id; const { loading, onSubmit } = useAuthSubmit( () => @@ -57,7 +55,7 @@ function UserRegister() { register: true, loginId: account, password: password, - invitationId: inviteInfo?.invitationId, + invitationId, source: UserConnectionSource.email, authId, }), @@ -95,13 +93,21 @@ function UserRegister() { > {trans("userAuth.register")} - - setSubmitBtnDisable(!e.target.checked)} /> - - - {trans("userAuth.userLogin")} - + setSubmitBtnDisable(!e.target.checked)} /> + {Boolean(invitationId) && ( + <> + + + + )} + + {trans("userAuth.userLogin")} + ); } diff --git a/client/packages/lowcoder/src/pages/userAuth/thirdParty/authRedirect.tsx b/client/packages/lowcoder/src/pages/userAuth/thirdParty/authRedirect.tsx index 87d1a8fbd..686532fe2 100644 --- a/client/packages/lowcoder/src/pages/userAuth/thirdParty/authRedirect.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/thirdParty/authRedirect.tsx @@ -2,7 +2,7 @@ import { useLocation } from "react-router-dom"; import { AuthSessionStoreParams } from "constants/authConstants"; import { messageInstance } from "lowcoder-design"; -import { AUTH_LOGIN_URL, BASE_URL } from "constants/routesURL"; +import { AUTH_LOGIN_URL, AUTH_REGISTER_URL, BASE_URL } from "constants/routesURL"; import history from "util/history"; import PageSkeleton from "components/PageSkeleton"; import { trans } from "i18n"; @@ -35,7 +35,13 @@ function validateParam(authParams: AuthSessionStoreParams, urlParam: AuthRedirec return true; } else { messageInstance.error(trans("userAuth.invalidThirdPartyParam")); - history.push(authParams.authGoal === "login" ? AUTH_LOGIN_URL : BASE_URL, { + let redirectUrl = BASE_URL; + if(authParams.authGoal === "login") { + redirectUrl = AUTH_LOGIN_URL; + } else if(authParams.authGoal === "register") { + redirectUrl = AUTH_REGISTER_URL; + } + history.push(redirectUrl, { thirdPartyAuthError: true, }); return false; diff --git a/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/abstractAuthenticator.ts b/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/abstractAuthenticator.ts index 784bbee0b..6d1ecea9c 100644 --- a/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/abstractAuthenticator.ts +++ b/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/abstractAuthenticator.ts @@ -28,7 +28,9 @@ export abstract class AbstractAuthenticator { doAuth() { const { authParams } = this; - authParams.authGoal === "login" ? this.doLogin() : this.doBind(); + (authParams.authGoal === "login" || authParams.authGoal === "register") + ? this.doLogin() + : this.doBind(); } protected doLogin() { diff --git a/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/oAuthAuthenticator.ts b/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/oAuthAuthenticator.ts index 7f0246299..9557a27c6 100644 --- a/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/oAuthAuthenticator.ts +++ b/client/packages/lowcoder/src/pages/userAuth/thirdParty/authenticator/oAuthAuthenticator.ts @@ -1,6 +1,6 @@ import { AbstractAuthenticator } from "./abstractAuthenticator"; import { AxiosPromise } from "axios"; -import UserApi from "api/userApi"; +import UserApi, { CommonLoginParam, ThirdPartyAuthRequest } from "api/userApi"; import { ApiResponse } from "api/apiResponses"; export class OAuthAuthenticator extends AbstractAuthenticator { @@ -19,13 +19,16 @@ export class OAuthAuthenticator extends AbstractAuthenticator { login(): AxiosPromise { const { urlParam, authParams, redirectUrl } = this; - return UserApi.thirdPartyLogin({ + const params: ThirdPartyAuthRequest & CommonLoginParam = { state: urlParam.state!, code: urlParam.code!, source: authParams.sourceType, authId: authParams.authId, redirectUrl: redirectUrl, - ...(authParams.invitationId && { invitationId: authParams.invitationId }), - }); + } + if(authParams.invitedOrganizationId) { + params.orgId = authParams.invitedOrganizationId; + } + return UserApi.thirdPartyLogin(params); } } diff --git a/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx b/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx index 6a3eedb75..5409f3fcc 100644 --- a/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx @@ -7,7 +7,7 @@ import { import { CommonGrayLabel, WhiteLoading } from "lowcoder-design"; import { useLocation } from "react-router-dom"; import history from "util/history"; -import { LoginLogoStyle, StyledLoginButton } from "pages/userAuth/authComponents"; +import { LoginLogoStyle, LoginLabelStyle, StyledLoginButton } from "pages/userAuth/authComponents"; import { useSelector } from "react-redux"; import { selectSystemConfig } from "redux/selectors/configSelectors"; import React from "react"; @@ -19,6 +19,7 @@ import { geneAuthStateAndSaveParam, getAuthUrl, getRedirectUrl } from "pages/use function ThirdPartyLoginButton(props: { config: ThirdPartyConfigType; invitationId?: string; + invitedOrganizationId?: string; autoJump?: boolean; authGoal: ThirdPartyAuthGoal; label: string; @@ -33,7 +34,8 @@ function ThirdPartyLoginButton(props: { props.authGoal, config, loginRedirectUrl, - props.invitationId + props.invitationId, + props.invitedOrganizationId, ); if (config.authType === "LDAP") { history.push({ @@ -70,16 +72,24 @@ function ThirdPartyLoginButton(props: { onLoginClick(); return ; } + + const buttonLabel = props.authGoal === 'register' + ? `Sign up with ${label}` + : `Sign in with ${label}`; + return ( - + - {label} + + { buttonLabel } + ); } export function ThirdPartyAuth(props: { invitationId?: string; + invitedOrganizationId?: string; autoJumpSource?: string; authGoal: ThirdPartyAuthGoal; labelFormatter?: (name: string) => string; @@ -101,6 +111,7 @@ export function ThirdPartyAuth(props: { key={config.name} config={config} invitationId={props.invitationId} + invitedOrganizationId={props.invitedOrganizationId} label={props.labelFormatter ? props.labelFormatter(config.name) : config.name} /> ); diff --git a/client/packages/lowcoder/src/redux/reduxActions/configActions.ts b/client/packages/lowcoder/src/redux/reduxActions/configActions.ts index 2b8e7f3cc..78ae83fbf 100644 --- a/client/packages/lowcoder/src/redux/reduxActions/configActions.ts +++ b/client/packages/lowcoder/src/redux/reduxActions/configActions.ts @@ -1,9 +1,16 @@ import { ReduxActionTypes } from "constants/reduxActionConstants"; import { ExternalEditorContextState } from "util/context/ExternalEditorContext"; -export const fetchConfigAction = () => { +export type FetchConfigActionPayload = { + orgId?: string; +}; + +export const fetchConfigAction = (orgId?: string) => { return { type: ReduxActionTypes.FETCH_SYS_CONFIG_INIT, + payload: { + orgId, + } }; }; diff --git a/client/packages/lowcoder/src/redux/sagas/configSagas.ts b/client/packages/lowcoder/src/redux/sagas/configSagas.ts index 8faf9c9e6..8570c04fb 100644 --- a/client/packages/lowcoder/src/redux/sagas/configSagas.ts +++ b/client/packages/lowcoder/src/redux/sagas/configSagas.ts @@ -1,14 +1,22 @@ import { all, call, put, takeLatest } from "redux-saga/effects"; -import { ReduxActionErrorTypes, ReduxActionTypes } from "constants/reduxActionConstants"; +import { + ReduxActionErrorTypes, + ReduxActionTypes, + ReduxAction, +} from "constants/reduxActionConstants"; import { AxiosResponse } from "axios"; import { validateResponse } from "api/apiUtils"; import log from "loglevel"; import ConfigApi, { ConfigResponse } from "api/configApi"; import { transToSystemConfig } from "@lowcoder-ee/constants/configConstants"; +import { FetchConfigActionPayload } from "redux/reduxActions/configActions"; -export function* fetchConfigSaga() { +export function* fetchConfigSaga(action: ReduxAction) { try { - const response: AxiosResponse = yield call(ConfigApi.fetchConfig); + const response: AxiosResponse = yield call( + ConfigApi.fetchConfig, + action.payload.orgId, + ); const isValidResponse: boolean = validateResponse(response); if (isValidResponse) { yield put({ From e8ca478d3beb396c0ad9278ad421347e560bd01c Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Thu, 21 Sep 2023 23:05:08 +0500 Subject: [PATCH 03/43] feat: fix multiple oauth buttons spacing --- .../src/pages/userAuth/authComponents.tsx | 1 + .../lowcoder/src/pages/userAuth/register.tsx | 4 ---- .../userAuth/thirdParty/thirdPartyAuth.tsx | 18 ++++++++++++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx b/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx index 5625708ae..b56804b03 100644 --- a/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx @@ -158,6 +158,7 @@ export const ConfirmButton = (props: { const TermsAndPrivacyContent = styled.div` display: flex; align-items: center; + margin-top: 16px; font-size: 13px; color: #333333; diff --git a/client/packages/lowcoder/src/pages/userAuth/register.tsx b/client/packages/lowcoder/src/pages/userAuth/register.tsx index 2f33f693e..d93f386f4 100644 --- a/client/packages/lowcoder/src/pages/userAuth/register.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/register.tsx @@ -33,10 +33,6 @@ const RegisterContent = styled(FormWrapperMobile)` display: flex; flex-direction: column; margin-bottom: 106px; - - button { - margin-bottom: 16px; - } `; function UserRegister() { diff --git a/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx b/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx index 5409f3fcc..2e647dca0 100644 --- a/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/thirdParty/thirdPartyAuth.tsx @@ -12,10 +12,20 @@ import { useSelector } from "react-redux"; import { selectSystemConfig } from "redux/selectors/configSelectors"; import React from "react"; import { messageInstance } from "lowcoder-design"; - +import styled from "styled-components"; import { trans } from "i18n"; import { geneAuthStateAndSaveParam, getAuthUrl, getRedirectUrl } from "pages/userAuth/authUtils"; +const ThirdPartyLoginButtonWrapper = styled.div` + button{ + width: 100%; + + &:not(:last-child) { + margin-bottom: 16px; + } + } +`; + function ThirdPartyLoginButton(props: { config: ThirdPartyConfigType; invitationId?: string; @@ -116,5 +126,9 @@ export function ThirdPartyAuth(props: { /> ); }); - return <>{socialLoginButtons}; + return ( + + {socialLoginButtons} + + ); } From 7a69d659b39ab72c751789e150a62479c1d17915 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Fri, 22 Sep 2023 11:55:28 +0500 Subject: [PATCH 04/43] fix: fixed profile dropdown warnning --- .../src/pages/common/profileDropdown.tsx | 97 ++++++++++++------- .../lowcoder/src/pages/userAuth/formLogin.tsx | 17 ++-- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/client/packages/lowcoder/src/pages/common/profileDropdown.tsx b/client/packages/lowcoder/src/pages/common/profileDropdown.tsx index ab9711a5b..adc001b76 100644 --- a/client/packages/lowcoder/src/pages/common/profileDropdown.tsx +++ b/client/packages/lowcoder/src/pages/common/profileDropdown.tsx @@ -26,6 +26,7 @@ import { trans } from "i18n"; import { showSwitchOrg } from "@lowcoder-ee/pages/common/customerService"; import { checkIsMobile } from "util/commonUtils"; import { selectSystemConfig } from "redux/selectors/configSelectors"; +import { ItemType } from "antd/es/menu/hooks/useItems"; const ProfileWrapper = styled.div` display: flex; @@ -159,13 +160,10 @@ export default function ProfileDropdown(props: DropDownProps) { } }; - const menu = ( - } - > - + let profileDropdownMenuItems:ItemType[] = [ + { + key: 'profile', + label: ( @@ -187,36 +185,61 @@ export default function ProfileDropdown(props: DropDownProps) { {OrgRoleInfo[currentOrgRoleId].name} )} - - {orgs && orgs.length > 0 && showSwitchOrg(props.user, sysConfig) && ( - - - {trans("profile.joinedOrg")} - - {orgs.map((org: Org) => { - const MenuItem = (currentOrgId === org.id ? SelectDropMenuItem : Menu.Item) as React.ElementType; - return ( - }> - {org.name} - - ); - })} - {!checkIsMobile(window.innerWidth) && ( - <> - - }> - {trans("profile.createOrg")} - - - )} - - )} - {trans("profile.logout")} - + ), + }, + { + key: 'logout', + label: trans("profile.logout"), + } + ] + + if(orgs && orgs.length > 0 && showSwitchOrg(props.user, sysConfig)) { + const switchOrgSubMenu = orgs.map((org: Org) => ({ + key: org.id, + icon: currentOrgId === org.id && , + label: org.name + })) + + let addWorkSpace:ItemType[] = []; + if(!checkIsMobile(window.innerWidth)) { + addWorkSpace = [ + { type: 'divider'}, + { + key: 'newOrganization', + icon: , + label: trans("profile.createOrg") + } + ] + } + + const switchOrgMenu = { + key: 'switchOrg', + label: trans("profile.switchOrg"), + popupOffset: [4, -12], + children: [ + { + key: 'joinedOrg', + label: ( + + {trans("profile.joinedOrg")} + + ), + disabled: true, + }, + ...switchOrgSubMenu, + ...addWorkSpace, + ] + } + profileDropdownMenuItems.splice(1, 0, switchOrgMenu); + } + + const menu = ( + } + items={profileDropdownMenuItems} + /> ); return ( <> diff --git a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx index 55cdb95ee..cf18146b9 100644 --- a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx @@ -71,16 +71,13 @@ export default function FormLogin() { {trans("userAuth.login")} - {Boolean(invitationId) && ( - <> - - - - )} + + + {systemConfig.form.enableRegister && ( From 4de487c0646c96e075265397034cfd6845296de9 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Fri, 22 Sep 2023 23:18:33 +0500 Subject: [PATCH 05/43] feat: added env variable for custom welcome message on org auth page --- client/packages/lowcoder-cli/client.d.ts | 1 + client/packages/lowcoder-dev-utils/buildVars.js | 4 ++++ client/packages/lowcoder/src/app-env.d.ts | 1 + 3 files changed, 6 insertions(+) diff --git a/client/packages/lowcoder-cli/client.d.ts b/client/packages/lowcoder-cli/client.d.ts index 2621660f5..1a94b5149 100644 --- a/client/packages/lowcoder-cli/client.d.ts +++ b/client/packages/lowcoder-cli/client.d.ts @@ -34,6 +34,7 @@ declare var LOWCODER_NODE_SERVICE_URL: string; declare var LOWCODER_SHOW_BRAND: string; declare var LOWCODER_CUSTOM_LOGO: string; declare var LOWCODER_CUSTOM_LOGO_SQUARE: string; +declare var LOWCODER_SHOW_CUSTOM_AUTH_WELCOME_TEXT: string; declare var REACT_APP_ENV: string; declare var REACT_APP_BUILD_ID: string; declare var REACT_APP_LOG_LEVEL: string; diff --git a/client/packages/lowcoder-dev-utils/buildVars.js b/client/packages/lowcoder-dev-utils/buildVars.js index 0ad460323..fa4d6f4c3 100644 --- a/client/packages/lowcoder-dev-utils/buildVars.js +++ b/client/packages/lowcoder-dev-utils/buildVars.js @@ -35,6 +35,10 @@ export const buildVars = [ name: "LOWCODER_NODE_SERVICE_URL", defaultValue: "", }, + { + name: "LOWCODER_SHOW_CUSTOM_AUTH_WELCOME_TEXT", + defaultValue: "", + }, { name: "REACT_APP_ENV", defaultValue: "production", diff --git a/client/packages/lowcoder/src/app-env.d.ts b/client/packages/lowcoder/src/app-env.d.ts index 95d829c6f..9d645614a 100644 --- a/client/packages/lowcoder/src/app-env.d.ts +++ b/client/packages/lowcoder/src/app-env.d.ts @@ -37,6 +37,7 @@ declare var LOWCODER_NODE_SERVICE_URL: string; declare var LOWCODER_SHOW_BRAND: string; declare var LOWCODER_CUSTOM_LOGO: string; declare var LOWCODER_CUSTOM_LOGO_SQUARE: string; +declare var LOWCODER_SHOW_CUSTOM_AUTH_WELCOME_TEXT: string; declare var REACT_APP_ENV: string; declare var REACT_APP_BUILD_ID: string; declare var REACT_APP_LOG_LEVEL: string; From 8b01d789f047fd38e083a53f580118a00943ceac Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Wed, 27 Sep 2023 18:55:17 +0500 Subject: [PATCH 06/43] feat: oauth flow updates for third party login options --- client/packages/lowcoder-cli/client.d.ts | 2 +- .../packages/lowcoder-dev-utils/buildVars.js | 4 +- client/packages/lowcoder/src/app-env.d.ts | 2 +- client/packages/lowcoder/src/app.tsx | 30 +++++++---- .../lowcoder/src/constants/authConstants.ts | 4 ++ .../lowcoder/src/constants/routesURL.ts | 4 ++ .../src/pages/common/inviteLanding.tsx | 2 +- .../lowcoder/src/pages/userAuth/authUtils.ts | 2 +- .../lowcoder/src/pages/userAuth/formLogin.tsx | 52 +++++++++++++------ .../lowcoder/src/pages/userAuth/index.tsx | 32 +++++++++--- .../lowcoder/src/pages/userAuth/login.tsx | 31 +++++++---- .../lowcoder/src/pages/userAuth/register.tsx | 35 ++++++++++--- 12 files changed, 143 insertions(+), 57 deletions(-) diff --git a/client/packages/lowcoder-cli/client.d.ts b/client/packages/lowcoder-cli/client.d.ts index 1a94b5149..98926bd29 100644 --- a/client/packages/lowcoder-cli/client.d.ts +++ b/client/packages/lowcoder-cli/client.d.ts @@ -34,7 +34,7 @@ declare var LOWCODER_NODE_SERVICE_URL: string; declare var LOWCODER_SHOW_BRAND: string; declare var LOWCODER_CUSTOM_LOGO: string; declare var LOWCODER_CUSTOM_LOGO_SQUARE: string; -declare var LOWCODER_SHOW_CUSTOM_AUTH_WELCOME_TEXT: string; +declare var LOWCODER_CUSTOM_AUTH_WELCOME_TEXT: string; declare var REACT_APP_ENV: string; declare var REACT_APP_BUILD_ID: string; declare var REACT_APP_LOG_LEVEL: string; diff --git a/client/packages/lowcoder-dev-utils/buildVars.js b/client/packages/lowcoder-dev-utils/buildVars.js index fa4d6f4c3..5fa8a40c6 100644 --- a/client/packages/lowcoder-dev-utils/buildVars.js +++ b/client/packages/lowcoder-dev-utils/buildVars.js @@ -36,8 +36,8 @@ export const buildVars = [ defaultValue: "", }, { - name: "LOWCODER_SHOW_CUSTOM_AUTH_WELCOME_TEXT", - defaultValue: "", + name: "LOWCODER_CUSTOM_AUTH_WELCOME_TEXT", + defaultValue: "This is custom welcome message", }, { name: "REACT_APP_ENV", diff --git a/client/packages/lowcoder/src/app-env.d.ts b/client/packages/lowcoder/src/app-env.d.ts index 9d645614a..f11d51d0e 100644 --- a/client/packages/lowcoder/src/app-env.d.ts +++ b/client/packages/lowcoder/src/app-env.d.ts @@ -37,7 +37,7 @@ declare var LOWCODER_NODE_SERVICE_URL: string; declare var LOWCODER_SHOW_BRAND: string; declare var LOWCODER_CUSTOM_LOGO: string; declare var LOWCODER_CUSTOM_LOGO_SQUARE: string; -declare var LOWCODER_SHOW_CUSTOM_AUTH_WELCOME_TEXT: string; +declare var LOWCODER_CUSTOM_AUTH_WELCOME_TEXT: string; declare var REACT_APP_ENV: string; declare var REACT_APP_BUILD_ID: string; declare var REACT_APP_LOG_LEVEL: string; diff --git a/client/packages/lowcoder/src/app.tsx b/client/packages/lowcoder/src/app.tsx index 68742a6fc..12d30f54b 100644 --- a/client/packages/lowcoder/src/app.tsx +++ b/client/packages/lowcoder/src/app.tsx @@ -13,6 +13,8 @@ import { IMPORT_APP_FROM_TEMPLATE_URL, INVITE_LANDING_URL, isAuthUnRequired, + ORG_AUTH_LOGIN_URL, + ORG_AUTH_REGISTER_URL, QUERY_LIBRARY_URL, SETTING, TRASH_URL, @@ -70,10 +72,11 @@ const Wrapper = (props: { children: React.ReactNode }) => ( type AppIndexProps = { isFetchUserFinished: boolean; isFetchHomeFinished: boolean; - isFetchingConfig: boolean; + // isFetchingConfig: boolean; + currentOrgId?: string; orgDev: boolean; defaultHomePage: string | null | undefined; - fetchConfig: () => void; + fetchConfig: (orgId?: string) => void; getCurrentUser: () => void; fetchHome: () => void; favicon: string; @@ -83,18 +86,22 @@ type AppIndexProps = { class AppIndex extends React.Component { componentDidMount() { this.props.getCurrentUser(); - if (!history.location.pathname.startsWith("/invite/")) { - this.props.fetchConfig(); - } - if (history.location.pathname === BASE_URL) { + const { pathname } = history.location; + + this.props.fetchConfig(this.props.currentOrgId); + + if (pathname === BASE_URL) { this.props.fetchHome(); } } - componentDidUpdate() { + componentDidUpdate(prevProps: AppIndexProps) { if (history.location.pathname === BASE_URL) { this.props.fetchHome(); } + if(prevProps.currentOrgId !== this.props.currentOrgId) { + this.props.fetchConfig(this.props.currentOrgId); + } } render() { @@ -103,7 +110,7 @@ class AppIndex extends React.Component { // make sure all users in this app have checked login info if ( !this.props.isFetchUserFinished || - this.props.isFetchingConfig || + // this.props.isFetchingConfig || (pathname === BASE_URL && !this.props.isFetchHomeFinished) ) { const hideLoadingHeader = isTemplate || isAuthUnRequired(pathname); @@ -153,6 +160,8 @@ class AppIndex extends React.Component { component={ApplicationHome} /> + + @@ -176,8 +185,9 @@ class AppIndex extends React.Component { const mapStateToProps = (state: AppState) => ({ isFetchUserFinished: isFetchUserFinished(state), - isFetchingConfig: getSystemConfigFetching(state), + // isFetchingConfig: getSystemConfigFetching(state), orgDev: state.ui.users.user.orgDev, + currentOrgId: state.ui.users.user.currentOrgId, defaultHomePage: state.ui.application.homeOrg?.commonSettings.defaultHomePage, isFetchHomeFinished: state.ui.application.loadingStatus.fetchHomeDataFinished, favicon: getBrandingConfig(state)?.favicon @@ -190,7 +200,7 @@ const mapDispatchToProps = (dispatch: any) => ({ getCurrentUser: () => { dispatch(fetchUserAction()); }, - fetchConfig: () => dispatch(fetchConfigAction()), + fetchConfig: (orgId?: string) => dispatch(fetchConfigAction(orgId)), fetchHome: () => dispatch(fetchHomeData({})), }); diff --git a/client/packages/lowcoder/src/constants/authConstants.ts b/client/packages/lowcoder/src/constants/authConstants.ts index 7e0e074d9..323615f16 100644 --- a/client/packages/lowcoder/src/constants/authConstants.ts +++ b/client/packages/lowcoder/src/constants/authConstants.ts @@ -3,6 +3,8 @@ import { AUTH_LOGIN_URL, AUTH_REGISTER_URL, OAUTH_REDIRECT, + ORG_AUTH_LOGIN_URL, + ORG_AUTH_REGISTER_URL, } from "constants/routesURL"; import { InviteInfo } from "api/inviteApi"; import Login, { ThirdPartyBindCard } from "pages/userAuth/login"; @@ -73,6 +75,8 @@ export const AuthRoutes: Array<{ path: string; component: React.ComponentType `${ALL_APPLICATIONS_URL}/${appId}/${viewMode}`; @@ -49,6 +51,8 @@ export const isAuthUnRequired = (pathname: string): boolean => { return ( pathname.startsWith("/invite/") || pathname.startsWith(USER_AUTH_URL) || + pathname.endsWith('/auth/login') || + pathname.endsWith('/auth/register') || pathname.startsWith(COMPONENT_DOC_URL) ); }; diff --git a/client/packages/lowcoder/src/pages/common/inviteLanding.tsx b/client/packages/lowcoder/src/pages/common/inviteLanding.tsx index 0d0d09d32..cce825f18 100644 --- a/client/packages/lowcoder/src/pages/common/inviteLanding.tsx +++ b/client/packages/lowcoder/src/pages/common/inviteLanding.tsx @@ -58,7 +58,7 @@ function InviteLanding(props: InviteLandingProp) { messageInstance.error(errorResp.message); history.push(BASE_URL); }).finally(() => { - fetchConfig(orgId); + // fetchConfig(orgId); }); }, [fetchUserFinished, invitationId, fetchConfig]); return null; diff --git a/client/packages/lowcoder/src/pages/userAuth/authUtils.ts b/client/packages/lowcoder/src/pages/userAuth/authUtils.ts index 497528022..cff083fdf 100644 --- a/client/packages/lowcoder/src/pages/userAuth/authUtils.ts +++ b/client/packages/lowcoder/src/pages/userAuth/authUtils.ts @@ -23,7 +23,7 @@ import { } from "constants/authConstants"; export const AuthContext = createContext<{ - systemConfig: SystemConfig; + systemConfig?: SystemConfig; inviteInfo?: AuthInviteInfo; thirdPartyAuthError?: boolean; }>(undefined as any); diff --git a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx index cf18146b9..5c60e3140 100644 --- a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx @@ -6,7 +6,7 @@ import { LoginCardTitle, StyledRouteLink, } from "pages/userAuth/authComponents"; -import React, { useContext, useState } from "react"; +import React, { useContext, useMemo, useState } from "react"; import styled from "styled-components"; import UserApi from "api/userApi"; import { useRedirectUrl } from "util/hooks"; @@ -15,8 +15,8 @@ import { UserConnectionSource } from "@lowcoder-ee/constants/userConstants"; import { trans } from "i18n"; import { AuthContext, useAuthSubmit } from "pages/userAuth/authUtils"; import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; -import { AUTH_REGISTER_URL } from "constants/routesURL"; -import { useLocation } from "react-router-dom"; +import { AUTH_REGISTER_URL, ORG_AUTH_REGISTER_URL } from "constants/routesURL"; +import { useLocation, useParams } from "react-router-dom"; import { Divider } from "antd"; const AccountLoginWrapper = styled(FormWrapperMobile)` @@ -25,15 +25,26 @@ const AccountLoginWrapper = styled(FormWrapperMobile)` margin-bottom: 106px; `; -export default function FormLogin() { +type FormLoginProps = { + organizationId?: string; +} + +export default function FormLogin(props: FormLoginProps) { const [account, setAccount] = useState(""); const [password, setPassword] = useState(""); const redirectUrl = useRedirectUrl(); const { systemConfig, inviteInfo } = useContext(AuthContext); const invitationId = inviteInfo?.invitationId; - const invitedOrganizationId = inviteInfo?.invitedOrganizationId; const authId = systemConfig?.form.id; const location = useLocation(); + const orgId = useParams().orgId; + + // const organizationId = useMemo(() => { + // if(inviteInfo?.invitedOrganizationId) { + // return inviteInfo?.invitedOrganizationId; + // } + // return orgId; + // }, [ inviteInfo, orgId ]) const { onSubmit, loading } = useAuthSubmit( () => @@ -71,20 +82,27 @@ export default function FormLogin() { {trans("userAuth.login")} - - - + + {props.organizationId && ( + <> + + + + )} - {systemConfig.form.enableRegister && ( - - {trans("userAuth.register")} - - )} + + {trans("userAuth.register")} + ); diff --git a/client/packages/lowcoder/src/pages/userAuth/index.tsx b/client/packages/lowcoder/src/pages/userAuth/index.tsx index 1e0fb898f..6d5e322ae 100644 --- a/client/packages/lowcoder/src/pages/userAuth/index.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/index.tsx @@ -1,19 +1,39 @@ import { AUTH_LOGIN_URL, USER_AUTH_URL } from "constants/routesURL"; -import { Redirect, Route, Switch, useLocation } from "react-router-dom"; -import React from "react"; -import { useSelector } from "react-redux"; +import { Redirect, Route, Switch, useLocation, useParams } from "react-router-dom"; +import React, { useEffect, useMemo } from "react"; +import { useSelector, useDispatch } from "react-redux"; import { selectSystemConfig } from "redux/selectors/configSelectors"; import { AuthContext } from "pages/userAuth/authUtils"; import { AuthRoutes } from "@lowcoder-ee/constants/authConstants"; import { AuthLocationState } from "constants/authConstants"; import { ProductLoading } from "components/ProductLoading"; +import { fetchConfigAction } from "redux/reduxActions/configActions"; +import _ from "lodash"; export default function UserAuth() { + const dispatch = useDispatch(); const location = useLocation(); - const systemConfig = useSelector(selectSystemConfig); - if (!systemConfig) { + const systemConfig = useSelector(selectSystemConfig, _.isEqual); + const orgId = useParams().orgId; + const inviteInfo = location.state?.inviteInfo; + + const organizationId = useMemo(() => { + if(inviteInfo?.invitedOrganizationId) { + return inviteInfo?.invitedOrganizationId; + } + return orgId; + }, [ orgId, inviteInfo ]) + + useEffect(() => { + if(organizationId) { + dispatch(fetchConfigAction(organizationId)); + } + }, [organizationId, dispatch]) + + if (organizationId && !systemConfig) { return ; } + return ( {AuthRoutes.map((route) => ( - + ))} diff --git a/client/packages/lowcoder/src/pages/userAuth/login.tsx b/client/packages/lowcoder/src/pages/userAuth/login.tsx index a847e93cf..26e6915c3 100644 --- a/client/packages/lowcoder/src/pages/userAuth/login.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/login.tsx @@ -1,11 +1,11 @@ -import { useLocation } from "react-router-dom"; +import { useLocation, useParams } from "react-router-dom"; import { AuthSearchParams } from "constants/authConstants"; import { CommonTextLabel } from "components/Label"; import { trans } from "i18n"; import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; import FormLogin from "@lowcoder-ee/pages/userAuth/formLogin"; import { AuthContainer } from "pages/userAuth/authComponents"; -import React, { useContext } from "react"; +import React, { useContext, useMemo } from "react"; import { AuthContext, getLoginTitle } from "pages/userAuth/authUtils"; import styled from "styled-components"; import { requiresUnAuth } from "pages/userAuth/authHOC"; @@ -69,8 +69,8 @@ export const ThirdPartyBindCard = () => { ().orgId; + + const loginType = systemConfig?.authConfigs.find( (config) => config.sourceType === queryParams.get(AuthSearchParams.loginType) )?.sourceType; let autoJumpSource: string | undefined; @@ -96,6 +98,13 @@ function Login() { autoJumpSource = systemConfig.authConfigs[0].sourceType; } + const organizationId = useMemo(() => { + if(inviteInfo?.invitedOrganizationId) { + return inviteInfo?.invitedOrganizationId; + } + return orgId; + }, [ inviteInfo, orgId ]) + const thirdPartyLoginView = ( {!autoJumpSource && ( @@ -116,16 +125,18 @@ function Login() { if (loginType) { loginCardView = thirdPartyLoginView; // Specify the login type with query param - } else if (systemConfig.form.enableLogin) { - loginCardView = ; + } else if (systemConfig?.form.enableLogin) { + loginCardView = ; } else { loginCardView = thirdPartyLoginView; } + const loginTitle = organizationId && LOWCODER_CUSTOM_AUTH_WELCOME_TEXT !== "" + ? LOWCODER_CUSTOM_AUTH_WELCOME_TEXT + : getLoginTitle(inviteInfo?.createUserName, systemConfig?.branding?.brandName) + return ( - + {loginCardView} ); diff --git a/client/packages/lowcoder/src/pages/userAuth/register.tsx b/client/packages/lowcoder/src/pages/userAuth/register.tsx index d93f386f4..2e9149228 100644 --- a/client/packages/lowcoder/src/pages/userAuth/register.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/register.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from "react"; +import React, { useContext, useState, useMemo } from "react"; import { AuthContainer, ConfirmButton, @@ -8,7 +8,7 @@ import { TermsAndPrivacyInfo, } from "pages/userAuth/authComponents"; import { FormInput, PasswordInput } from "lowcoder-design"; -import { AUTH_LOGIN_URL } from "constants/routesURL"; +import { AUTH_LOGIN_URL, ORG_AUTH_LOGIN_URL } from "constants/routesURL"; import UserApi from "api/userApi"; import { useRedirectUrl } from "util/hooks"; import { checkEmailValid } from "util/stringUtils"; @@ -20,6 +20,7 @@ import { trans } from "i18n"; import { AuthContext, checkPassWithMsg, useAuthSubmit } from "pages/userAuth/authUtils"; import { Divider } from "antd"; import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; +import { useParams } from "react-router-dom"; const StyledFormInput = styled(FormInput)` margin-bottom: 16px; @@ -43,8 +44,16 @@ function UserRegister() { const location = useLocation(); const { systemConfig, inviteInfo } = useContext(AuthContext); const invitationId = inviteInfo?.invitationId; - const invitedOrganizationId = inviteInfo?.invitedOrganizationId; - const authId = systemConfig.form.id; + // const invitedOrganizationId = inviteInfo?.invitedOrganizationId; + const orgId = useParams().orgId; + const organizationId = useMemo(() => { + if(inviteInfo?.invitedOrganizationId) { + return inviteInfo?.invitedOrganizationId; + } + return orgId; + }, [ inviteInfo, orgId ]) + + const authId = systemConfig?.form.id; const { loading, onSubmit } = useAuthSubmit( () => UserApi.formLogin({ @@ -58,12 +67,17 @@ function UserRegister() { false, redirectUrl ); - if (!systemConfig || !systemConfig.form.enableRegister) { + + if (!systemConfig || !systemConfig?.form.enableRegister) { return null; } + const registerTitle = organizationId && LOWCODER_CUSTOM_AUTH_WELCOME_TEXT !== "" + ? LOWCODER_CUSTOM_AUTH_WELCOME_TEXT + : trans("userAuth.register") + return ( - + {trans("userAuth.registerByEmail")} )} - + {trans("userAuth.userLogin")} From 843a327e7b9e0cc72f19ecefa3557d2d7c6d1229 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 13:36:56 +0000 Subject: [PATCH 07/43] build(deps-dev): bump @types/react-resizable in /client Bumps [@types/react-resizable](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-resizable) from 1.7.4 to 3.0.5. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-resizable) --- updated-dependencies: - dependency-name: "@types/react-resizable" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- client/package.json | 2 +- client/yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/package.json b/client/package.json index 829ffdd41..f10da6f8c 100644 --- a/client/package.json +++ b/client/package.json @@ -33,7 +33,7 @@ "@types/qrcode.react": "^1.0.2", "@types/react-grid-layout": "^1.3.0", "@types/react-helmet": "^6.1.5", - "@types/react-resizable": "^1.7.4", + "@types/react-resizable": "^3.0.5", "@types/react-router-dom": "^5.3.2", "@types/shelljs": "^0.8.11", "@types/styled-components": "^5.1.19", diff --git a/client/yarn.lock b/client/yarn.lock index 4748d1eaf..e85cd3511 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -4097,12 +4097,12 @@ __metadata: languageName: node linkType: hard -"@types/react-resizable@npm:^1.7.4": - version: 1.7.4 - resolution: "@types/react-resizable@npm:1.7.4" +"@types/react-resizable@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/react-resizable@npm:3.0.5" dependencies: "@types/react": "*" - checksum: d665bb2ddf830b9f841be21204cee119602b3d983537a94ccbad40deb7cd602e04742e3e013009bbb27c2d0fe72441b29ed48bc75f7e482cfb25eaf45f281dc9 + checksum: d7ead4fb5d30136ae8664f978dd7b4ccef1a4c6acd44e3676ebfa31b261f3b5194330ae9747b9a5d381f5befe0f56043803560ded323b665eb0e46430a0e6bb9 languageName: node linkType: hard @@ -17221,7 +17221,7 @@ __metadata: "@types/qrcode.react": ^1.0.2 "@types/react-grid-layout": ^1.3.0 "@types/react-helmet": ^6.1.5 - "@types/react-resizable": ^1.7.4 + "@types/react-resizable": ^3.0.5 "@types/react-router-dom": ^5.3.2 "@types/shelljs": ^0.8.11 "@types/styled-components": ^5.1.19 From 451cb7365f4b2d7ab3e48fb87e403d6724070778 Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Mon, 2 Oct 2023 12:30:01 +0500 Subject: [PATCH 08/43] feat: show custom message if set --- .../packages/lowcoder-dev-utils/buildVars.js | 2 +- .../packages/lowcoder/src/i18n/locales/en.ts | 1 + .../packages/lowcoder/src/i18n/locales/zh.ts | 1 + .../src/pages/userAuth/authComponents.tsx | 26 +++++++++++++++-- .../lowcoder/src/pages/userAuth/formLogin.tsx | 23 ++++----------- .../lowcoder/src/pages/userAuth/login.tsx | 13 +++++++-- .../lowcoder/src/pages/userAuth/register.tsx | 28 +++++++++++-------- .../userAuth/thirdParty/thirdPartyAuth.tsx | 2 ++ 8 files changed, 60 insertions(+), 36 deletions(-) diff --git a/client/packages/lowcoder-dev-utils/buildVars.js b/client/packages/lowcoder-dev-utils/buildVars.js index 5fa8a40c6..1f25eb122 100644 --- a/client/packages/lowcoder-dev-utils/buildVars.js +++ b/client/packages/lowcoder-dev-utils/buildVars.js @@ -37,7 +37,7 @@ export const buildVars = [ }, { name: "LOWCODER_CUSTOM_AUTH_WELCOME_TEXT", - defaultValue: "This is custom welcome message", + defaultValue: "", }, { name: "REACT_APP_ENV", diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index ddebe2166..5f89000a3 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1960,6 +1960,7 @@ export const en = { resetSuccess: "Reset succeeded", resetSuccessDesc: "Password reset succeeded. The new password is: {password}", copyPassword: "Copy password", + poweredByLowcoder: "Powered by Lowcoder.cloud" }, preLoad: { jsLibraryHelpText: diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts index 753c456c6..8cd96a946 100644 --- a/client/packages/lowcoder/src/i18n/locales/zh.ts +++ b/client/packages/lowcoder/src/i18n/locales/zh.ts @@ -1934,6 +1934,7 @@ userAuth: { resetSuccess: "重置成功", resetSuccessDesc: "密码重置成功.新密码为:{password}", copyPassword: "复制密码", + poweredByLowcoder: "供电 Lowcoder.cloud" }, preLoad: { jsLibraryHelpText: "通过URL链接向当前应用程序添加JavaScript库.lodash、day.js、uuid、numbro内置于系统中,可立即使用.JavaScript库在应用程序初始化之前加载,这可能会影响应用程序的性能.", diff --git a/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx b/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx index b56804b03..81847b6b3 100644 --- a/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/authComponents.tsx @@ -32,7 +32,7 @@ const AuthCard = styled.div` } `; -const AuthCardTitle = styled.div<{ type?: string }>` +const AuthCardHeading = styled.div<{ type?: string }>` font-weight: 600; font-size: 28px; color: #222222; @@ -51,6 +51,12 @@ const AuthCardTitle = styled.div<{ type?: string }>` } `; +const AuthCardSubHeading = styled.div` + font-size: 14px; + color: #222222; + line-height: 14px; +` + const AuthBottom = styled.div` display: flex; align-items: center; @@ -116,10 +122,24 @@ const StyledConfirmButton = styled(TacoButton)` transition: unset; `; -export const AuthContainer = (props: { children: any; title?: string; type?: string }) => { +export const AuthContainer = (props: { + children: any; + heading?: string; + subHeading?: string; + type?: string +}) => { return ( - {props.title || ""} + + {props.heading || ""} + + { props.subHeading && ( + + {props.subHeading} + + )} {props.children} ); diff --git a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx index 5c60e3140..186c62c7c 100644 --- a/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/formLogin.tsx @@ -6,7 +6,7 @@ import { LoginCardTitle, StyledRouteLink, } from "pages/userAuth/authComponents"; -import React, { useContext, useMemo, useState } from "react"; +import React, { useContext, useState } from "react"; import styled from "styled-components"; import UserApi from "api/userApi"; import { useRedirectUrl } from "util/hooks"; @@ -17,7 +17,6 @@ import { AuthContext, useAuthSubmit } from "pages/userAuth/authUtils"; import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; import { AUTH_REGISTER_URL, ORG_AUTH_REGISTER_URL } from "constants/routesURL"; import { useLocation, useParams } from "react-router-dom"; -import { Divider } from "antd"; const AccountLoginWrapper = styled(FormWrapperMobile)` display: flex; @@ -39,13 +38,6 @@ export default function FormLogin(props: FormLoginProps) { const location = useLocation(); const orgId = useParams().orgId; - // const organizationId = useMemo(() => { - // if(inviteInfo?.invitedOrganizationId) { - // return inviteInfo?.invitedOrganizationId; - // } - // return orgId; - // }, [ inviteInfo, orgId ]) - const { onSubmit, loading } = useAuthSubmit( () => UserApi.formLogin({ @@ -84,14 +76,11 @@ export default function FormLogin(props: FormLoginProps) { {props.organizationId && ( - <> - - - + )} diff --git a/client/packages/lowcoder/src/pages/userAuth/login.tsx b/client/packages/lowcoder/src/pages/userAuth/login.tsx index 26e6915c3..6478c1c31 100644 --- a/client/packages/lowcoder/src/pages/userAuth/login.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/login.tsx @@ -64,7 +64,7 @@ const thirdPartyLoginLabel = (name: string) => trans("userAuth.signInLabel", { n export const ThirdPartyBindCard = () => { const { systemConfig } = useContext(AuthContext); return ( - + + {loginCardView} ); diff --git a/client/packages/lowcoder/src/pages/userAuth/register.tsx b/client/packages/lowcoder/src/pages/userAuth/register.tsx index 2e9149228..151d00a20 100644 --- a/client/packages/lowcoder/src/pages/userAuth/register.tsx +++ b/client/packages/lowcoder/src/pages/userAuth/register.tsx @@ -18,7 +18,6 @@ import { useLocation } from "react-router-dom"; import { UserConnectionSource } from "@lowcoder-ee/constants/userConstants"; import { trans } from "i18n"; import { AuthContext, checkPassWithMsg, useAuthSubmit } from "pages/userAuth/authUtils"; -import { Divider } from "antd"; import { ThirdPartyAuth } from "pages/userAuth/thirdParty/thirdPartyAuth"; import { useParams } from "react-router-dom"; @@ -72,12 +71,20 @@ function UserRegister() { return null; } - const registerTitle = organizationId && LOWCODER_CUSTOM_AUTH_WELCOME_TEXT !== "" + const registerHeading = organizationId && LOWCODER_CUSTOM_AUTH_WELCOME_TEXT !== "" ? LOWCODER_CUSTOM_AUTH_WELCOME_TEXT : trans("userAuth.register") + const registerSubHeading = organizationId && LOWCODER_CUSTOM_AUTH_WELCOME_TEXT !== "" + ? trans("userAuth.poweredByLowcoder") + : '' + return ( - + {trans("userAuth.registerByEmail")} setSubmitBtnDisable(!e.target.checked)} /> - {Boolean(invitationId) && ( - <> - - - + {organizationId && ( + )} + { Boolean(socialLoginButtons.length) && } {socialLoginButtons} ); From 1aa9f112ab3ea88a354d8fd00a90a7c2ed0fc5ee Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Sat, 7 Oct 2023 12:27:41 +0300 Subject: [PATCH 09/43] agora integration initial setaup --- client/packages/lowcoder/package.json | 2 + .../src/comps/comps/containerBase/utils.tsx | 1 + .../lowcoder/src/comps/comps/imageComp.tsx | 47 +- .../comps/comps/videoComp/videoContolComp.tsx | 226 ++++++++ .../comps/videoComp/videoControlButton.tsx | 376 +++++++++++++ .../comps/videoComp/videoMeetingComp.tsx | 323 +++++++++++ .../videoComp/videobuttonCompConstants.tsx | 111 ++++ .../src/comps/hooks/agoraFunctions.tsx | 144 +++++ .../lowcoder/src/comps/hooks/hookComp.tsx | 27 +- .../src/comps/hooks/hookCompTypes.tsx | 7 +- .../src/comps/hooks/videoControllerComp.tsx | 526 ++++++++++++++++++ client/packages/lowcoder/src/comps/index.tsx | 56 +- .../lowcoder/src/comps/uiCompRegistry.ts | 15 +- .../src/comps/utils/propertyUtils.tsx | 1 + .../packages/lowcoder/src/constants/Layers.ts | 1 + .../packages/lowcoder/src/i18n/locales/en.ts | 308 ++++++---- .../src/pages/editor/editorConstants.tsx | 6 +- 17 files changed, 2052 insertions(+), 125 deletions(-) create mode 100644 client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx create mode 100644 client/packages/lowcoder/src/comps/comps/videoComp/videoControlButton.tsx create mode 100644 client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx create mode 100644 client/packages/lowcoder/src/comps/comps/videoComp/videobuttonCompConstants.tsx create mode 100644 client/packages/lowcoder/src/comps/hooks/agoraFunctions.tsx create mode 100644 client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx diff --git a/client/packages/lowcoder/package.json b/client/packages/lowcoder/package.json index 278628768..4d856faee 100644 --- a/client/packages/lowcoder/package.json +++ b/client/packages/lowcoder/package.json @@ -36,6 +36,8 @@ "@types/react-signature-canvas": "^1.0.2", "@types/react-test-renderer": "^18.0.0", "@types/react-virtualized": "^9.21.21", + "agora-access-token": "^2.0.4", + "agora-rtc-sdk-ng": "^4.19.0", "ali-oss": "^6.17.1", "antd": "5.7.2", "antd-img-crop": "^4.12.2", diff --git a/client/packages/lowcoder/src/comps/comps/containerBase/utils.tsx b/client/packages/lowcoder/src/comps/comps/containerBase/utils.tsx index 35cc13d10..ca7ecd14d 100644 --- a/client/packages/lowcoder/src/comps/comps/containerBase/utils.tsx +++ b/client/packages/lowcoder/src/comps/comps/containerBase/utils.tsx @@ -95,6 +95,7 @@ export function oldContainerParamsToNew(params: any): any { container: { layout: params.value.layout, items: params.value.items }, }; const newParams = { ...params, value: newValue }; + // console.log("tempParams", newParams); // log.debug("params: ", params, "newParams: ", newParams); return newParams; } diff --git a/client/packages/lowcoder/src/comps/comps/imageComp.tsx b/client/packages/lowcoder/src/comps/comps/imageComp.tsx index 871bfa9df..48a5f4784 100644 --- a/client/packages/lowcoder/src/comps/comps/imageComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/imageComp.tsx @@ -1,15 +1,27 @@ import styled, { css } from "styled-components"; import { Section, sectionNames } from "lowcoder-design"; -import { clickEvent, eventHandlerControl } from "../controls/eventHandlerControl"; +import { + clickEvent, + eventHandlerControl, +} from "../controls/eventHandlerControl"; import { StringStateControl } from "../controls/codeStateControl"; import { UICompBuilder, withDefault } from "../generators"; -import { NameConfig, NameConfigHidden, withExposingConfigs } from "../generators/withExposing"; +import { + NameConfig, + NameConfigHidden, + withExposingConfigs, +} from "../generators/withExposing"; import { RecordConstructorToView } from "lowcoder-core"; import { useEffect, useRef, useState } from "react"; import _ from "lodash"; import ReactResizeDetector from "react-resize-detector"; import { styleControl } from "comps/controls/styleControl"; -import { ImageStyle, ImageStyleType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants"; +import { + ImageStyle, + ImageStyleType, + heightCalculator, + widthCalculator, +} from "comps/controls/styleControlConstants"; import { hiddenPropertyView } from "comps/utils/propertyUtils"; import { trans } from "i18n"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; @@ -42,9 +54,9 @@ const getStyle = (style: ImageStyleType) => { img { border: 1px solid ${style.border}; border-radius: ${style.radius}; - margin: ${style.margin}; - padding: ${style.padding}; - max-width: ${widthCalculator(style.margin)}; + margin: ${style.margin}; + padding: ${style.padding}; + max-width: ${widthCalculator(style.margin)}; max-height: ${heightCalculator(style.margin)}; } @@ -67,7 +79,7 @@ const ContainerImg = (props: RecordConstructorToView) => { setWidth(img.naturalWidth); setHeight(img.naturalHeight); }; - } + }; useEffect(() => { const newImage = new Image(0, 0); @@ -79,14 +91,16 @@ const ContainerImg = (props: RecordConstructorToView) => { }; }, [props.src.value]); - useEffect(() =>{ + useEffect(() => { if (height && width) { onResize(); } - }, [height, width]) + }, [height, width]); // on safari const setStyle = (height: string, width: string) => { + console.log(width, height); + const img = imgRef.current; const imgDiv = img?.getElementsByTagName("div")[0]; const imgCurrent = img?.getElementsByTagName("img")[0]; @@ -117,7 +131,12 @@ const ContainerImg = (props: RecordConstructorToView) => { return ( -
+
{ })} -
{children.onEvent.getPropertyView()}
+
+ {children.onEvent.getPropertyView()} +
{children.autoHeight.getPropertyView()} {hiddenPropertyView(children)}
-
{children.style.getPropertyView()}
+
+ {children.style.getPropertyView()} +
); }) diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx b/client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx new file mode 100644 index 000000000..6e3bd8c96 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx @@ -0,0 +1,226 @@ +import styled, { css } from "styled-components"; +import { Section, sectionNames } from "lowcoder-design"; +import { + clickEvent, + eventHandlerControl, +} from "../../controls/eventHandlerControl"; +import { StringStateControl } from "../../controls/codeStateControl"; +import { UICompBuilder, withDefault } from "../../generators"; +import { + NameConfig, + NameConfigHidden, + withExposingConfigs, +} from "../../generators/withExposing"; +import { RecordConstructorToView } from "lowcoder-core"; +import { useEffect, useRef, useState } from "react"; +import _ from "lodash"; +import ReactResizeDetector from "react-resize-detector"; +import { styleControl } from "comps/controls/styleControl"; +import { + ImageStyle, + ImageStyleType, + heightCalculator, + widthCalculator, +} from "comps/controls/styleControlConstants"; +import { hiddenPropertyView } from "comps/utils/propertyUtils"; +import { trans } from "i18n"; +import { AutoHeightControl } from "comps/controls/autoHeightControl"; +import { BoolControl } from "comps/controls/boolControl"; +import { Image as AntImage } from "antd"; +import { DEFAULT_IMG_URL } from "util/stringUtils"; +import { + Button100, + ButtonCompWrapper, + ButtonStyleControl, +} from "./videobuttonCompConstants"; + +const Container = styled.div<{ $style: ImageStyleType | undefined }>` + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + .ant-image, + img { + width: 100%; + height: 100%; + } + + img { + object-fit: contain; + pointer-events: auto; + } + + ${(props) => props.$style && getStyle(props.$style)} +`; + +const getStyle = (style: ImageStyleType) => { + return css` + img { + border: 1px solid ${style.border}; + border-radius: ${style.radius}; + margin: ${style.margin}; + padding: ${style.padding}; + max-width: ${widthCalculator(style.margin)}; + max-height: ${heightCalculator(style.margin)}; + } + + .ant-image-mask { + border-radius: ${style.radius}; + } + `; +}; + +const EventOptions = [clickEvent] as const; + +const ContainerImg = (props: RecordConstructorToView) => { + const imgRef = useRef(null); + const conRef = useRef(null); + const [width, setWidth] = useState(0); + const [height, setHeight] = useState(0); + + const imgOnload = (img: HTMLImageElement) => { + img.onload = function () { + setWidth(img.naturalWidth); + setHeight(img.naturalHeight); + }; + }; + + useEffect(() => { + const newImage = new Image(0, 0); + newImage.src = props.src.value; + imgOnload(newImage); + newImage.onerror = function (e) { + newImage.src = DEFAULT_IMG_URL; + imgOnload(newImage); + }; + }, [props.src.value]); + + useEffect(() => { + if (height && width) { + onResize(); + } + }, [height, width]); + + // on safari + const setStyle = (height: string, width: string) => { + console.log(width, height); + + const img = imgRef.current; + console.log("img", img); + const imgDiv = img?.getElementsByTagName("button")[0]; + console.log("button", imgDiv); + + const imgCurrent = img?.getElementsByTagName("button")[0]; + img!.style.height = height; + img!.style.width = width; + imgDiv!.style.height = height; + imgDiv!.style.width = width; + // imgCurrent!.style.height = height; + // imgCurrent!.style.width = width; + }; + + const onResize = () => { + const img = imgRef.current; + const container = conRef.current; + console.log(container?.clientWidth, container?.clientHeight); + + if (!img?.clientWidth || !img?.clientHeight || props.autoHeight || !width) { + return; + } + // fixme border style bug on safari + setStyle(container?.clientHeight + "px", container?.clientWidth + "px"); + // if ( + // (_.divide(container?.clientWidth!, container?.clientHeight!) || 0) > + // (_.divide(Number(width), Number(height)) || 0) + // ) { + // setStyle("100%", "auto"); + // } else { + // setStyle("auto", "100%"); + // } + }; + return ( + + +
+ + // isDefault(props.type) + // ? props.onEvent("click") + // : submitForm(editorState, props.form) + // } + > + m + +
+
+
+ ); +}; + +const childrenMap = { + src: withDefault(StringStateControl, "https://temp.im/350x400"), + onEvent: eventHandlerControl(EventOptions), + style: styleControl(ImageStyle), + autoHeight: withDefault(AutoHeightControl, "fixed"), + supportPreview: BoolControl, +}; + +let ImageBasicComp = new UICompBuilder(childrenMap, (props) => { + return ; +}) + .setPropertyViewFn((children) => { + return ( + <> +
+ {children.src.propertyView({ + label: trans("image.src"), + })} + {children.supportPreview.propertyView({ + label: trans("image.supportPreview"), + tooltip: trans("image.supportPreviewTip"), + })} +
+ +
+ {children.onEvent.getPropertyView()} +
+ +
+ {children.autoHeight.getPropertyView()} + {hiddenPropertyView(children)} +
+ +
+ {children.style.getPropertyView()} +
+ + ); + }) + .build(); + +ImageBasicComp = class extends ImageBasicComp { + override autoHeight(): boolean { + return this.children.autoHeight.getView(); + } +}; + +export const VideoContolComp = withExposingConfigs(ImageBasicComp, [ + new NameConfig("src", trans("image.srcDesc")), + NameConfigHidden, +]); diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoControlButton.tsx b/client/packages/lowcoder/src/comps/comps/videoComp/videoControlButton.tsx new file mode 100644 index 000000000..217cb1bc6 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/videoComp/videoControlButton.tsx @@ -0,0 +1,376 @@ +import { BoolCodeControl, StringControl } from "comps/controls/codeControl"; +import { dropdownControl } from "comps/controls/dropdownControl"; +import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; +import { IconControl } from "comps/controls/iconControl"; +import { CompNameContext, EditorContext, EditorState } from "comps/editorState"; +import { withDefault } from "comps/generators"; +import { UICompBuilder } from "comps/generators/uiCompBuilder"; +import _ from "lodash"; +import { + disabledPropertyView, + hiddenPropertyView, + loadingPropertyView, +} from "comps/utils/propertyUtils"; +import { + CommonBlueLabel, + controlItem, + Dropdown, + Section, + sectionNames, +} from "lowcoder-design"; +import { trans } from "i18n"; +import styled, { css } from "styled-components"; + +import { + CommonNameConfig, + NameConfig, + withExposingConfigs, +} from "../../generators/withExposing"; +import { IForm } from "../formComp/formDataConstants"; +import { SimpleNameComp } from "../simpleNameComp"; +import { + Button100, + ButtonCompWrapper, + ButtonStyleControl, +} from "./videobuttonCompConstants"; +import { RefControl } from "comps/controls/refControl"; +import { + AutoHeightControl, + ImageStyleType, + heightCalculator, + widthCalculator, +} from "@lowcoder-ee/index.sdk"; +import { useEffect, useRef, useState } from "react"; +import ReactResizeDetector from "react-resize-detector"; + +const Container = styled.div<{ $style: any }>` + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + ${(props) => props.$style && getStyle(props.$style)} +`; + +const getStyle = (style: any) => { + return css` + button { + border: 1px solid ${style.border}; + border-radius: ${style.radius}; + margin: ${style.margin}; + padding: ${style.padding}; + max-width: ${widthCalculator(style.margin)}; + max-height: ${heightCalculator(style.margin)}; + } + `; +}; + +const FormLabel = styled(CommonBlueLabel)` + font-size: 13px; + margin-right: 4px; +`; + +const IconWrapper = styled.div<{ $style: any }>` + display: flex; + + ${(props) => props.$style && getStyleIcon(props.$style)} +`; + +function getStyleIcon(style: any) { + return css` + svg { + width: ${style.size} !important; + height: ${style.size} !important; + } + `; +} + +// const IconWrapper = styled.div<{ $styled: any }>` +// display: flex; +// svg { +// width: ${styled.width}px !important; +// height: ${styled.height}30px !important; +// } +// `; + +function getFormOptions(editorState: EditorState) { + return editorState + .uiCompInfoList() + .filter((info) => info.type === "form") + .map((info) => ({ + label: info.name, + value: info.name, + })); +} + +function getForm(editorState: EditorState, formName: string) { + const comp = editorState?.getUICompByName(formName); + if (comp && comp.children.compType.getView() === "form") { + return comp.children.comp as unknown as IForm; + } +} + +function getFormEventHandlerPropertyView( + editorState: EditorState, + formName: string +) { + const form = getForm(editorState, formName); + if (!form) { + return undefined; + } + return ( + + {form.onEventPropertyView( + <> + + editorState.setSelectedCompNames( + new Set([formName]), + "rightPanel" + ) + } + > + {formName} + + {trans("button.formButtonEvent")} + + )} + + ); +} + +class SelectFormControl extends SimpleNameComp { + override getPropertyView() { + const label = trans("button.formToSubmit"); + return controlItem( + { filterText: label }, + + {(editorState) => ( + <> + this.dispatchChangeValueAction(value)} + allowClear={true} + /> + {getFormEventHandlerPropertyView(editorState, this.value)} + + )} + + ); + } +} + +const typeOptions = [ + { + label: trans("button.default"), + value: "", + }, + { + label: trans("button.submit"), + value: "submit", + }, +] as const; + +function isDefault(type?: string) { + return !type; +} + +function submitForm(editorState: EditorState, formName: string) { + const form = getForm(editorState, formName); + if (form) { + form.submit(); + } +} + +let ButtonTmpComp = (function () { + const childrenMap = { + text: withDefault(StringControl, trans("button.button")), + iconSize: withDefault(StringControl, "20px"), + type: dropdownControl(typeOptions, ""), + autoHeight: withDefault(AutoHeightControl, "fixed"), + onEvent: ButtonEventHandlerControl, + disabled: BoolCodeControl, + loading: BoolCodeControl, + form: SelectFormControl, + prefixIcon: IconControl, + suffixIcon: IconControl, + style: ButtonStyleControl, + viewRef: RefControl, + }; + + return new UICompBuilder(childrenMap, (props) => { + const [width, setWidth] = useState(120); + const [height, setHeight] = useState(0); + + const imgRef = useRef(null); + const conRef = useRef(null); + useEffect(() => { + if (height && width) { + onResize(); + console.log("props", props, height, width); + } + }, [height, width]); + + const setStyle = (height: string, width: string) => { + console.log(width, height); + + const img = imgRef.current; + + const imgDiv = img?.getElementsByTagName("button")[0]; + console.log("img 1", img); + const imgCurrent = img?.getElementsByTagName("button")[0]; + console.log("img 2", imgCurrent); + img!.style.height = height; + img!.style.width = width; + imgDiv!.style.height = height; + imgDiv!.style.width = width; + // imgCurrent!.style.height = height; + // imgCurrent!.style.width = width; + }; + + const onResize = () => { + const img = imgRef.current; + console.log("img", img); + const container = conRef.current; + // console.log("img", container); + console.log( + "img", + !img?.clientWidth, + !img?.clientHeight, + props.autoHeight, + !width + ); + if ( + !img?.clientWidth || + !img?.clientHeight || + props.autoHeight || + !width + ) { + return; + } + // fixme border style bug on safari + // if ( + // (_.divide(container?.clientWidth!, container?.clientHeight!) || 0) > + // (_.divide(Number(width), Number(height)) || 0) + // ) { + // setStyle("100%", "auto"); + // } else { + console.log( + container?.clientHeight + "px", + container?.clientWidth + "px" + ); + + setStyle(container?.clientHeight + "px", container?.clientWidth + "px"); + // } + }; + + return ( + + {(editorState) => ( + + +
+ + isDefault(props.type) + ? props.onEvent("click") + : submitForm(editorState, props.form) + } + > + {props.prefixIcon && ( + + {props.prefixIcon} + + )} + { + props.text || + (props.prefixIcon || props.suffixIcon ? undefined : " ") // Avoid button disappearing + } + {props.suffixIcon && ( + + {props.suffixIcon} + + )} + +
+
+
+ )} +
+ ); + }) + .setPropertyViewFn((children) => ( + <> +
+ {children.text.propertyView({ label: trans("text") })} + {children.autoHeight.getPropertyView()} +
+
+ {children.type.propertyView({ + label: trans("prop.type"), + radioButton: true, + })} + {isDefault(children.type.getView()) + ? [ + children.onEvent.getPropertyView(), + disabledPropertyView(children), + loadingPropertyView(children), + ] + : children.form.getPropertyView()} +
+ +
+ {children.prefixIcon.propertyView({ + label: trans("button.prefixIcon"), + })} + {children.suffixIcon.propertyView({ + label: trans("button.suffixIcon"), + })} + {children.iconSize.propertyView({ + label: trans("meeting.iconSize"), + })} + {hiddenPropertyView(children)} +
+
+ {children.style.getPropertyView()} +
+ + )) + .build(); +})(); +ButtonTmpComp = class extends ButtonTmpComp { + override autoHeight(): boolean { + return this.children.autoHeight.getView(); + } +}; +export const VideoControlButton = withExposingConfigs(ButtonTmpComp, [ + new NameConfig("text", trans("button.textDesc")), + new NameConfig("loading", trans("button.loadingDesc")), + ...CommonNameConfig, +]); diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx b/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx new file mode 100644 index 000000000..460bebd63 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx @@ -0,0 +1,323 @@ +import { + ArrayControl, + ArrayOrJSONObjectControl, + BoolCodeControl, + JSONObjectArrayControl, + NumberControl, + StringControl, +} from "comps/controls/codeControl"; +import { dropdownControl } from "comps/controls/dropdownControl"; +import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; +import { IconControl } from "comps/controls/iconControl"; +import { CompNameContext, EditorContext, EditorState } from "comps/editorState"; +import { withDefault } from "comps/generators"; +import { UICompBuilder } from "comps/generators/uiCompBuilder"; +import ReactResizeDetector from "react-resize-detector"; +import _ from "lodash"; +import { + CommonBlueLabel, + controlItem, + Dropdown, + Section, + sectionNames, +} from "lowcoder-design"; +import { trans } from "i18n"; + +import styled, { css } from "styled-components"; +import { + CommonNameConfig, + NameConfig, + withExposingConfigs, +} from "../../generators/withExposing"; +import { IForm } from "../formComp/formDataConstants"; +import { SimpleNameComp } from "../simpleNameComp"; +import { ButtonStyleControl } from "./videobuttonCompConstants"; +import { RefControl } from "comps/controls/refControl"; +import { useEffect, useRef, useState } from "react"; + +import { AutoHeightControl } from "comps/controls/autoHeightControl"; +import { + arrayStringExposingStateControl, + booleanExposingStateControl, + jsonObjectExposingStateControl, + stringExposingStateControl, + withMethodExposing, +} from "@lowcoder-ee/index.sdk"; +// import useAgora from "@lowcoder-ee/comps/hooks/agoraFunctions"; + +const FormLabel = styled(CommonBlueLabel)` + font-size: 13px; + margin-right: 4px; +`; + +const IconWrapper = styled.div` + display: flex; +`; + +function getFormOptions(editorState: EditorState) { + return editorState + .uiCompInfoList() + .filter((info) => info.type === "form") + .map((info) => ({ + label: info.name, + value: info.name, + })); +} +const Container = styled.div<{ $style: any }>` + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + ${(props) => props.$style && getStyle(props.$style)} +`; + +const getStyle = (style: any) => { + return css` + button { + border: 1px solid ${style.border}; + border-radius: ${style.radius}; + margin: ${style.margin}; + padding: ${style.padding}; + } + `; +}; +function getForm(editorState: EditorState, formName: string) { + const comp = editorState?.getUICompByName(formName); + if (comp && comp.children.compType.getView() === "form") { + return comp.children.comp as unknown as IForm; + } +} + +function getFormEventHandlerPropertyView( + editorState: EditorState, + formName: string +) { + const form = getForm(editorState, formName); + if (!form) { + return undefined; + } + + return ( + + {form.onEventPropertyView( + <> + + editorState.setSelectedCompNames( + new Set([formName]), + "rightPanel" + ) + } + > + {formName} + + {trans("button.formButtonEvent")} + + )} + + ); +} + +class SelectFormControl extends SimpleNameComp { + override getPropertyView() { + const label = trans("button.formToSubmit"); + return controlItem( + { filterText: label }, + + {(editorState) => ( + <> + this.dispatchChangeValueAction(value)} + allowClear={true} + /> + {getFormEventHandlerPropertyView(editorState, this.value)} + + )} + + ); + } +} + +const typeOptions = [ + { + label: trans("button.default"), + value: "", + }, + { + label: trans("button.submit"), + value: "submit", + }, +] as const; + +let VideoCompBuilder = (function (props) { + const childrenMap = { + autoHeight: withDefault(AutoHeightControl, "fixed"), + type: dropdownControl(typeOptions, ""), + onEvent: ButtonEventHandlerControl, + disabled: BoolCodeControl, + loading: BoolCodeControl, + form: SelectFormControl, + prefixIcon: IconControl, + suffixIcon: IconControl, + style: ButtonStyleControl, + viewRef: RefControl, + appId: withDefault(StringControl, trans("prop.appid")), /// + videokey: withDefault(StringControl, trans("prop.videokey")), + participants: arrayStringExposingStateControl("participants"), + userId: stringExposingStateControl( + "text", + trans("meeting.userId", { name: "{{currentUser.name}}" }) + ), + }; + // const { client, videoHeight, videoWidth, setHeight, setWidth } = useAgora(); + + return new UICompBuilder(childrenMap, (props) => { + console.log("userId", props.userId.value); + // "afd10eabe68a4de68a76461be92c693c" + const videoRef = useRef(null); + const conRef = useRef(null); + + useEffect(() => { + onResize(); + }, []); + + useEffect(() => { + if (props.participants.value.length > 0) { + console.log("bbb", props.participants.value); + } + }, [props.participants.value]); + + const onResize = async () => { + const container = conRef.current; + let videoCo = videoRef.current; + videoCo!.style.height = container?.clientHeight + "px"; + videoCo!.style.width = container?.clientWidth + "px"; + }; + + return ( + + {(editorState) => ( + + + + + + )} + + ); + }) + .setPropertyViewFn((children) => ( + <> +
+ {children.userId.propertyView({ + label: trans("meeting.userId"), + })} + {children.autoHeight.getPropertyView()} + {children.videokey.propertyView({ + label: trans("prop.videokey"), + })} +
+ {/*
+ {/* {hiddenPropertyView(children)} +
*/} + + {/*
+ {children.type.propertyView({ + label: trans("prop.type"), + radioButton: true, + })} */} + {/* {isDefault(children.type.getView()) + ? [ + children.onEvent.getPropertyView(), + disabledPropertyView(children), + loadingPropertyView(children), + ] + : children.form.getPropertyView()} */} + {/*
*/} + + {/*
+ {children.prefixIcon.propertyView({ + label: trans("button.prefixIcon"), + })} + {children.suffixIcon.propertyView({ + label: trans("button.suffixIcon"), + })} + {hiddenPropertyView(children)} +
+ +
+ {children.style.getPropertyView()} +
*/} + + )) + .build(); +})(); + +VideoCompBuilder = class extends VideoCompBuilder { + override autoHeight(): boolean { + return this.children.autoHeight.getView(); + } +}; + +VideoCompBuilder = withMethodExposing(VideoCompBuilder, [ + { + method: { + name: "audioControl", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: (comp, values) => { + // let value = !comp.children.audioControl.getView().value; + // turnOnMicrophone(value); + // comp.children.audioControl.change(value); + }, + }, + // { + // method: { + // name: "videoControl", + // description: trans("meeting.actionBtnDesc"), + // params: [], + // }, + // execute: (comp, values) => { + // let value = !comp.children.videoControl.getView().value; + // turnOnCamera(value); + // comp.children.videoControl.change(value); + // }, + // }, + // { + // method: { + // name: "startMeeting", + // description: trans("meeting.actionBtnDesc"), + // params: [], + // }, + // execute: (comp, values) => { + // publishVideo(comp.children.appId.getView(), "testsdaadasdsa"); + // }, + // }, + // { + // method: { + // name: "endCall", + // description: trans("meeting.actionBtnDesc"), + // params: [], + // }, + // execute: (comp, values) => { + // let value = !comp.children.endCall.getView().value; + // leaveChannel(); + // comp.children.endCall.change(value); + // }, + // }, +]); + +export const VideoMeetingComp = withExposingConfigs(VideoCompBuilder, [ + // new NameConfig("appId", trans("button.textDesc")), + new NameConfig("loading", trans("button.loadingDesc")), + ...CommonNameConfig, +]); diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videobuttonCompConstants.tsx b/client/packages/lowcoder/src/comps/comps/videoComp/videobuttonCompConstants.tsx new file mode 100644 index 000000000..26da52f34 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/videoComp/videobuttonCompConstants.tsx @@ -0,0 +1,111 @@ +import { Button } from "antd"; +import { styleControl } from "comps/controls/styleControl"; +import { + ButtonStyleType, + ButtonStyle, +} from "comps/controls/styleControlConstants"; +import { migrateOldData } from "comps/generators/simpleGenerators"; +import styled, { css } from "styled-components"; +import { genActiveColor, genHoverColor } from "lowcoder-design"; +import { refMethods } from "comps/generators/withMethodExposing"; +import { + blurMethod, + clickMethod, + focusWithOptions, +} from "comps/utils/methodUtils"; + +export function getButtonStyle(buttonStyle: ButtonStyleType) { + const hoverColor = genHoverColor(buttonStyle.background); + const activeColor = genActiveColor(buttonStyle.background); + return css` + &&& { + border-radius: ${buttonStyle.radius}; + margin: ${buttonStyle.margin}; + padding: ${buttonStyle.padding}; + &:not(:disabled) { + // click animation color + --antd-wave-shadow-color: ${buttonStyle.border}; + border-color: ${buttonStyle.border}; + color: ${buttonStyle.text}; + background-color: ${buttonStyle.background}; + border-radius: ${buttonStyle.radius}; + margin: ${buttonStyle.margin}; + padding: ${buttonStyle.padding}; + + :hover, + :focus { + color: ${buttonStyle.text}; + background-color: ${hoverColor}; + border-color: ${buttonStyle.border === buttonStyle.background + ? hoverColor + : buttonStyle.border}; + } + + :active { + color: ${buttonStyle.text}; + background-color: ${activeColor}; + border-color: ${buttonStyle.border === buttonStyle.background + ? activeColor + : buttonStyle.border}; + } + } + } + `; +} + +export const Button100 = styled(Button)<{ $buttonStyle?: ButtonStyleType }>` + ${(props) => props.$buttonStyle && getButtonStyle(props.$buttonStyle)} + width: 100%; + height: auto; + display: inline-flex; + justify-content: center; + align-items: center; + overflow: hidden; + span { + overflow: hidden; + text-overflow: ellipsis; + } + gap: 6px; +`; + +export const ButtonCompWrapper = styled.div<{ disabled: boolean }>` + // The button component is disabled but can respond to drag & select events + ${(props) => + props.disabled && + ` + cursor: not-allowed; + button:disabled { + pointer-events: none; + } + `}; +`; + +/** + * Compatible with old data 2022-08-05 + */ +function fixOldData(oldData: any) { + if ( + oldData && + (oldData.hasOwnProperty("backgroundColor") || + oldData.hasOwnProperty("borderColor") || + oldData.hasOwnProperty("color")) + ) { + return { + background: oldData.backgroundColor, + border: oldData.borderColor, + text: oldData.color, + }; + } + return oldData; +} +const ButtonTmpStyleControl = styleControl(ButtonStyle); +export const ButtonStyleControl = migrateOldData( + ButtonTmpStyleControl, + fixOldData +); + +export const buttonRefMethods = refMethods([ + focusWithOptions, + blurMethod, + clickMethod, +]); diff --git a/client/packages/lowcoder/src/comps/hooks/agoraFunctions.tsx b/client/packages/lowcoder/src/comps/hooks/agoraFunctions.tsx new file mode 100644 index 000000000..c82de1180 --- /dev/null +++ b/client/packages/lowcoder/src/comps/hooks/agoraFunctions.tsx @@ -0,0 +1,144 @@ +import { useEffect, useState } from "react"; +import AgoraRTC, { + IAgoraRTCClient, + IAgoraRTCRemoteUser, + ICameraVideoTrack, + IMicrophoneAudioTrack, +} from "agora-rtc-sdk-ng"; // Update the import with correct types +import { v4 as uuidv4 } from "uuid"; + +const useAgora = () => { + const [client, setClient] = useState(null); + const [audioTrack, setAudioTrack] = useState( + null + ); + const [videoTrack, setVideoTrack] = useState(null); + const [isJoined, setIsJoined] = useState(false); + const [videoHeight, setHeight] = useState(200); + const [videoWidth, setWidth] = useState(200); + + const initializeAgora = () => { + const agoraClient = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" }); + setClient(agoraClient); + }; + + const turnOnCamera = async (flag: any) => { + if (videoTrack) { + return videoTrack.setEnabled(flag); + } + const newVideoTrack = await AgoraRTC.createCameraVideoTrack(); + newVideoTrack.play("camera-video"); + setVideoTrack(newVideoTrack); + }; + + const turnOnMicrophone = async (flag: any) => { + if (audioTrack) { + return audioTrack.setEnabled(flag); + } + const newAudioTrack = await AgoraRTC.createMicrophoneAudioTrack(); + newAudioTrack.play(); + setAudioTrack(newAudioTrack); + }; + + const leaveChannel = async () => { + if (isJoined) { + if (!client) { + console.error("Agora client is not initialized"); + return; + } + + if (!client.localTracks.length) { + console.error("No local tracks to unpublish"); + return; + } + + if (videoTrack) { + await turnOnCamera(false); + await client.unpublish(videoTrack); + videoTrack.stop(); + setVideoTrack(null); + } + + if (audioTrack) { + await turnOnMicrophone(false); + await client.unpublish(audioTrack); + audioTrack.stop(); + setAudioTrack(null); + } + + await client.leave(); + setIsJoined(false); + } + }; + + const joinChannel = async (appId: any, channel: any, token: any) => { + if (!channel) { + channel = "react-room"; + } + + if (isJoined) { + await leaveChannel(); + } + + client?.on("user-published", onUserPublish); + + await client?.join(appId, channel, token || null, uuidv4()); + setIsJoined(true); + }; + + const publishVideo = async (appId: any, channel: any) => { + await turnOnCamera(true); + + if (!isJoined) { + await joinChannel(appId, channel, null); + } + + await client?.publish(videoTrack!); + + const mediaStreamTrack = videoTrack?.getMediaStreamTrack(); + + if (mediaStreamTrack) { + const videoSettings = mediaStreamTrack.getSettings(); + const videoWidth = videoSettings.width; + const videoHeight = videoSettings.height; + setWidth(videoWidth!); + setHeight(videoHeight!); + console.log(`Video width: ${videoWidth}px, height: ${videoHeight}px`); + } else { + console.error("Media stream track not found"); + } + }; + + const onUserPublish = async ( + user: IAgoraRTCRemoteUser, + mediaType: string + ) => { + if (mediaType === "video") { + const remoteTrack = await client?.subscribe(user, mediaType); + remoteTrack?.play("remote-video"); + } + if (mediaType === "audio") { + const remoteTrack = await client?.subscribe(user, mediaType); + remoteTrack?.play(); + } + }; + + return { + client, + audioTrack, + videoTrack, + isJoined, + turnOnCamera, + turnOnMicrophone, + leaveChannel, + joinChannel, + publishVideo, + initializeAgora, + videoWidth, + videoHeight, + setHeight, + setWidth, + }; +}; + +export default useAgora; diff --git a/client/packages/lowcoder/src/comps/hooks/hookComp.tsx b/client/packages/lowcoder/src/comps/hooks/hookComp.tsx index b71169493..e5fa4d598 100644 --- a/client/packages/lowcoder/src/comps/hooks/hookComp.tsx +++ b/client/packages/lowcoder/src/comps/hooks/hookComp.tsx @@ -13,7 +13,11 @@ import { import { hookToStateComp, simpleValueComp } from "comps/generators/hookToComp"; import { withSimpleExposing } from "comps/generators/withExposing"; import { DrawerComp } from "comps/hooks/drawerComp"; -import { HookCompConstructor, HookCompMapRawType, HookCompType } from "comps/hooks/hookCompTypes"; +import { + HookCompConstructor, + HookCompMapRawType, + HookCompType, +} from "comps/hooks/hookCompTypes"; import { ModalComp } from "comps/hooks/modalComp"; import { trans } from "i18n"; import _ from "lodash"; @@ -28,6 +32,7 @@ import { MessageComp } from "./messageComp"; import { ThemeComp } from "./themeComp"; import UrlParamsHookComp from "./UrlParamsHookComp"; import { UtilsComp } from "./utilsComp"; +import { VideoCOntrollerComp } from "./videoControllerComp"; window._ = _; window.dayjs = dayjs; @@ -85,11 +90,12 @@ const HookMap: HookCompMapRawType = { currentTime: CurrentTimeHookComp, lodashJsLib: LodashJsLib, dayJsLib: DayJsLib, - momentJsLib: DayJsLib, // old components use this hook + momentJsLib: DayJsLib, // old components use this hook utils: UtilsComp, message: MessageComp, localStorage: LocalStorageComp, modal: ModalComp, + meeting: VideoCOntrollerComp, currentUser: CurrentUserHookComp, urlParams: UrlParamsHookComp, drawer: DrawerComp, @@ -111,9 +117,12 @@ function SelectHookView(props: { // Select the modal and its subcomponents on the left to display the modal useEffect(() => { if ( - (props.compType !== "modal" && props.compType !== "drawer") || + (props.compType !== "modal" && + props.compType !== "drawer" && + props.compType !== "meeting") || !selectedComp || - (editorState.selectSource !== "addComp" && editorState.selectSource !== "leftPanel") + (editorState.selectSource !== "addComp" && + editorState.selectSource !== "leftPanel") ) { return; } else if ((selectedComp as any).children.comp === props.comp) { @@ -125,7 +134,9 @@ function SelectHookView(props: { } else { // all child components of modal const allChildComp = getAllCompItems((props.comp as any).getCompTree()); - const selectChildComp = Object.values(allChildComp).find((child) => child === selectedComp); + const selectChildComp = Object.values(allChildComp).find( + (child) => child === selectedComp + ); const visible = props.comp.children.visible.getView().value; if (selectChildComp && !visible) { props.comp.children.visible.dispatch( @@ -140,7 +151,11 @@ function SelectHookView(props: { }, [selectedComp, editorState.selectSource]); return ( -
editorState.setSelectedCompNames(new Set([props.compName]))}> +
+ editorState.setSelectedCompNames(new Set([props.compName])) + } + > {props.children}
); diff --git a/client/packages/lowcoder/src/comps/hooks/hookCompTypes.tsx b/client/packages/lowcoder/src/comps/hooks/hookCompTypes.tsx index 1db9875a0..86aece2a2 100644 --- a/client/packages/lowcoder/src/comps/hooks/hookCompTypes.tsx +++ b/client/packages/lowcoder/src/comps/hooks/hookCompTypes.tsx @@ -3,6 +3,7 @@ import { withExposingRaw } from "comps/generators/withExposing"; const AllHookComp = [ "modal", "drawer", + "meeting", "title", "windowSize", "currentTime", @@ -17,7 +18,7 @@ const AllHookComp = [ "theme", ] as const; -export type HookCompType = typeof AllHookComp[number]; +export type HookCompType = (typeof AllHookComp)[number]; const AllHookCompSet = new Set(AllHookComp); export const isHookComp = (compType: string) => { @@ -41,6 +42,10 @@ const HookCompConfig: Record< category: "ui", singleton: false, }, + meeting: { + category: "ui", + singleton: false, + }, lodashJsLib: { category: "hide", }, diff --git a/client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx b/client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx new file mode 100644 index 000000000..f5cb68aca --- /dev/null +++ b/client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx @@ -0,0 +1,526 @@ +import { CloseOutlined } from "@ant-design/icons"; +import { Button } from "antd"; +import { ContainerCompBuilder } from "comps/comps/containerBase/containerCompBuilder"; +import { + gridItemCompToGridItems, + InnerGrid, +} from "comps/comps/containerComp/containerView"; +import { AutoHeightControl } from "comps/controls/autoHeightControl"; +import { BoolControl } from "comps/controls/boolControl"; +import { + JSONObjectArrayControl, + NumberControl, + StringControl, +} from "comps/controls/codeControl"; +import { + arrayStringExposingStateControl, + booleanExposingStateControl, + jsonObjectExposingStateControl, + jsonValueExposingStateControl, + numberExposingStateControl, +} from "comps/controls/codeStateControl"; +import { PositionControl } from "comps/controls/dropdownControl"; +import { + closeEvent, + eventHandlerControl, +} from "comps/controls/eventHandlerControl"; +import { styleControl } from "comps/controls/styleControl"; +import { DrawerStyle } from "comps/controls/styleControlConstants"; +import { withDefault } from "comps/generators"; +import { withMethodExposing } from "comps/generators/withMethodExposing"; +import { BackgroundColorContext } from "comps/utils/backgroundColorContext"; +import { CanvasContainerID } from "constants/domLocators"; +import { Layers } from "constants/Layers"; +import { trans } from "i18n"; +import { changeChildAction } from "lowcoder-core"; +import { + Drawer, + HintPlaceHolder, + Section, + sectionNames, +} from "lowcoder-design"; +import { useCallback, useEffect, useState } from "react"; +import { ResizeHandle } from "react-resizable"; +import styled from "styled-components"; +import { useUserViewMode } from "util/hooks"; +import { isNumeric } from "util/stringUtils"; +import { NameConfig, withExposingConfigs } from "../generators/withExposing"; +import { v4 as uuidv4 } from "uuid"; + +import AgoraRTC, { + ICameraVideoTrack, + IMicrophoneAudioTrack, + IAgoraRTCClient, + IAgoraRTCRemoteUser, + IRemoteVideoTrack, +} from "agora-rtc-sdk-ng"; +import { JSONObject } from "@lowcoder-ee/index.sdk"; + +const EventOptions = [closeEvent] as const; + +const DEFAULT_SIZE = 378; +const DEFAULT_PADDING = 16; + +const DrawerWrapper = styled.div` + // Shield the mouse events of the lower layer, the mask can be closed in the edit mode to prevent the lower layer from sliding + pointer-events: auto; +`; + +const ButtonStyle = styled(Button)` + position: absolute; + left: 0; + top: 0; + z-index: 10; + font-weight: 700; + box-shadow: none; + color: rgba(0, 0, 0, 0.45); + height: 54px; + width: 54px; + + svg { + width: 16px; + height: 16px; + } + + &, + :hover, + :focus { + background-color: transparent; + border: none; + } + + :hover, + :focus { + color: rgba(0, 0, 0, 0.75); + } +`; + +// If it is a number, use the px unit by default +function transToPxSize(size: string | number) { + return isNumeric(size) ? size + "px" : (size as string); +} + +const PlacementOptions = [ + { + label: trans("drawer.top"), + value: "top", + }, + { + label: trans("drawer.right"), + value: "right", + }, + { + label: trans("drawer.bottom"), + value: "bottom", + }, + { + label: trans("drawer.left"), + value: "left", + }, +] as const; + +let client: IAgoraRTCClient = AgoraRTC.createClient({ + mode: "rtc", + codec: "vp8", +}); + +let audioTrack: IMicrophoneAudioTrack; +let videoTrack: ICameraVideoTrack; + +const turnOnCamera = async (flag?: boolean) => { + if (videoTrack) { + return videoTrack.setEnabled(flag!); + } + videoTrack = await AgoraRTC.createCameraVideoTrack(); + videoTrack.play("camera-video"); +}; + +const turnOnMicrophone = async (flag?: boolean) => { + if (audioTrack) { + return audioTrack.setEnabled(flag!); + } + audioTrack = await AgoraRTC.createMicrophoneAudioTrack(); + audioTrack.play(); +}; + +const leaveChannel = async () => { + console.log("isJoined", isJoined); + + if (!client) { + console.error("Agora client is not initialized"); + return; + } + + if (!client.localTracks.length) { + console.error("No local tracks to unpublish"); + return; + } + if (videoTrack) { + // await turnOnCamera(false); + await client.unpublish(videoTrack); + videoTrack.stop(); + } + + if (audioTrack) { + // await turnOnMicrophone(false); + await client.unpublish(audioTrack); + audioTrack.stop(); + } + + await client.leave(); + isJoined = false; // Update the flag to indicate that you have left the channel +}; +let isJoined = false; + +const joinChannel = async (appId: any, channel: any, token: any) => { + if (!channel) { + channel = "react-room"; + } + + if (isJoined) { + await leaveChannel(); + } + + // client.on("user-published", onUserPublish); + + await client.join( + appId, + channel, + token || null, + Math.floor(100000 + Math.random() * 900000) + ); + + isJoined = true; +}; + +const publishVideo = async (appId: any, channel: any, height: any) => { + console.log("publishVideo", appId, channel, isJoined); + await turnOnCamera(true); + console.log(appId, channel); + + if (!isJoined) { + await joinChannel(appId, channel, null); + } + + console.log("publish videoTrack ", videoTrack); + + await client.publish(videoTrack); + + // turnOnCamera(true); + const mediaStreamTrack = videoTrack.getMediaStreamTrack(); + + if (mediaStreamTrack) { + const videoSettings = mediaStreamTrack.getSettings(); + const videoWidth = videoSettings.width; + const videoHeight = videoSettings.height; + console.log("videoHeight ", videoHeight); + + height.videoWidth.change(videoWidth); + height.videoHeight.change(videoHeight); + console.log(`Video width: ${videoWidth}px, height: ${videoHeight}px`); + } else { + console.error("Media stream track not found"); + } +}; + +const onUserPublish = async ( + user: IAgoraRTCRemoteUser, + mediaType: "video" | "audio" +) => { + if (mediaType === "video") { + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play("remote-video"); + } + if (mediaType === "audio") { + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play(); + } +}; + +let MTComp = (function () { + const childrenMap = { + visible: booleanExposingStateControl("visible"), + onEvent: eventHandlerControl(EventOptions), + width: StringControl, + height: StringControl, + autoHeight: AutoHeightControl, + style: styleControl(DrawerStyle), + placement: PositionControl, + maskClosable: withDefault(BoolControl, true), + showMask: withDefault(BoolControl, true), + audioControl: booleanExposingStateControl("false"), + videoControl: booleanExposingStateControl("true"), + endCall: booleanExposingStateControl("false"), + videoSettings: jsonObjectExposingStateControl(""), + videoWidth: numberExposingStateControl("videoWidth", 200), + videoHeight: numberExposingStateControl("videoHeight", 200), + appId: withDefault(StringControl, trans("prop.appid")), + participants: jsonValueExposingStateControl("participants"), + }; + return new ContainerCompBuilder(childrenMap, (props, dispatch) => { + const isTopBom = ["top", "bottom"].includes(props.placement); + const { items, ...otherContainerProps } = props.container; + const userViewMode = useUserViewMode(); + const resizable = !userViewMode && (!isTopBom || !props.autoHeight); + const onResizeStop = useCallback( + ( + e: React.SyntheticEvent, + node: HTMLElement, + size: { width: number; height: number }, + handle: ResizeHandle + ) => { + isTopBom + ? dispatch(changeChildAction("height", size.height, true)) + : dispatch(changeChildAction("width", size.width, true)); + }, + [dispatch, isTopBom] + ); + + const usersWithVideoTracks: any = {}; + + useEffect(() => { + console.log("nnnn ", props.participants); + }, [props.participants.value]); + + useEffect(() => { + if (client) { + console.log("REGISTERING LISTNERS"); + + client.on( + "user-published", + async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + if (mediaType === "video") { + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play("remote-video"); + } + if (mediaType === "audio") { + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play(); + } + const remoteVideoTrack = user.videoTrack; + if (remoteVideoTrack) { + props.participants.onChange([JSON.stringify(user.uid)]); + console.log("usersWithVideoTracks", props.participants); + } + } + ); + + client.on("user-joined", (user: IAgoraRTCRemoteUser) => { + // usersWithVideoTracks[user.uid] = { user, videoTracks: [] }; + // props.participants.onChange(usersWithVideoTracks); + // console.log( + // "userJoined", + // user.uid, + // props.participants.value, + // usersWithVideoTracks + // ); + // const uid = user.uid; + // usersWithVideoTracks[uid] = { user, videoTracks: [] }; + }); + client.on("user-offline", (uid: any, reason: any) => { + console.log(`User ${uid} left the channel.`); + }); + client.on("user-published", (user, mediaType) => { + console.log(`User ${user.uid} published ${user.videoTrack} stream.`); + }); + client.on("stream-removed", (user: IAgoraRTCRemoteUser) => { + console.log(`Stream from user ${user.uid} removed.`); + }); + client.on("stream-added", (user: IAgoraRTCRemoteUser) => { + console.log("stream-added"); + + if (user.hasVideo) { + console.log(`Stream from user ${user.videoTrack} added.`); + } + }); + } + // turnOnCamera(true); + }, [client]); + + return ( + + + + document.querySelector(`#${CanvasContainerID}`) || document.body + } + footer={null} + width={transToPxSize(props.width || DEFAULT_SIZE)} + height={ + !props.autoHeight + ? transToPxSize(props.height || DEFAULT_SIZE) + : "" + } + onClose={(e) => { + props.visible.onChange(false); + }} + afterOpenChange={(visible) => { + if (!visible) { + props.onEvent("close"); + } + }} + zIndex={Layers.drawer} + maskClosable={props.maskClosable} + mask={props.showMask} + > + { + props.visible.onChange(false); + }} + > + + + + + + + ); + }) + .setPropertyViewFn((children) => ( + <> +
+ {children.appId.propertyView({ label: trans("prop.appid") })} + {children.placement.propertyView({ + label: trans("drawer.placement"), + radioButton: true, + })} + {["top", "bottom"].includes(children.placement.getView()) + ? children.autoHeight.getPropertyView() + : children.width.propertyView({ + label: trans("drawer.width"), + tooltip: trans("drawer.widthTooltip"), + placeholder: DEFAULT_SIZE + "", + })} + {!children.autoHeight.getView() && + ["top", "bottom"].includes(children.placement.getView()) && + children.height.propertyView({ + label: trans("drawer.height"), + tooltip: trans("drawer.heightTooltip"), + placeholder: DEFAULT_SIZE + "", + })} + {children.maskClosable.propertyView({ + label: trans("prop.maskClosable"), + })} + {children.showMask.propertyView({ + label: trans("prop.showMask"), + })} +
+
+ {children.onEvent.getPropertyView()} +
+
+ {children.style.getPropertyView()} +
+ + )) + .build(); +})(); + +MTComp = class extends MTComp { + override autoHeight(): boolean { + return false; + } +}; + +MTComp = withMethodExposing(MTComp, [ + { + method: { + name: "openDrawer", + description: trans("drawer.openDrawerDesc"), + params: [], + }, + execute: (comp, values) => { + comp.children.visible.getView().onChange(true); + }, + }, + { + method: { + name: "audioControl", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: (comp, values) => { + let value = !comp.children.audioControl.getView().value; + turnOnMicrophone(value); + comp.children.audioControl.change(value); + }, + }, + { + method: { + name: "videoControl", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: (comp, values) => { + let value = !comp.children.videoControl.getView().value; + turnOnCamera(value); + comp.children.videoControl.change(value); + }, + }, + { + method: { + name: "startMeeting", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: async (comp, values) => { + await publishVideo( + comp.children.appId.getView(), + "testsdaadasdsa", + comp.children + ); + }, + }, + { + method: { + name: "endCall", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: async (comp, values) => { + let value = !comp.children.endCall.getView().value; + await leaveChannel(); + comp.children.endCall.change(value); + }, + }, + { + method: { + name: "closeDrawer", + description: trans("drawer.closeDrawerDesc"), + params: [], + }, + execute: (comp, values) => { + comp.children.visible.getView().onChange(false); + }, + }, +]); + +export const VideoCOntrollerComp = withExposingConfigs(MTComp, [ + new NameConfig("visible", trans("export.visibleDesc")), + new NameConfig("appId", trans("prop.appid")), + new NameConfig("participants", trans("prop.participants")), +]); diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index 16668379d..e48516ac3 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -5,7 +5,10 @@ import { ModalComp } from "comps/hooks/modalComp"; import { ButtonComp } from "./comps/buttonComp/buttonComp"; import { DropdownComp } from "./comps/buttonComp/dropdownComp"; import { LinkComp } from "./comps/buttonComp/linkComp"; -import { ContainerComp, defaultContainerData } from "./comps/containerComp/containerComp"; +import { + ContainerComp, + defaultContainerData, +} from "./comps/containerComp/containerComp"; import { CustomComp } from "./comps/customComp/customComp"; import { DatePickerComp, DateRangeComp } from "./comps/dateComp/dateComp"; import { DividerComp } from "./comps/dividerComp"; @@ -101,7 +104,12 @@ import { import { defaultFormData, FormComp } from "./comps/formComp/formComp"; import { IFrameComp } from "./comps/iframeComp"; -import { defaultGridData, defaultListViewData, GridComp, ListViewComp } from "./comps/listViewComp"; +import { + defaultGridData, + defaultListViewData, + GridComp, + ListViewComp, +} from "./comps/listViewComp"; import { ModuleComp } from "./comps/moduleComp/moduleComp"; import { NavComp } from "./comps/navComp/navComp"; import { TableComp } from "./comps/tableComp"; @@ -124,10 +132,13 @@ import { ScannerComp } from "./comps/buttonComp/scannerComp"; import { SignatureComp } from "./comps/signatureComp"; import { TimeLineComp } from "./comps/timelineComp/timelineComp"; import { MentionComp } from "./comps/textInputComp/mentionComp"; -import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp" +import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp"; //Added by Aqib Mirza import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp"; import { ResponsiveLayoutComp } from "./comps/responsiveLayout"; +import { VideoMeetingComp } from "./comps/videoComp/videoMeetingComp"; +import { VideoControlButton } from "./comps/videoComp/videoControlButton"; +import { VideoCOntrollerComp } from "./hooks/videoControllerComp"; type Registry = { [key in UICompType]?: UICompManifest; @@ -373,7 +384,7 @@ const uiCompMap: Registry = { keywords: trans("uiComp.buttonCompKeywords"), comp: ButtonComp, layoutInfo: { - w: 3, + w: 2, h: 5, }, withoutLoading: true, @@ -546,6 +557,27 @@ const uiCompMap: Registry = { }, defaultDataFn: defaultContainerData, }, + + videocomponent: { + name: trans("meeting.videoCompName"), + enName: "Video", + description: trans("meeting.videoCompName"), + categories: ["meeting"], + icon: VideoCompIcon, + keywords: trans("meeting.meetingCompKeywords"), + comp: VideoMeetingComp, + withoutLoading: true, + }, + meetingcontrols: { + name: trans("meeting.meetingControlCompName"), + enName: "Controls", + description: trans("meeting.meetingCompDesc"), + categories: ["meeting"], + icon: ButtonCompIcon, + keywords: trans("meeting.meetingCompKeywords"), + comp: VideoControlButton, + withoutLoading: true, + }, tabbedContainer: { name: trans("uiComp.tabbedContainerCompName"), enName: "Tabbed Container", @@ -742,6 +774,16 @@ const uiCompMap: Registry = { comp: DrawerComp, withoutLoading: true, }, + meeting: { + name: trans("meeting.meetingCompName"), + enName: "Drawer", + description: trans("meeting.meetingCompDesc"), + categories: ["meeting"], + icon: DrawerCompIcon, + keywords: trans("meeting.meetingCompKeywords"), + comp: VideoCOntrollerComp, + withoutLoading: true, + }, carousel: { name: trans("uiComp.carouselCompName"), enName: "Carousel", @@ -876,12 +918,14 @@ const uiCompMap: Registry = { description: trans("uiComp.autoCompleteCompDesc"), categories: ["dataInputText"], icon: AutoCompleteCompIcon, - keywords: cnchar.spell(trans("uiComp.autoCompleteCompName"), "first", "low").toString(), + keywords: cnchar + .spell(trans("uiComp.autoCompleteCompName"), "first", "low") + .toString(), comp: AutoCompleteComp, layoutInfo: { w: 7, h: 5, - } + }, }, responsiveLayout: { name: trans("uiComp.responsiveLayoutCompName"), diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index 523409a01..1aa9778bb 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -5,7 +5,9 @@ import { JSONValue } from "util/jsonTypes"; import { EditorState } from "./editorState"; import { trans } from "i18n"; -export type ExposingMultiCompConstructor = ReturnType; +export type ExposingMultiCompConstructor = ReturnType< + typeof withExposingConfigs +>; // Required when the container generates default child comps type CompDefaultDataFunction = ( compName: string, @@ -22,6 +24,7 @@ export interface UICompLayoutInfo { export const uiCompCategoryNames = { common: trans("uiCompCategory.common"), + meeting: trans("uiCompCategory.meeting"), dataInputText: trans("uiCompCategory.dataInputText"), dataInputNumber: trans("uiCompCategory.dataInputNumber"), dataInputSelect: trans("uiCompCategory.dataInputSelect"), @@ -53,6 +56,9 @@ export type UICompType = | "moduleContainer" | "textArea" | "chart" + | "meeting" + | "videocomponent" + | "meetingcontrols" | "imageEditor" | "calendar" | "password" @@ -114,11 +120,14 @@ export type UICompType = | "timeline" | "mention" | "autocomplete" - | "responsiveLayout" + | "responsiveLayout"; export const uiCompRegistry = {} as Record; -export function registerComp(compType: UICompType | string, manifest: UICompManifest) { +export function registerComp( + compType: UICompType | string, + manifest: UICompManifest +) { uiCompRegistry[compType] = { ...manifest, keywords: [manifest.name, manifest.enName, manifest.keywords] diff --git a/client/packages/lowcoder/src/comps/utils/propertyUtils.tsx b/client/packages/lowcoder/src/comps/utils/propertyUtils.tsx index 3889982d3..76f458a68 100644 --- a/client/packages/lowcoder/src/comps/utils/propertyUtils.tsx +++ b/client/packages/lowcoder/src/comps/utils/propertyUtils.tsx @@ -30,6 +30,7 @@ export const placeholderPropertyView = (children: { placeholder: InstanceType; }) => children.placeholder.propertyView({ label: trans("prop.placeholder") }); + export const allowClearPropertyView = (children: { allowClear: InstanceType; }) => children.allowClear.propertyView({ label: trans("prop.showClear") }); diff --git a/client/packages/lowcoder/src/constants/Layers.ts b/client/packages/lowcoder/src/constants/Layers.ts index 04391ac4f..fcd2a361b 100644 --- a/client/packages/lowcoder/src/constants/Layers.ts +++ b/client/packages/lowcoder/src/constants/Layers.ts @@ -17,6 +17,7 @@ export const Layers = { modal: 950, // drawer: 950, + meeting: 950, tabBar: 800, // historySnapshotPanel: 555, diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index ddebe2166..67e118864 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -47,7 +47,8 @@ export const en = { api: { publishSuccess: "Published", recoverFailed: "Recover failed", - needUpdate: "Your current version is too old, please upgrade to the latest version.", + needUpdate: + "Your current version is too old, please upgrade to the latest version.", }, codeEditor: { notSupportAutoFormat: "Current code editor not supports auto formatting", @@ -64,16 +65,20 @@ export const en = { blur: "Remove focus", click: "Click", select: "Select all the text", - setSelectionRange: "Set the start and end positions of the current text selection", + setSelectionRange: + "Set the start and end positions of the current text selection", selectionStart: "The 0-based index of the first selected character.", - selectionEnd: "The 0-based index of the character after the last selected character.", + selectionEnd: + "The 0-based index of the character after the last selected character.", setRangeText: "Replace a range of text", replacement: "The string to insert.", replaceStart: "The 0-based index of the first character to replace.", - replaceEnd: "The 0-based index of the character after the last character to replace.", + replaceEnd: + "The 0-based index of the character after the last character to replace.", }, errorBoundary: { - encounterError: "Loading component failed. Please check your configuration. ", + encounterError: + "Loading component failed. Please check your configuration. ", clickToReload: "Click to reload", errorMsg: "Error: ", }, @@ -88,8 +93,10 @@ export const en = { noContainerSelected: "[bug] No selected container", deleteCompsSuccess: "Delete success. You can use {undoKey} to undo.", deleteCompsTitle: "Delete components", - deleteCompsBody: "Are you sure you want to delete {compNum} selected components?", - cutCompsSuccess: "Cut success. You can use {pasteKey} to paste, or use {undoKey} to undo.", + deleteCompsBody: + "Are you sure you want to delete {compNum} selected components?", + cutCompsSuccess: + "Cut success. You can use {pasteKey} to paste, or use {undoKey} to undo.", }, leftPanel: { queries: "Queries", @@ -135,6 +142,7 @@ export const en = { prop: { expand: "Expand", columns: "Columns", + videokey: "video key", rowSelection: "Row selection", toolbar: "Toolbar", pagination: "Pagination", @@ -149,6 +157,8 @@ export const en = { showClear: "Show clear button", showSearch: "Searchable", defaultValue: "Default value", + participants: "Participants", + appid: "Application Id", required: "Required field", readOnly: "Read only", readOnlyTooltip: @@ -234,10 +244,12 @@ export const en = { export: "Export data", exportNoFileType: "No select (optional)", fileName: "File name", - fileNameTooltip: "Support extension to specify the file type, like image.png.", + fileNameTooltip: + "Support extension to specify the file type, like image.png.", fileType: "File type", condition: "Only run when", - conditionTooltip: "Only run the event handler when this condition evaluates to 'true'", + conditionTooltip: + "Only run the event handler when this condition evaluates to 'true'", debounce: "Debounce", throttle: "Throttle", slowdownTooltip: @@ -275,7 +287,8 @@ export const en = { canvas: "Canvas color", canvasDesc: "The default background color of the app", primarySurface: "Container color", - primarySurfaceDesc: "The default background color for components such as tables", + primarySurfaceDesc: + "The default background color for components such as tables", borderRadius: "Border radius", borderRadiusDesc: "Most components use the default border radius", chart: "Chart style", @@ -286,14 +299,16 @@ export const en = { padding: "Padding", paddingDesc: "The default padding is typically used for most components", containerheaderpadding: "Header Padding", - containerheaderpaddingDesc: "The default headerpadding is typically used for most components", + containerheaderpaddingDesc: + "The default headerpadding is typically used for most components", //Added By Aqib Mirza gridColumns: "Grid Columns", gridColumnsDesc: "The default number of columns is typically used for most containers", }, style: { - resetTooltip: "Reset styles. Delete the input's value to reset an individual field.", + resetTooltip: + "Reset styles. Delete the input's value to reset an individual field.", contrastText: "Contrast text color", generated: "Generated", customize: "Customize", @@ -346,7 +361,8 @@ export const en = { }, export: { hiddenDesc: "If true, the component is hidden", - disabledDesc: "If true, the component will be greyed out and non-interactive", + disabledDesc: + "If true, the component will be greyed out and non-interactive", visibleDesc: "If true, the component is visible", inputValueDesc: "Current value of the input", invalidDesc: "Whether the value is invalid", @@ -365,22 +381,32 @@ export const en = { ratingValueDesc: "The currently selected score", ratingMaxDesc: "The maximum score currently set", datePickerValueDesc: "Currently selected date", - datePickerFormattedValueDesc: "Formatted selected date according to the specified format", + datePickerFormattedValueDesc: + "Formatted selected date according to the specified format", datePickerTimestampDesc: "The currently selected timestamp of the date (s)", dateRangeStartDesc: "Currently selected start date", dateRangeEndDesc: "Currently selected end date", - dateRangeStartTimestampDesc: "The currently selected timestamp of the start date (s)", - dateRangeEndTimestampDesc: "The currently selected timestamp of the end date (s)", - dateRangeFormattedValueDesc: "Formatted selected date according to the specified format", - dateRangeFormattedStartValueDesc: "Formatted start date according to the specified format", - dateRangeFormattedEndValueDesc: "Formatted end date according to the specified format", + dateRangeStartTimestampDesc: + "The currently selected timestamp of the start date (s)", + dateRangeEndTimestampDesc: + "The currently selected timestamp of the end date (s)", + dateRangeFormattedValueDesc: + "Formatted selected date according to the specified format", + dateRangeFormattedStartValueDesc: + "Formatted start date according to the specified format", + dateRangeFormattedEndValueDesc: + "Formatted end date according to the specified format", timePickerValueDesc: "Currently selected time", - timePickerFormattedValueDesc: "Formatted selected time according to the specified format", + timePickerFormattedValueDesc: + "Formatted selected time according to the specified format", timeRangeStartDesc: "Currently selected start time", timeRangeEndDesc: "Currently selected end time", - timeRangeFormattedValueDesc: "Formatted selected time according to the specified format", - timeRangeFormattedStartValueDesc: "Formatted start time according to the specified format", - timeRangeFormattedEndValueDesc: "Formatted end time according to the specified format", + timeRangeFormattedValueDesc: + "Formatted selected time according to the specified format", + timeRangeFormattedStartValueDesc: + "Formatted start time according to the specified format", + timeRangeFormattedEndValueDesc: + "Formatted end time according to the specified format", }, validationDesc: { email: "Please enter a valid email address", @@ -392,10 +418,14 @@ export const en = { "Insufficient number of characters, current length {length}, minimum length {minLength}", maxValue: "Greater than the maximum, current {value}, maximum {max}", minValue: "Less than the minimum, current {value}, minimum {min}", - maxTime: "Greater than the maximum time, current time {time}, the maximum time {maxTime}", - minTime: "Less than the minimum time, current time {time}, the minimum time {minTime}", - maxDate: "Greater than maximum date, current time {date}, maximum date {maxDate}", - minDate: "Less than minimum date, current time {date}, minimum date {minDate}", + maxTime: + "Greater than the maximum time, current time {time}, the maximum time {maxTime}", + minTime: + "Less than the minimum time, current time {time}, the minimum time {minTime}", + maxDate: + "Greater than maximum date, current time {date}, maximum date {maxDate}", + minDate: + "Less than minimum date, current time {date}, minimum date {minDate}", }, query: { noQueries: "No queries available. ", @@ -407,7 +437,8 @@ export const en = { advancedTab: "Advanced", showFailNotification: "Show notification on failure", failCondition: "Failure conditions", - failConditionTooltip1: "Customizes failure condition and corresponding notification.", + failConditionTooltip1: + "Customizes failure condition and corresponding notification.", failConditionTooltip2: "If any condition returns true, the query will be marked as failure and triggers corresponding notification.", showSuccessNotification: "Show notification on success", @@ -477,7 +508,8 @@ export const en = { execSuccess: "run success", execFail: "run failed", execIgnored: "The results of this query was ignored.", - deleteSuccessMessage: "Successfully deleted. You can use {undoKey} to undo.", + deleteSuccessMessage: + "Successfully deleted. You can use {undoKey} to undo.", dataExportDesc: "Data obtained by the current query", codeExportDesc: "Current query status code", successExportDesc: "Whether the current query was executed successfully", @@ -522,7 +554,8 @@ export const en = { sslCertVerificationTypeDisabled: "Disabled", selfSignedCert: "Self-signed Cert", selfSignedCertRequireMsg: "Please enter your Certificate", - enableTurnOffPreparedStatement: "Enable toggling prepared statements for queries", + enableTurnOffPreparedStatement: + "Enable toggling prepared statements for queries", enableTurnOffPreparedStatementTooltip: "You can enable or disable prepared statements in query Advanced tab", serviceName: "Service name", @@ -610,11 +643,13 @@ export const en = { publish: "Publish", historyVersion: "History version", deleteQueryLabel: "Delete query", - deleteQueryContent: "The query can't be recovered after being deleted. Delete the query?", + deleteQueryContent: + "The query can't be recovered after being deleted. Delete the query?", run: "Run", readOnly: "Read only", exit: "Exit", - recoverAppSnapshotContent: "Restore the current query to the version {version}", + recoverAppSnapshotContent: + "Restore the current query to the version {version}", searchPlaceholder: "Search query", allQuery: "All queries", deleteQueryTitle: "Delete query", @@ -648,8 +683,10 @@ export const en = { }, smtpQuery: { attachment: "Attachment", - attachmentTooltip: "Can use with file upload component, need convert data to: ", - MIMETypeUrl: "https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types", + attachmentTooltip: + "Can use with file upload component, need convert data to: ", + MIMETypeUrl: + "https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types", sender: "Sender", recipient: "Recipient", carbonCopy: "Carbon copy", @@ -660,6 +697,7 @@ export const en = { }, uiCompCategory: { common: "Commonly used", + meeting: "Meeting Settings", dataInputText: "Text inputs", dataInputNumber: "Number inputs", dataInputSelect: "Select inputs", @@ -863,13 +901,16 @@ export const en = { menuViewDocs: "View documentation", menuUpgradeToLatest: "Upgrade to latest version", nameNotEmpty: "Can not be empty", - nameRegex: "Must start with a letter and contain only letters, digits, and underscores (_)", + nameRegex: + "Must start with a letter and contain only letters, digits, and underscores (_)", nameJSKeyword: "Can not be a Javascript keyword", nameGlobalVariable: "Can not be global variable name", nameExists: "Name {name} already exist", - getLatestVersionMetaError: "Failed to fetch latest version, please try later.", + getLatestVersionMetaError: + "Failed to fetch latest version, please try later.", needNotUpgrade: "Current version is already latest.", - compNotFoundInLatestVersion: "Current component not found in the latest version.", + compNotFoundInLatestVersion: + "Current component not found in the latest version.", upgradeSuccess: "Successfully upgraded to latest version.", searchProp: "Search", }, @@ -990,9 +1031,11 @@ export const en = { radio: { options: "Options", horizontal: "Horizontal", - horizontalTooltip: "The horizontal layout wraps itself when it runs out of space", + horizontalTooltip: + "The horizontal layout wraps itself when it runs out of space", vertical: "Vertical", - verticalTooltip: "The vertical layout will always be displayed in a single column", + verticalTooltip: + "The vertical layout will always be displayed in a single column", autoColumns: "Auto column", autoColumnsTooltip: "The auto column layout automatically rearranges the order as space permits and displays as multiple columns", @@ -1002,11 +1045,13 @@ export const en = { }, selectInput: { valueDesc: "Currently selected value", - selectedIndexDesc: "The index of the currently selected value, or -1 if no value is selected", + selectedIndexDesc: + "The index of the currently selected value, or -1 if no value is selected", selectedLabelDesc: "The label of the currently selected value", }, file: { - typeErrorMsg: "Must be a number with a valid file size unit, or a unitless number of bytes.", + typeErrorMsg: + "Must be a number with a valid file size unit, or a unitless number of bytes.", fileEmptyErrorMsg: "upload failed. The file size is empty.", fileSizeExceedErrorMsg: "upload failed. The file size exceeds the limit.", minSize: "Min size", @@ -1025,7 +1070,8 @@ export const en = { uploadType: "Upload type", showUploadList: "Show upload list", maxFiles: "Max files", - filesValueDesc: "The contents of the currently uploaded file are Base64 encoded", + filesValueDesc: + "The contents of the currently uploaded file are Base64 encoded", filesDesc: "List of the current uploaded files. For details, refer to", clearValueDesc: "Clear all files", parseFiles: "Parse files", @@ -1068,13 +1114,15 @@ export const en = { default: "Default", submit: "Submit", textDesc: "Text currently displayed on button", - loadingDesc: "Is the button in loading state? If true the current button is loading", + loadingDesc: + "Is the button in loading state? If true the current button is loading", formButtonEvent: "event", }, link: { link: "Link", textDesc: "Text currently displayed on link", - loadingDesc: "Is the link in loading state? If true the current link is loading", + loadingDesc: + "Is the link in loading state? If true the current link is loading", }, scanner: { text: "Click scan", @@ -1174,7 +1222,8 @@ export const en = { optionList: "Operation list", option1: "Operation 1", status: "Status", - statusTooltip: "Optional values: success, error, default, warning, processing", + statusTooltip: + "Optional values: success, error, default, warning, processing", primaryButton: "Primary", defaultButton: "Default", type: "Type", @@ -1186,7 +1235,8 @@ export const en = { small: "S", middle: "M", large: "L", - refreshButtonTooltip: "The current data changes, click to regenerate the column.", + refreshButtonTooltip: + "The current data changes, click to regenerate the column.", changeSetDesc: "An object representing changes to an editable table, only contains the changed cell. Rows go first and columns go second.", selectedRowDesc: @@ -1228,7 +1278,8 @@ export const en = { showValue: "Show Value", expandable: "Expandable", configExpandedView: "Configure expanded view", - toUpdateRowsDesc: "An array of objects for rows to be updated in editable tables.", + toUpdateRowsDesc: + "An array of objects for rows to be updated in editable tables.", empty: "Empty", falseValues: "Text when false", allColumn: "All", @@ -1276,7 +1327,8 @@ export const en = { M: "M (Medium)", Q: "Q (Quartile)", H: "H (High)", - maxLength: "The content is too long. Set the length to less than 2953 characters", + maxLength: + "The content is too long. Set the length to less than 2953 characters", }, jsonExplorer: { indent: "Indent", @@ -1335,8 +1387,10 @@ export const en = { media: { playDesc: "Begins playback of the media.", pauseDesc: "Pauses the media playback.", - loadDesc: "Resets the media to the beginning and restart selecting the media resource.", - seekTo: "Seek to the given number of seconds, or fraction if amount is between 0 and 1", + loadDesc: + "Resets the media to the beginning and restart selecting the media resource.", + seekTo: + "Seek to the given number of seconds, or fraction if amount is between 0 and 1", seekToAmount: "Number of seconds, or fraction if it is between 0 and 1", showPreview: "Show preview", }, @@ -1353,8 +1407,10 @@ export const en = { insertImage: "Insert an image or ", }, millisecondsControl: { - timeoutTypeError: "Please enter the correct timeout period, the current input is: {value}", - timeoutLessThanMinError: "Input must greater than {left}, the current input is: {value}", + timeoutTypeError: + "Please enter the correct timeout period, the current input is: {value}", + timeoutLessThanMinError: + "Input must greater than {left}, the current input is: {value}", }, selectionControl: { single: "Single", @@ -1379,6 +1435,31 @@ export const en = { width: "Drawer width", height: "Drawer height", }, + meeting: { + placement: "Drawer placement", + size: "Size", + top: "Top", + right: "Right", + bottom: "Bottom", + left: "Left", + widthTooltip: "Number or percentage, e.g. 520, 60%", + heightTooltip: "Number, e.g. 378", + openDrawerDesc: "Open Drawer", + closeDrawerDesc: "Close Drawer", + width: "Drawer width", + height: "Drawer height", + actionBtnDesc: "Action Button", + title: "Meeting title", + meetingCompName: "Meeting Controller", + videoCompName: "Video Stream", + meetingControlCompName: "Controls Buttons", + meetingCompDesc: "Meeting component", + meetingCompControls: "Meeting control", + meetingCompKeywords: "", + iconSize: "Icon Size", + userId: "userId", + roomId: "roomId", + }, settings: { title: "Settings", member: "Members", @@ -1404,7 +1485,8 @@ export const en = { newGroupPrefix: "New group ", allMembers: "All members", deleteModalTitle: "Delete this group", - deleteModalContent: "The deleted group cannot be restored. Are you sure to delete the group?", + deleteModalContent: + "The deleted group cannot be restored. Are you sure to delete the group?", addMember: "Add members", nameColumn: "User name", joinTimeColumn: "Joining time", @@ -1416,9 +1498,12 @@ export const en = { exitOrg: "Leave", exitOrgDesc: "Are you sure you want to leave this workspace.", moveOutOrg: "Remove", - moveOutOrgDescSaasMode: "Are you sure you want to remove user {name} from this workspace?", - moveOutOrgDesc: "Are you sure you want to remove user {name}? This action cannot be recovered.", - devGroupTip: "Members of the developer group have privileges to create apps and data sources.", + moveOutOrgDescSaasMode: + "Are you sure you want to remove user {name} from this workspace?", + moveOutOrgDesc: + "Are you sure you want to remove user {name}? This action cannot be recovered.", + devGroupTip: + "Members of the developer group have privileges to create apps and data sources.", lastAdminQuit: "The last administrator cannot exit.", organizationNotExist: "The current workspace does not exist", inviteUserHelp: "You can copy the invitation link to send to the user", @@ -1431,7 +1516,8 @@ export const en = { manageBtn: "Manage", userDetail: "Detail", syncDeleteTip: "This group has been deleted from the address book source", - syncGroupTip: "This group is an address book synchronization group and cannot be edited", + syncGroupTip: + "This group is an address book synchronization group and cannot be edited", }, orgSettings: { newOrg: "New workspace", @@ -1442,7 +1528,8 @@ export const en = { "You are about to delete this workspace {permanentlyDelete}. Once deleted, the workspace {notRestored}.", permanentlyDelete: "permanently", notRestored: "cannot be restored", - deleteModalLabel: "Please enter workspace name{name}to confirm the operation:", + deleteModalLabel: + "Please enter workspace name{name}to confirm the operation:", deleteModalTip: "Please enter workspace name", deleteModalErr: "Workspace name is incorrect", deleteModalBtn: "Delete", @@ -1488,9 +1575,12 @@ export const en = { noTableSelected: "No table selected", noColumn: "No column", noColumnSelected: "No column selected", - noDataSourceFound: "No supported data source found. Create a new data source", - noTableFound: "No tables were found in this data source, please select another data source", - noColumnFound: "No supported column was found in this table. Please select another table", + noDataSourceFound: + "No supported data source found. Create a new data source", + noTableFound: + "No tables were found in this data source, please select another data source", + noColumnFound: + "No supported column was found in this table. Please select another table", formTitle: "Form title", name: "Name", nameTooltip: @@ -1522,9 +1612,11 @@ export const en = { "Number of rows in the list - This is usually set to a variable (for example, '{{query1.data.length}}') if you need to present the results of a query.", noOfColumns: "Column count", itemIndexName: "Item index name", - itemIndexNameDesc: "the variable name refer to the item's index, default as {default}", + itemIndexNameDesc: + "the variable name refer to the item's index, default as {default}", itemDataName: "Item data name", - itemDataNameDesc: "the variable name refer to the item's data object, default as {default}", + itemDataNameDesc: + "the variable name refer to the item's data object, default as {default}", itemsDesc: "Exposing data of Comps in list", dataDesc: "The raw data used in the current list", dataTooltip: @@ -1594,19 +1686,23 @@ export const en = { }, temporaryState: { value: "Init value", - valueTooltip: "The initial Value stored in the temporary state can be any valid JSON Value.", + valueTooltip: + "The initial Value stored in the temporary state can be any valid JSON Value.", docLink: "About temporary state", pathTypeError: "Path must be either a string or an array of values", unStructuredError: "Unstructured data {prev} can't be updated by {path}", valueDesc: "Temporary state value", - deleteMessage: "The temporary state is deleted successfully. You can use {undoKey} to undo.", + deleteMessage: + "The temporary state is deleted successfully. You can use {undoKey} to undo.", }, dataResponder: { data: "Data", dataDesc: "Data of current data responder", - dataTooltip: "When this data is changed, it will trigger subsequent actions.", + dataTooltip: + "When this data is changed, it will trigger subsequent actions.", docLink: "About the Data responder", - deleteMessage: "The data responder is deleted successfully. You can use {undoKey} to undo.", + deleteMessage: + "The data responder is deleted successfully. You can use {undoKey} to undo.", }, theme: { title: "Themes", @@ -1644,7 +1740,8 @@ export const en = { defaultTheme: "Default", yellow: "Yellow", green: "Green", - previewTitle: "Theme preview\nExample components that use your theme colors", + previewTitle: + "Theme preview\nExample components that use your theme colors", dateColumn: "Date", emailColumn: "Email", phoneColumn: "Phone", @@ -1682,7 +1779,8 @@ export const en = { pluginSetting: { title: "Plugins", npmPluginTitle: "npm plugins", - npmPluginDesc: "Set up npm plugins for all applications in the current workspace.", + npmPluginDesc: + "Set up npm plugins for all applications in the current workspace.", npmPluginEmpty: "No npm plugins were added.", npmPluginAddButton: "Add a npm plugin", saveSuccess: "Saved successfully", @@ -1695,9 +1793,11 @@ export const en = { defaultHomePlaceholder: "Select the default homepage", saveBtn: "Save", preloadJSTitle: "Preload JavaScript", - preloadJSHelp: "Set up preloaded JavaScript code for all apps in the current workspace.", + preloadJSHelp: + "Set up preloaded JavaScript code for all apps in the current workspace.", preloadCSSTitle: "Preload CSS", - preloadCSSHelp: " Set up preloaded CSS code for all apps in the current workspace.", + preloadCSSHelp: + " Set up preloaded CSS code for all apps in the current workspace.", preloadCSSApply: "Apply to the homepage of the workspace", preloadLibsTitle: "JavaScript library", preloadLibsHelp: @@ -1739,7 +1839,8 @@ export const en = { }, module: { emptyText: "No data", - circularReference: "Circular reference, current module/application cannot be used!", + circularReference: + "Circular reference, current module/application cannot be used!", emptyTestInput: "The current module has no input to test", emptyTestMethod: "The current module has no method to test", name: "Name", @@ -1762,7 +1863,8 @@ export const en = { output: "Output", nameExists: "Name {name} already exist", eventTriggered: "Event {name} is triggered", - globalPromptWhenEventTriggered: "Displays a global prompt when an event is triggered", + globalPromptWhenEventTriggered: + "Displays a global prompt when an event is triggered", emptyEventTest: "The current module has no events to test", emptyEvent: "No event has been added", event: "Event", @@ -1898,7 +2000,8 @@ export const en = { videoText: "Overview", onBtnText: "OK", // eslint-disable-next-line only-ascii/only-ascii - permissionDenyTitle: "💡 Unable to create a new application or data source?", + permissionDenyTitle: + "💡 Unable to create a new application or data source?", permissionDenyContent: "You don't have permission to create the application and data source. Please contact the administrator to join the developer group.", appName: "Tutorial application", @@ -1914,7 +2017,8 @@ export const en = { nameCheckMessage: "The name cannot be empty", viewOnly: "View only", recoverAppSnapshotTitle: "Restore this version?", - recoverAppSnapshotContent: "Restore current app to the version created at {time}.", + recoverAppSnapshotContent: + "Restore current app to the version created at {time}.", recoverAppSnapshotMessage: "Restore this version", returnEdit: "Return to editor", deploy: "Publish", @@ -1958,7 +2062,8 @@ export const en = { resetPasswordDesc: "Reset user {name}'s password. A new password will be generated after reset.", resetSuccess: "Reset succeeded", - resetSuccessDesc: "Password reset succeeded. The new password is: {password}", + resetSuccessDesc: + "Password reset succeeded. The new password is: {password}", copyPassword: "Copy password", }, preLoad: { @@ -2051,7 +2156,8 @@ export const en = { resCardSubTitle: "{time} by {creator}", trashEmpty: "Trash is empty.", projectEmpty: "Nothing here.", - projectEmptyCanAdd: "You don't have any apps yet. Click New to get started.", + projectEmptyCanAdd: + "You don't have any apps yet. Click New to get started.", name: "Name", type: "Type", creator: "Created by", @@ -2063,7 +2169,8 @@ export const en = { nameCheckMessage: "The name cannot be empty", deleteElementTitle: "Delete permanently", moveToTrashSubTitle: "{type} {name} will be moved to trash.", - deleteElementSubTitle: "Delete {type} {name} permanently, it cannot be recovered.", + deleteElementSubTitle: + "Delete {type} {name} permanently, it cannot be recovered.", deleteSuccessMsg: "Deleted successfully", deleteErrorMsg: "Deleted error", recoverSuccessMsg: "Recovered successfully", @@ -2136,12 +2243,15 @@ export const en = { aboutUs: "", changeLog: "", introVideo: "", - devNpmPlugin: "https://docs.lowcoder.cloud/lowcoder-extension/develop-data-source-plugins", + devNpmPlugin: + "https://docs.lowcoder.cloud/lowcoder-extension/develop-data-source-plugins", devNpmPluginText: "How to develop npm plugin", - useHost: "https://docs.lowcoder.cloud/setup-and-run/self-hosting/access-local-database-or-api", + useHost: + "https://docs.lowcoder.cloud/setup-and-run/self-hosting/access-local-database-or-api", eventHandlerSlowdown: "https://docs.lowcoder.cloud/build-applications/app-interaction/event-handlers", - thirdLib: "https://docs.lowcoder.cloud/lowcoder-extension/use-third-party-libraries-in-apps", + thirdLib: + "https://docs.lowcoder.cloud/lowcoder-extension/use-third-party-libraries-in-apps", thirdLibUrlText: "Use third-party libraries", }, datasourceTutorial: { @@ -2155,8 +2265,10 @@ export const en = { }, queryTutorial: { js: "", - transformer: "https://docs.lowcoder.cloud/business-logic-in-apps/write-javascript/transformers", - tempState: "https://docs.lowcoder.cloud/business-logic-in-apps/write-javascript/temporary-state", + transformer: + "https://docs.lowcoder.cloud/business-logic-in-apps/write-javascript/transformers", + tempState: + "https://docs.lowcoder.cloud/business-logic-in-apps/write-javascript/temporary-state", }, customComponent: { entryUrl: "https://sdk.lowcoder.cloud/custom_component.html", @@ -2226,7 +2338,8 @@ export const en = { defaultStartDateValue: "Default Start Date", defaultEndDateValue: "Default End Date", basicUsage: "Basic Usage", - basicDemoDescription: "The following examples show the basic usage of the component.", + basicDemoDescription: + "The following examples show the basic usage of the component.", noDefaultValue: "No Default Value", forbid: "Forbidden", placeholder: "Placeholder", @@ -2298,7 +2411,8 @@ export const en = { styleColor: "Font color", selectionMode: "Row selection mode", paginationSetting: "Pagination setting", - paginationShowSizeChanger: "Support users to modify the number of entries per page", + paginationShowSizeChanger: + "Support users to modify the number of entries per page", paginationShowSizeChangerButton: "Show size changer button", paginationShowQuickJumper: "Show quick jumper", paginationHideOnSinglePage: "Hide when there is only one page", @@ -2432,7 +2546,8 @@ export const en = { disableContent: "Disabling this ID provider may result in some users being unable to log in. Are you sure to proceed?", manualTip: "", - lockTip: "The content is locked. To make changes, please click the{icon}to unlock.", + lockTip: + "The content is locked. To make changes, please click the{icon}to unlock.", lockModalContent: "Changing the 'ID attribute' field can have significant impacts on user identification. Please confirm that you understand the implications of this change before proceeding.", payUserTag: "Premium", @@ -2450,7 +2565,7 @@ export const en = { animationStart: "Animation Start", valueDesc: "Current json Data", loop: "Loop", - auto: 'auto', + auto: "auto", onHover: "On hover", singlePlay: "Single Play", endlessLoop: "Endless Loop", @@ -2466,7 +2581,8 @@ export const en = { left: "Left", right: "Right", alternate: "alternate", - modeTooltip: "Set the content to appear left/right or alternately on both sides of the timeline", + modeTooltip: + "Set the content to appear left/right or alternately on both sides of the timeline", reverse: "reverse", pending: "pending", defaultPending: "continuous improvement", @@ -2485,7 +2601,7 @@ export const en = { clickedObjectDesc: "clicked item data", clickedIndexDesc: "clicked item index", }, - mention:{ + mention: { mentionList: "mention list", }, autoComplete: { @@ -2501,13 +2617,13 @@ export const en = { type: "type", antDesign: "AntDesign", normal: "Normal", - selectKey: 'key', - selectLable: 'label', - ComponentType: 'Component Type', - colorIcon: 'blue', - grewIcon: 'grew', - noneIcon: 'none', - small: 'small', + selectKey: "key", + selectLable: "label", + ComponentType: "Component Type", + colorIcon: "blue", + grewIcon: "grew", + noneIcon: "none", + small: "small", large: "large", componentSize: "component size", Introduction: "Introduction keys", diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index 345baf396..c70e599c8 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -6,6 +6,7 @@ import { LeftCheckbox, LeftCommon, LeftContainer, + LeftMeeting, LeftDate, LeftDivider, LeftDrawer, @@ -83,6 +84,9 @@ export const CompStateIcon: { form: , jsonSchemaForm: , container: , + meeting: , + videocomponent: , + meetingcontrols: , tabbedContainer: , modal: , listView: , @@ -106,7 +110,7 @@ export const CompStateIcon: { signature: , jsonLottie: , //Added By Aqib Mirza timeline: , - mention: , + mention: , autocomplete: , responsiveLayout: , }; From cf0fac6e64b41b1ef7c1789408e4811a52da51f5 Mon Sep 17 00:00:00 2001 From: FalkWolsky Date: Sat, 7 Oct 2023 18:50:53 +0200 Subject: [PATCH 10/43] Small fixes to make it running locally --- .../src/components/Meeting.tsx | 93 +++++++++ .../lowcoder-design/src/icons/index.ts | 2 + client/packages/lowcoder-design/src/index.ts | 3 +- .../comps/videoComp/videoMeetingComp.tsx | 4 +- client/yarn.lock | 187 ++++++++++++++++++ 5 files changed, 286 insertions(+), 3 deletions(-) create mode 100644 client/packages/lowcoder-design/src/components/Meeting.tsx diff --git a/client/packages/lowcoder-design/src/components/Meeting.tsx b/client/packages/lowcoder-design/src/components/Meeting.tsx new file mode 100644 index 000000000..a438f905b --- /dev/null +++ b/client/packages/lowcoder-design/src/components/Meeting.tsx @@ -0,0 +1,93 @@ +import { Drawer as AntdDrawer, DrawerProps as AntdDrawerProps } from "antd"; +import Handle from "./Modal/handler"; +import { useEffect, useMemo, useState } from "react"; +import { Resizable, ResizeHandle } from "react-resizable"; +import { useResizeDetector } from "react-resize-detector"; +import styled from "styled-components"; + +const StyledMeeting = styled(AntdDrawer)` + & .ant-drawer-content-wrapper { + transition-duration: 0s; + } +`; + +type Placement = "top" | "bottom" | "left" | "right"; +function getResizeHandle(placement?: Placement): ResizeHandle { + switch (placement) { + case "top": + return "s"; + case "bottom": + return "n"; + case "left": + return "e"; + } + return "w"; +} + +type MeetingProps = { + resizable?: boolean; + onResizeStart?: ( + e: React.SyntheticEvent, + node: HTMLElement, + size: { width: number; height: number }, + handle: ResizeHandle + ) => void; + onResize?: ( + e: React.SyntheticEvent, + node: HTMLElement, + size: { width: number; height: number }, + handle: ResizeHandle + ) => void; + onResizeStop?: ( + e: React.SyntheticEvent, + node: HTMLElement, + size: { width: number; height: number }, + handle: ResizeHandle + ) => void; +} & AntdDrawerProps; + +export function Meeting(props: MeetingProps) { + const { resizable, width: drawerWidth, height: drawerHeight, children, ...otherProps } = props; + const placement = useMemo(() => props.placement ?? "right", [props.placement]); + const resizeHandles = useMemo( + () => (resizable ? [getResizeHandle(placement)] : []), + [placement, resizable] + ); + const isTopBom = ["top", "bottom"].includes(placement); + const [width, setWidth] = useState(); + const [height, setHeight] = useState(); + useEffect(() => { + setWidth(undefined); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [drawerWidth]); + useEffect(() => { + setHeight(undefined); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [drawerHeight]); + const { width: detectWidth, height: detectHeight, ref } = useResizeDetector(); + // log.info("Drawer. drawerWidth: ", drawerWidth, " width: ", width, "detectWidth: ", detectWidth); + return ( + + + props.onResizeStart?.(event, node, size, handle) + } + onResize={(event, { node, size, handle }) => { + isTopBom ? setHeight(size.height) : setWidth(size.width); + props.onResize?.(event, node, size, handle); + }} + onResizeStop={(event, { node, size, handle }) => + props.onResizeStop?.(event, node, size, handle) + } + > +
+ {children} +
+
+
+ ); +} diff --git a/client/packages/lowcoder-design/src/icons/index.ts b/client/packages/lowcoder-design/src/icons/index.ts index 6c9c2eb2b..0ea5ed45d 100644 --- a/client/packages/lowcoder-design/src/icons/index.ts +++ b/client/packages/lowcoder-design/src/icons/index.ts @@ -168,6 +168,7 @@ export { ReactComponent as AudioCompIcon } from "./icon-insert-audio.svg"; export { ReactComponent as VideoCompIcon } from "./icon-insert-video.svg"; export { ReactComponent as videoPlayTriangle } from "./icon-video-play-triangle.svg"; export { ReactComponent as DrawerCompIcon } from "./icon-drawer.svg"; +export { ReactComponent as LeftMeetingIcon } from "./icon-left-comp-video.svg"; export { ReactComponent as PlusIcon } from "./icon-plus.svg"; export { ReactComponent as HomeIcon } from "./icon-application-home.svg"; export { ReactComponent as HomeModuleIcon } from "./icon-application-module.svg"; @@ -236,6 +237,7 @@ export { ReactComponent as LeftContainer } from "./icon-left-comp-container.svg" export { ReactComponent as LeftDate } from "./icon-left-comp-date.svg"; export { ReactComponent as LeftDivider } from "./icon-left-comp-divider.svg"; export { ReactComponent as LeftDrawer } from "./icon-left-comp-drawer.svg"; +export { ReactComponent as LeftMeeting } from "./icon-left-comp-video.svg"; export { ReactComponent as LeftFile } from "./icon-left-comp-file.svg"; export { ReactComponent as LeftFileViewer } from "./icon-left-comp-fileViewer.svg"; export { ReactComponent as LeftForm } from "./icon-left-comp-form.svg"; diff --git a/client/packages/lowcoder-design/src/index.ts b/client/packages/lowcoder-design/src/index.ts index a2a7ca495..133417f7c 100644 --- a/client/packages/lowcoder-design/src/index.ts +++ b/client/packages/lowcoder-design/src/index.ts @@ -1,6 +1,7 @@ export * from "./components/Collapase"; export * from "./components/CustomModal"; -export * from "./components/Drawer"; +export * from "./components/Drawer"; +export * from "./components/Meeting"; export * from "./components/Dropdown"; export * from "./components/ExternalLink"; export * from "./components/GlobalInstances"; diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx b/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx index 460bebd63..9892499d0 100644 --- a/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx @@ -216,7 +216,7 @@ let VideoCompBuilder = (function (props) { }) .setPropertyViewFn((children) => ( <> -
+ {/*
{children.userId.propertyView({ label: trans("meeting.userId"), })} @@ -224,7 +224,7 @@ let VideoCompBuilder = (function (props) { {children.videokey.propertyView({ label: trans("prop.videokey"), })} -
+
*/} {/*
{/* {hiddenPropertyView(children)}
*/} diff --git a/client/yarn.lock b/client/yarn.lock index 4748d1eaf..0d2810fcf 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -12,6 +12,40 @@ __metadata: languageName: node linkType: hard +"@agora-js/media@npm:^4.19.0": + version: 4.19.0 + resolution: "@agora-js/media@npm:4.19.0" + dependencies: + "@agora-js/report": ^4.19.0 + "@agora-js/shared": ^4.19.0 + agora-rte-extension: ^1.2.3 + axios: ^0.27.2 + pako: ^2.1.0 + webrtc-adapter: 8.2.0 + checksum: c72485d9350376e8168dfcc205c2d5e19ea00c041a49404c4829cc520ab9216a842011467d23b542cff649447699852cb48563c675b2883c3a1ac3e68d27d78b + languageName: node + linkType: hard + +"@agora-js/report@npm:^4.19.0": + version: 4.19.0 + resolution: "@agora-js/report@npm:4.19.0" + dependencies: + "@agora-js/shared": ^4.19.0 + axios: ^0.27.2 + checksum: 2624fcad0aecb89ad38a420e7135bbeeb33c46c4e56797211a54b01c32fcf4b4add818bbf5af9497e27bdb0cc62eb95fe607c53071b21c03a2b2345cb37adb80 + languageName: node + linkType: hard + +"@agora-js/shared@npm:^4.19.0": + version: 4.19.0 + resolution: "@agora-js/shared@npm:4.19.0" + dependencies: + axios: ^0.27.2 + ua-parser-js: ^0.7.34 + checksum: 215164c8456a81c614809cb351b4ea31ed939324d99ce3e80bedd1e7737488c1486dd65320641077473339c25cf5520e4406d47003ac6e5a88ee889270bae378 + languageName: node + linkType: hard + "@ampproject/remapping@npm:^2.2.0": version: 2.2.1 resolution: "@ampproject/remapping@npm:2.2.1" @@ -4700,6 +4734,39 @@ __metadata: languageName: node linkType: hard +"agora-access-token@npm:^2.0.4": + version: 2.0.4 + resolution: "agora-access-token@npm:2.0.4" + dependencies: + crc-32: 1.2.0 + cuint: 0.2.2 + checksum: 7d91fa01c4ba085f70b8bdac9d296f8a5d29d2dc5a1c5cd995d4fe7bfb557cc3c5223bb0417065e89c584c0dbfaa7ddfdb4b689b0b8fc2459e77ad9d4ff0d52a + languageName: node + linkType: hard + +"agora-rtc-sdk-ng@npm:^4.19.0": + version: 4.19.0 + resolution: "agora-rtc-sdk-ng@npm:4.19.0" + dependencies: + "@agora-js/media": ^4.19.0 + "@agora-js/report": ^4.19.0 + "@agora-js/shared": ^4.19.0 + agora-rte-extension: ^1.2.3 + axios: ^0.27.2 + formdata-polyfill: ^4.0.7 + ua-parser-js: ^0.7.34 + webrtc-adapter: 8.2.0 + checksum: 495d16957dd7c12f0032dcc0a27d3d918ed20e4c869ea828e611dbc0130708231e483859cd51d64a7527e71078a7c7ed28d7924fb0dfe0be9a169b915ec1280a + languageName: node + linkType: hard + +"agora-rte-extension@npm:^1.2.3": + version: 1.2.3 + resolution: "agora-rte-extension@npm:1.2.3" + checksum: 5b53a2f08720a17e7dac5dc35c3d4c539a5eabe9e20a4da2bf08c666072dc11e90cac6b92e2b1ccbd4516c70cf4934ddfe13d9863553e1e36949a7b138cde96a + languageName: node + linkType: hard + "ahooks-v3-count@npm:^1.0.0": version: 1.0.0 resolution: "ahooks-v3-count@npm:1.0.0" @@ -5288,6 +5355,16 @@ __metadata: languageName: node linkType: hard +"axios@npm:^0.27.2": + version: 0.27.2 + resolution: "axios@npm:0.27.2" + dependencies: + follow-redirects: ^1.14.9 + form-data: ^4.0.0 + checksum: 38cb7540465fe8c4102850c4368053c21683af85c5fdf0ea619f9628abbcb59415d1e22ebc8a6390d2bbc9b58a9806c874f139767389c862ec9b772235f06854 + languageName: node + linkType: hard + "axobject-query@npm:^3.1.1": version: 3.1.1 resolution: "axobject-query@npm:3.1.1" @@ -6420,6 +6497,18 @@ __metadata: languageName: node linkType: hard +"crc-32@npm:1.2.0": + version: 1.2.0 + resolution: "crc-32@npm:1.2.0" + dependencies: + exit-on-epipe: ~1.0.1 + printj: ~1.1.0 + bin: + crc32: ./bin/crc32.njs + checksum: 7bcde8bea262f6629ac3c70e20bdfa3d058dc77091705ce8620513f76f19b41fc273ddd65a716eef9b4e33fbb61ff7f9b266653d214319aef27e4223789c6b9e + languageName: node + linkType: hard + "crc-32@npm:~1.2.0, crc-32@npm:~1.2.1": version: 1.2.2 resolution: "crc-32@npm:1.2.2" @@ -6678,6 +6767,13 @@ __metadata: languageName: node linkType: hard +"cuint@npm:0.2.2": + version: 0.2.2 + resolution: "cuint@npm:0.2.2" + checksum: b8127a93a7f16ce120ffcb22108014327c9808b258ee20e7dbb4c6740d7cb0f0c12d18a054eb716b0f2470090666abaae8a082d3cd5ef0e94fa447dd155842c4 + languageName: node + linkType: hard + "cytoscape-cose-bilkent@npm:^4.1.0": version: 4.1.0 resolution: "cytoscape-cose-bilkent@npm:4.1.0" @@ -8424,6 +8520,13 @@ __metadata: languageName: node linkType: hard +"exit-on-epipe@npm:~1.0.1": + version: 1.0.1 + resolution: "exit-on-epipe@npm:1.0.1" + checksum: e8ab4940416d19f311b3c9226e3725c6c4c6026fe682266ecc0ff33a455d585fe3e4ee757857c7bf1d0491b478cb232b8e395dfb438e65ac87317eda47304c32 + languageName: node + linkType: hard + "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -8600,6 +8703,16 @@ __metadata: languageName: node linkType: hard +"fetch-blob@npm:^3.1.2": + version: 3.2.0 + resolution: "fetch-blob@npm:3.2.0" + dependencies: + node-domexception: ^1.0.0 + web-streams-polyfill: ^3.0.3 + checksum: f19bc28a2a0b9626e69fd7cf3a05798706db7f6c7548da657cbf5026a570945f5eeaedff52007ea35c8bcd3d237c58a20bf1543bc568ab2422411d762dd3d5bf + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -8700,6 +8813,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.14.9": + version: 1.15.3 + resolution: "follow-redirects@npm:1.15.3" + peerDependenciesMeta: + debug: + optional: true + checksum: 584da22ec5420c837bd096559ebfb8fe69d82512d5585004e36a3b4a6ef6d5905780e0c74508c7b72f907d1fa2b7bd339e613859e9c304d0dc96af2027fd0231 + languageName: node + linkType: hard + "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -8745,6 +8868,15 @@ __metadata: languageName: node linkType: hard +"formdata-polyfill@npm:^4.0.7": + version: 4.0.10 + resolution: "formdata-polyfill@npm:4.0.10" + dependencies: + fetch-blob: ^3.1.2 + checksum: 82a34df292afadd82b43d4a740ce387bc08541e0a534358425193017bf9fb3567875dc5f69564984b1da979979b70703aa73dee715a17b6c229752ae736dd9db + languageName: node + linkType: hard + "formstream@npm:^1.1.0": version: 1.2.0 resolution: "formstream@npm:1.2.0" @@ -11724,6 +11856,8 @@ __metadata: "@types/regenerator-runtime": ^0.13.1 "@types/uuid": ^8.3.4 "@vitejs/plugin-react": ^2.2.0 + agora-access-token: ^2.0.4 + agora-rtc-sdk-ng: ^4.19.0 ali-oss: ^6.17.1 antd: 5.7.2 antd-img-crop: ^4.12.2 @@ -12925,6 +13059,13 @@ __metadata: languageName: node linkType: hard +"node-domexception@npm:^1.0.0": + version: 1.0.0 + resolution: "node-domexception@npm:1.0.0" + checksum: ee1d37dd2a4eb26a8a92cd6b64dfc29caec72bff5e1ed9aba80c294f57a31ba4895a60fd48347cf17dd6e766da0ae87d75657dfd1f384ebfa60462c2283f5c7f + languageName: node + linkType: hard + "node-fetch@npm:^2.6.11": version: 2.6.11 resolution: "node-fetch@npm:2.6.11" @@ -13371,6 +13512,13 @@ __metadata: languageName: node linkType: hard +"pako@npm:^2.1.0": + version: 2.1.0 + resolution: "pako@npm:2.1.0" + checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e + languageName: node + linkType: hard + "papaparse@npm:^5.3.2": version: 5.4.1 resolution: "papaparse@npm:5.4.1" @@ -13693,6 +13841,15 @@ __metadata: languageName: node linkType: hard +"printj@npm:~1.1.0": + version: 1.1.2 + resolution: "printj@npm:1.1.2" + bin: + printj: ./bin/printj.njs + checksum: 1c0c66844545415e339356ad62009cdc467819817b1e0341aba428087a1414d46b84089edb4e77ef24705829f8aae6349724b9c7bd89d8690302b2de7a89b315 + languageName: node + linkType: hard + "process-es6@npm:^0.11.2, process-es6@npm:^0.11.6": version: 0.11.6 resolution: "process-es6@npm:0.11.6" @@ -16356,6 +16513,13 @@ __metadata: languageName: node linkType: hard +"sdp@npm:^3.0.2": + version: 3.2.0 + resolution: "sdp@npm:3.2.0" + checksum: 227885bddab9a5845e56ae184ff51e43ec7bc155e7f1ed2f17ca1b012e6767011d5bd01b6c4064ded8e3b6f6bf3c9b26b2cf754b9c8662285988ed27b54f37b1 + languageName: node + linkType: hard + "semver@npm:^5.0.1, semver@npm:^5.6.0": version: 5.7.1 resolution: "semver@npm:5.7.1" @@ -17799,6 +17963,13 @@ __metadata: languageName: node linkType: hard +"ua-parser-js@npm:^0.7.34": + version: 0.7.36 + resolution: "ua-parser-js@npm:0.7.36" + checksum: 04e18e7f6bf4964a10d74131ea9784c7f01d0c2d3b96f73340ac0a1f8e83d010b99fd7d425e7a2100fa40c58b72f6201408cbf4baa2df1103637f96fb59f2a30 + languageName: node + linkType: hard + "ua-parser-js@npm:^1.0.33": version: 1.0.35 resolution: "ua-parser-js@npm:1.0.35" @@ -18528,6 +18699,13 @@ __metadata: languageName: node linkType: hard +"web-streams-polyfill@npm:^3.0.3": + version: 3.2.1 + resolution: "web-streams-polyfill@npm:3.2.1" + checksum: b119c78574b6d65935e35098c2afdcd752b84268e18746606af149e3c424e15621b6f1ff0b42b2676dc012fc4f0d313f964b41a4b5031e525faa03997457da02 + languageName: node + linkType: hard + "web-vitals@npm:^2.1.0": version: 2.1.4 resolution: "web-vitals@npm:2.1.4" @@ -18563,6 +18741,15 @@ __metadata: languageName: node linkType: hard +"webrtc-adapter@npm:8.2.0": + version: 8.2.0 + resolution: "webrtc-adapter@npm:8.2.0" + dependencies: + sdp: ^3.0.2 + checksum: 67221eac0f01c35f32235b0b988ed27b7e850d03315050a4432f6dc2ff47b8e0535732dfbe5d9718f6a27d46eddc527ca1465e509ba628fdd4c968013fdacb86 + languageName: node + linkType: hard + "weixin-js-sdk@npm:^1.6.0": version: 1.6.0 resolution: "weixin-js-sdk@npm:1.6.0" From e799728977049b3988735a41849a1353bade6f3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 22:09:23 +0000 Subject: [PATCH 11/43] build(deps): bump postcss from 8.4.24 to 8.4.31 in /client Bumps [postcss](https://github.com/postcss/postcss) from 8.4.24 to 8.4.31. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.24...8.4.31) --- updated-dependencies: - dependency-name: postcss dependency-type: indirect ... Signed-off-by: dependabot[bot] --- client/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/yarn.lock b/client/yarn.lock index 4748d1eaf..37af902c2 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -13631,13 +13631,13 @@ __metadata: linkType: hard "postcss@npm:^8.4.23": - version: 8.4.24 - resolution: "postcss@npm:8.4.24" + version: 8.4.31 + resolution: "postcss@npm:8.4.31" dependencies: nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 814e2126dacfea313588eda09cc99a9b4c26ec55c059188aa7a916d20d26d483483106dc5ff9e560731b59f45c5bb91b945dfadc670aed875cc90ddbbf4e787d + checksum: 1d8611341b073143ad90486fcdfeab49edd243377b1f51834dc4f6d028e82ce5190e4f11bb2633276864503654fb7cab28e67abdc0fbf9d1f88cad4a0ff0beea languageName: node linkType: hard From 6ca3d4dc96401470f808ff5e6d0c329fcfe6e36d Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Mon, 9 Oct 2023 10:17:47 +0300 Subject: [PATCH 12/43] v --- .../src/components/meeting.tsx | 43 ++ node_modules/.bin/uuid | 1 + node_modules/.yarn-integrity | 16 + node_modules/uuid/CHANGELOG.md | 274 ++++++++++ node_modules/uuid/CONTRIBUTING.md | 18 + node_modules/uuid/LICENSE.md | 9 + node_modules/uuid/README.md | 466 ++++++++++++++++++ node_modules/uuid/dist/bin/uuid | 2 + .../uuid/dist/commonjs-browser/index.js | 79 +++ .../uuid/dist/commonjs-browser/md5.js | 223 +++++++++ .../uuid/dist/commonjs-browser/native.js | 11 + .../uuid/dist/commonjs-browser/nil.js | 8 + .../uuid/dist/commonjs-browser/parse.js | 45 ++ .../uuid/dist/commonjs-browser/regex.js | 8 + .../uuid/dist/commonjs-browser/rng.js | 25 + .../uuid/dist/commonjs-browser/sha1.js | 104 ++++ .../uuid/dist/commonjs-browser/stringify.js | 44 ++ node_modules/uuid/dist/commonjs-browser/v1.js | 107 ++++ node_modules/uuid/dist/commonjs-browser/v3.js | 16 + .../uuid/dist/commonjs-browser/v35.js | 80 +++ node_modules/uuid/dist/commonjs-browser/v4.js | 43 ++ node_modules/uuid/dist/commonjs-browser/v5.js | 16 + .../uuid/dist/commonjs-browser/validate.js | 17 + .../uuid/dist/commonjs-browser/version.js | 21 + node_modules/uuid/dist/esm-browser/index.js | 9 + node_modules/uuid/dist/esm-browser/md5.js | 215 ++++++++ node_modules/uuid/dist/esm-browser/native.js | 4 + node_modules/uuid/dist/esm-browser/nil.js | 1 + node_modules/uuid/dist/esm-browser/parse.js | 35 ++ node_modules/uuid/dist/esm-browser/regex.js | 1 + node_modules/uuid/dist/esm-browser/rng.js | 18 + node_modules/uuid/dist/esm-browser/sha1.js | 96 ++++ .../uuid/dist/esm-browser/stringify.js | 33 ++ node_modules/uuid/dist/esm-browser/v1.js | 95 ++++ node_modules/uuid/dist/esm-browser/v3.js | 4 + node_modules/uuid/dist/esm-browser/v35.js | 66 +++ node_modules/uuid/dist/esm-browser/v4.js | 29 ++ node_modules/uuid/dist/esm-browser/v5.js | 4 + .../uuid/dist/esm-browser/validate.js | 7 + node_modules/uuid/dist/esm-browser/version.js | 11 + node_modules/uuid/dist/esm-node/index.js | 9 + node_modules/uuid/dist/esm-node/md5.js | 13 + node_modules/uuid/dist/esm-node/native.js | 4 + node_modules/uuid/dist/esm-node/nil.js | 1 + node_modules/uuid/dist/esm-node/parse.js | 35 ++ node_modules/uuid/dist/esm-node/regex.js | 1 + node_modules/uuid/dist/esm-node/rng.js | 12 + node_modules/uuid/dist/esm-node/sha1.js | 13 + node_modules/uuid/dist/esm-node/stringify.js | 33 ++ node_modules/uuid/dist/esm-node/v1.js | 95 ++++ node_modules/uuid/dist/esm-node/v3.js | 4 + node_modules/uuid/dist/esm-node/v35.js | 66 +++ node_modules/uuid/dist/esm-node/v4.js | 29 ++ node_modules/uuid/dist/esm-node/v5.js | 4 + node_modules/uuid/dist/esm-node/validate.js | 7 + node_modules/uuid/dist/esm-node/version.js | 11 + node_modules/uuid/dist/index.js | 79 +++ node_modules/uuid/dist/md5-browser.js | 223 +++++++++ node_modules/uuid/dist/md5.js | 23 + node_modules/uuid/dist/native-browser.js | 11 + node_modules/uuid/dist/native.js | 15 + node_modules/uuid/dist/nil.js | 8 + node_modules/uuid/dist/parse.js | 45 ++ node_modules/uuid/dist/regex.js | 8 + node_modules/uuid/dist/rng-browser.js | 25 + node_modules/uuid/dist/rng.js | 24 + node_modules/uuid/dist/sha1-browser.js | 104 ++++ node_modules/uuid/dist/sha1.js | 23 + node_modules/uuid/dist/stringify.js | 44 ++ node_modules/uuid/dist/uuid-bin.js | 85 ++++ node_modules/uuid/dist/v1.js | 107 ++++ node_modules/uuid/dist/v3.js | 16 + node_modules/uuid/dist/v35.js | 80 +++ node_modules/uuid/dist/v4.js | 43 ++ node_modules/uuid/dist/v5.js | 16 + node_modules/uuid/dist/validate.js | 17 + node_modules/uuid/dist/version.js | 21 + node_modules/uuid/package.json | 135 +++++ node_modules/uuid/wrapper.mjs | 10 + package.json | 5 + yarn.lock | 8 + 81 files changed, 3816 insertions(+) create mode 100644 client/packages/lowcoder-design/src/components/meeting.tsx create mode 120000 node_modules/.bin/uuid create mode 100644 node_modules/.yarn-integrity create mode 100644 node_modules/uuid/CHANGELOG.md create mode 100644 node_modules/uuid/CONTRIBUTING.md create mode 100644 node_modules/uuid/LICENSE.md create mode 100644 node_modules/uuid/README.md create mode 100755 node_modules/uuid/dist/bin/uuid create mode 100644 node_modules/uuid/dist/commonjs-browser/index.js create mode 100644 node_modules/uuid/dist/commonjs-browser/md5.js create mode 100644 node_modules/uuid/dist/commonjs-browser/native.js create mode 100644 node_modules/uuid/dist/commonjs-browser/nil.js create mode 100644 node_modules/uuid/dist/commonjs-browser/parse.js create mode 100644 node_modules/uuid/dist/commonjs-browser/regex.js create mode 100644 node_modules/uuid/dist/commonjs-browser/rng.js create mode 100644 node_modules/uuid/dist/commonjs-browser/sha1.js create mode 100644 node_modules/uuid/dist/commonjs-browser/stringify.js create mode 100644 node_modules/uuid/dist/commonjs-browser/v1.js create mode 100644 node_modules/uuid/dist/commonjs-browser/v3.js create mode 100644 node_modules/uuid/dist/commonjs-browser/v35.js create mode 100644 node_modules/uuid/dist/commonjs-browser/v4.js create mode 100644 node_modules/uuid/dist/commonjs-browser/v5.js create mode 100644 node_modules/uuid/dist/commonjs-browser/validate.js create mode 100644 node_modules/uuid/dist/commonjs-browser/version.js create mode 100644 node_modules/uuid/dist/esm-browser/index.js create mode 100644 node_modules/uuid/dist/esm-browser/md5.js create mode 100644 node_modules/uuid/dist/esm-browser/native.js create mode 100644 node_modules/uuid/dist/esm-browser/nil.js create mode 100644 node_modules/uuid/dist/esm-browser/parse.js create mode 100644 node_modules/uuid/dist/esm-browser/regex.js create mode 100644 node_modules/uuid/dist/esm-browser/rng.js create mode 100644 node_modules/uuid/dist/esm-browser/sha1.js create mode 100644 node_modules/uuid/dist/esm-browser/stringify.js create mode 100644 node_modules/uuid/dist/esm-browser/v1.js create mode 100644 node_modules/uuid/dist/esm-browser/v3.js create mode 100644 node_modules/uuid/dist/esm-browser/v35.js create mode 100644 node_modules/uuid/dist/esm-browser/v4.js create mode 100644 node_modules/uuid/dist/esm-browser/v5.js create mode 100644 node_modules/uuid/dist/esm-browser/validate.js create mode 100644 node_modules/uuid/dist/esm-browser/version.js create mode 100644 node_modules/uuid/dist/esm-node/index.js create mode 100644 node_modules/uuid/dist/esm-node/md5.js create mode 100644 node_modules/uuid/dist/esm-node/native.js create mode 100644 node_modules/uuid/dist/esm-node/nil.js create mode 100644 node_modules/uuid/dist/esm-node/parse.js create mode 100644 node_modules/uuid/dist/esm-node/regex.js create mode 100644 node_modules/uuid/dist/esm-node/rng.js create mode 100644 node_modules/uuid/dist/esm-node/sha1.js create mode 100644 node_modules/uuid/dist/esm-node/stringify.js create mode 100644 node_modules/uuid/dist/esm-node/v1.js create mode 100644 node_modules/uuid/dist/esm-node/v3.js create mode 100644 node_modules/uuid/dist/esm-node/v35.js create mode 100644 node_modules/uuid/dist/esm-node/v4.js create mode 100644 node_modules/uuid/dist/esm-node/v5.js create mode 100644 node_modules/uuid/dist/esm-node/validate.js create mode 100644 node_modules/uuid/dist/esm-node/version.js create mode 100644 node_modules/uuid/dist/index.js create mode 100644 node_modules/uuid/dist/md5-browser.js create mode 100644 node_modules/uuid/dist/md5.js create mode 100644 node_modules/uuid/dist/native-browser.js create mode 100644 node_modules/uuid/dist/native.js create mode 100644 node_modules/uuid/dist/nil.js create mode 100644 node_modules/uuid/dist/parse.js create mode 100644 node_modules/uuid/dist/regex.js create mode 100644 node_modules/uuid/dist/rng-browser.js create mode 100644 node_modules/uuid/dist/rng.js create mode 100644 node_modules/uuid/dist/sha1-browser.js create mode 100644 node_modules/uuid/dist/sha1.js create mode 100644 node_modules/uuid/dist/stringify.js create mode 100644 node_modules/uuid/dist/uuid-bin.js create mode 100644 node_modules/uuid/dist/v1.js create mode 100644 node_modules/uuid/dist/v3.js create mode 100644 node_modules/uuid/dist/v35.js create mode 100644 node_modules/uuid/dist/v4.js create mode 100644 node_modules/uuid/dist/v5.js create mode 100644 node_modules/uuid/dist/validate.js create mode 100644 node_modules/uuid/dist/version.js create mode 100644 node_modules/uuid/package.json create mode 100644 node_modules/uuid/wrapper.mjs create mode 100644 package.json create mode 100644 yarn.lock diff --git a/client/packages/lowcoder-design/src/components/meeting.tsx b/client/packages/lowcoder-design/src/components/meeting.tsx new file mode 100644 index 000000000..829044cf1 --- /dev/null +++ b/client/packages/lowcoder-design/src/components/meeting.tsx @@ -0,0 +1,43 @@ +import { trans } from "i18n/design"; +import { ReactNode } from "react"; +import styled from "styled-components"; +import { ReactComponent as MeetingContainerDrag } from "icons/icon-left-comp-video.svg"; + +type MeetingContainerPlaceholderProps = { + children?: ReactNode; +}; + +const HintText = styled.span` + font-size: 13px; + color: #b8b9bf; + text-align: center; +`; + +export function MeetingContainerPlaceholder( + props: MeetingContainerPlaceholderProps +) { + return ( +
+ + + {props.children} + +
+ ); +} + +export const MeetingHintPlaceHolder = ( + + {trans("container.hintPlaceHolder")} + +); diff --git a/node_modules/.bin/uuid b/node_modules/.bin/uuid new file mode 120000 index 000000000..588f70ecc --- /dev/null +++ b/node_modules/.bin/uuid @@ -0,0 +1 @@ +../uuid/dist/bin/uuid \ No newline at end of file diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity new file mode 100644 index 000000000..7799c779f --- /dev/null +++ b/node_modules/.yarn-integrity @@ -0,0 +1,16 @@ +{ + "systemParams": "darwin-x64-115", + "modulesFolders": [ + "node_modules" + ], + "flags": [], + "linkedModules": [], + "topLevelPatterns": [ + "uuid@^9.0.1" + ], + "lockfileEntries": { + "uuid@^9.0.1": "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + }, + "files": [], + "artifacts": {} +} \ No newline at end of file diff --git a/node_modules/uuid/CHANGELOG.md b/node_modules/uuid/CHANGELOG.md new file mode 100644 index 000000000..0412ad8a6 --- /dev/null +++ b/node_modules/uuid/CHANGELOG.md @@ -0,0 +1,274 @@ +# Changelog + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## [9.0.1](https://github.com/uuidjs/uuid/compare/v9.0.0...v9.0.1) (2023-09-12) + +### build + +- Fix CI to work with Node.js 20.x + +## [9.0.0](https://github.com/uuidjs/uuid/compare/v8.3.2...v9.0.0) (2022-09-05) + +### ⚠ BREAKING CHANGES + +- Drop Node.js 10.x support. This library always aims at supporting one EOLed LTS release which by this time now is 12.x which has reached EOL 30 Apr 2022. + +- Remove the minified UMD build from the package. + + Minified code is hard to audit and since this is a widely used library it seems more appropriate nowadays to optimize for auditability than to ship a legacy module format that, at best, serves educational purposes nowadays. + + For production browser use cases, users should be using a bundler. For educational purposes, today's online sandboxes like replit.com offer convenient ways to load npm modules, so the use case for UMD through repos like UNPKG or jsDelivr has largely vanished. + +- Drop IE 11 and Safari 10 support. Drop support for browsers that don't correctly implement const/let and default arguments, and no longer transpile the browser build to ES2015. + + This also removes the fallback on msCrypto instead of the crypto API. + + Browser tests are run in the first supported version of each supported browser and in the latest (as of this commit) version available on Browserstack. + +### Features + +- optimize uuid.v1 by 1.3x uuid.v4 by 4.3x (430%) ([#597](https://github.com/uuidjs/uuid/issues/597)) ([3a033f6](https://github.com/uuidjs/uuid/commit/3a033f6bab6bb3780ece6d645b902548043280bc)) +- remove UMD build ([#645](https://github.com/uuidjs/uuid/issues/645)) ([e948a0f](https://github.com/uuidjs/uuid/commit/e948a0f22bf22f4619b27bd913885e478e20fe6f)), closes [#620](https://github.com/uuidjs/uuid/issues/620) +- use native crypto.randomUUID when available ([#600](https://github.com/uuidjs/uuid/issues/600)) ([c9e076c](https://github.com/uuidjs/uuid/commit/c9e076c852edad7e9a06baaa1d148cf4eda6c6c4)) + +### Bug Fixes + +- add Jest/jsdom compatibility ([#642](https://github.com/uuidjs/uuid/issues/642)) ([16f9c46](https://github.com/uuidjs/uuid/commit/16f9c469edf46f0786164cdf4dc980743984a6fd)) +- change default export to named function ([#545](https://github.com/uuidjs/uuid/issues/545)) ([c57bc5a](https://github.com/uuidjs/uuid/commit/c57bc5a9a0653273aa639cda9177ce52efabe42a)) +- handle error when parameter is not set in v3 and v5 ([#622](https://github.com/uuidjs/uuid/issues/622)) ([fcd7388](https://github.com/uuidjs/uuid/commit/fcd73881692d9fabb63872576ba28e30ff852091)) +- run npm audit fix ([#644](https://github.com/uuidjs/uuid/issues/644)) ([04686f5](https://github.com/uuidjs/uuid/commit/04686f54c5fed2cfffc1b619f4970c4bb8532353)) +- upgrading from uuid3 broken link ([#568](https://github.com/uuidjs/uuid/issues/568)) ([1c849da](https://github.com/uuidjs/uuid/commit/1c849da6e164259e72e18636726345b13a7eddd6)) + +### build + +- drop Node.js 8.x from babel transpile target ([#603](https://github.com/uuidjs/uuid/issues/603)) ([aa11485](https://github.com/uuidjs/uuid/commit/aa114858260402107ec8a1e1a825dea0a259bcb5)) +- drop support for legacy browsers (IE11, Safari 10) ([#604](https://github.com/uuidjs/uuid/issues/604)) ([0f433e5](https://github.com/uuidjs/uuid/commit/0f433e5ec444edacd53016de67db021102f36148)) + +- drop node 10.x to upgrade dev dependencies ([#653](https://github.com/uuidjs/uuid/issues/653)) ([28a5712](https://github.com/uuidjs/uuid/commit/28a571283f8abda6b9d85e689f95b7d3ee9e282e)), closes [#643](https://github.com/uuidjs/uuid/issues/643) + +### [8.3.2](https://github.com/uuidjs/uuid/compare/v8.3.1...v8.3.2) (2020-12-08) + +### Bug Fixes + +- lazy load getRandomValues ([#537](https://github.com/uuidjs/uuid/issues/537)) ([16c8f6d](https://github.com/uuidjs/uuid/commit/16c8f6df2f6b09b4d6235602d6a591188320a82e)), closes [#536](https://github.com/uuidjs/uuid/issues/536) + +### [8.3.1](https://github.com/uuidjs/uuid/compare/v8.3.0...v8.3.1) (2020-10-04) + +### Bug Fixes + +- support expo>=39.0.0 ([#515](https://github.com/uuidjs/uuid/issues/515)) ([c65a0f3](https://github.com/uuidjs/uuid/commit/c65a0f3fa73b901959d638d1e3591dfacdbed867)), closes [#375](https://github.com/uuidjs/uuid/issues/375) + +## [8.3.0](https://github.com/uuidjs/uuid/compare/v8.2.0...v8.3.0) (2020-07-27) + +### Features + +- add parse/stringify/validate/version/NIL APIs ([#479](https://github.com/uuidjs/uuid/issues/479)) ([0e6c10b](https://github.com/uuidjs/uuid/commit/0e6c10ba1bf9517796ff23c052fc0468eedfd5f4)), closes [#475](https://github.com/uuidjs/uuid/issues/475) [#478](https://github.com/uuidjs/uuid/issues/478) [#480](https://github.com/uuidjs/uuid/issues/480) [#481](https://github.com/uuidjs/uuid/issues/481) [#180](https://github.com/uuidjs/uuid/issues/180) + +## [8.2.0](https://github.com/uuidjs/uuid/compare/v8.1.0...v8.2.0) (2020-06-23) + +### Features + +- improve performance of v1 string representation ([#453](https://github.com/uuidjs/uuid/issues/453)) ([0ee0b67](https://github.com/uuidjs/uuid/commit/0ee0b67c37846529c66089880414d29f3ae132d5)) +- remove deprecated v4 string parameter ([#454](https://github.com/uuidjs/uuid/issues/454)) ([88ce3ca](https://github.com/uuidjs/uuid/commit/88ce3ca0ba046f60856de62c7ce03f7ba98ba46c)), closes [#437](https://github.com/uuidjs/uuid/issues/437) +- support jspm ([#473](https://github.com/uuidjs/uuid/issues/473)) ([e9f2587](https://github.com/uuidjs/uuid/commit/e9f2587a92575cac31bc1d4ae944e17c09756659)) + +### Bug Fixes + +- prepare package exports for webpack 5 ([#468](https://github.com/uuidjs/uuid/issues/468)) ([8d6e6a5](https://github.com/uuidjs/uuid/commit/8d6e6a5f8965ca9575eb4d92e99a43435f4a58a8)) + +## [8.1.0](https://github.com/uuidjs/uuid/compare/v8.0.0...v8.1.0) (2020-05-20) + +### Features + +- improve v4 performance by reusing random number array ([#435](https://github.com/uuidjs/uuid/issues/435)) ([bf4af0d](https://github.com/uuidjs/uuid/commit/bf4af0d711b4d2ed03d1f74fd12ad0baa87dc79d)) +- optimize V8 performance of bytesToUuid ([#434](https://github.com/uuidjs/uuid/issues/434)) ([e156415](https://github.com/uuidjs/uuid/commit/e156415448ec1af2351fa0b6660cfb22581971f2)) + +### Bug Fixes + +- export package.json required by react-native and bundlers ([#449](https://github.com/uuidjs/uuid/issues/449)) ([be1c8fe](https://github.com/uuidjs/uuid/commit/be1c8fe9a3206c358e0059b52fafd7213aa48a52)), closes [ai/nanoevents#44](https://github.com/ai/nanoevents/issues/44#issuecomment-602010343) [#444](https://github.com/uuidjs/uuid/issues/444) + +## [8.0.0](https://github.com/uuidjs/uuid/compare/v7.0.3...v8.0.0) (2020-04-29) + +### ⚠ BREAKING CHANGES + +- For native ECMAScript Module (ESM) usage in Node.js only named exports are exposed, there is no more default export. + + ```diff + -import uuid from 'uuid'; + -console.log(uuid.v4()); // -> 'cd6c3b08-0adc-4f4b-a6ef-36087a1c9869' + +import { v4 as uuidv4 } from 'uuid'; + +uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d' + ``` + +- Deep requiring specific algorithms of this library like `require('uuid/v4')`, which has been deprecated in `uuid@7`, is no longer supported. + + Instead use the named exports that this module exports. + + For ECMAScript Modules (ESM): + + ```diff + -import uuidv4 from 'uuid/v4'; + +import { v4 as uuidv4 } from 'uuid'; + uuidv4(); + ``` + + For CommonJS: + + ```diff + -const uuidv4 = require('uuid/v4'); + +const { v4: uuidv4 } = require('uuid'); + uuidv4(); + ``` + +### Features + +- native Node.js ES Modules (wrapper approach) ([#423](https://github.com/uuidjs/uuid/issues/423)) ([2d9f590](https://github.com/uuidjs/uuid/commit/2d9f590ad9701d692625c07ed62f0a0f91227991)), closes [#245](https://github.com/uuidjs/uuid/issues/245) [#419](https://github.com/uuidjs/uuid/issues/419) [#342](https://github.com/uuidjs/uuid/issues/342) +- remove deep requires ([#426](https://github.com/uuidjs/uuid/issues/426)) ([daf72b8](https://github.com/uuidjs/uuid/commit/daf72b84ceb20272a81bb5fbddb05dd95922cbba)) + +### Bug Fixes + +- add CommonJS syntax example to README quickstart section ([#417](https://github.com/uuidjs/uuid/issues/417)) ([e0ec840](https://github.com/uuidjs/uuid/commit/e0ec8402c7ad44b7ef0453036c612f5db513fda0)) + +### [7.0.3](https://github.com/uuidjs/uuid/compare/v7.0.2...v7.0.3) (2020-03-31) + +### Bug Fixes + +- make deep require deprecation warning work in browsers ([#409](https://github.com/uuidjs/uuid/issues/409)) ([4b71107](https://github.com/uuidjs/uuid/commit/4b71107d8c0d2ef56861ede6403fc9dc35a1e6bf)), closes [#408](https://github.com/uuidjs/uuid/issues/408) + +### [7.0.2](https://github.com/uuidjs/uuid/compare/v7.0.1...v7.0.2) (2020-03-04) + +### Bug Fixes + +- make access to msCrypto consistent ([#393](https://github.com/uuidjs/uuid/issues/393)) ([8bf2a20](https://github.com/uuidjs/uuid/commit/8bf2a20f3565df743da7215eebdbada9d2df118c)) +- simplify link in deprecation warning ([#391](https://github.com/uuidjs/uuid/issues/391)) ([bb2c8e4](https://github.com/uuidjs/uuid/commit/bb2c8e4e9f4c5f9c1eaaf3ea59710c633cd90cb7)) +- update links to match content in readme ([#386](https://github.com/uuidjs/uuid/issues/386)) ([44f2f86](https://github.com/uuidjs/uuid/commit/44f2f86e9d2bbf14ee5f0f00f72a3db1292666d4)) + +### [7.0.1](https://github.com/uuidjs/uuid/compare/v7.0.0...v7.0.1) (2020-02-25) + +### Bug Fixes + +- clean up esm builds for node and browser ([#383](https://github.com/uuidjs/uuid/issues/383)) ([59e6a49](https://github.com/uuidjs/uuid/commit/59e6a49e7ce7b3e8fb0f3ee52b9daae72af467dc)) +- provide browser versions independent from module system ([#380](https://github.com/uuidjs/uuid/issues/380)) ([4344a22](https://github.com/uuidjs/uuid/commit/4344a22e7aed33be8627eeaaf05360f256a21753)), closes [#378](https://github.com/uuidjs/uuid/issues/378) + +## [7.0.0](https://github.com/uuidjs/uuid/compare/v3.4.0...v7.0.0) (2020-02-24) + +### ⚠ BREAKING CHANGES + +- The default export, which used to be the v4() method but which was already discouraged in v3.x of this library, has been removed. +- Explicitly note that deep imports of the different uuid version functions are deprecated and no longer encouraged and that ECMAScript module named imports should be used instead. Emit a deprecation warning for people who deep-require the different algorithm variants. +- Remove builtin support for insecure random number generators in the browser. Users who want that will have to supply their own random number generator function. +- Remove support for generating v3 and v5 UUIDs in Node.js<4.x +- Convert code base to ECMAScript Modules (ESM) and release CommonJS build for node and ESM build for browser bundlers. + +### Features + +- add UMD build to npm package ([#357](https://github.com/uuidjs/uuid/issues/357)) ([4e75adf](https://github.com/uuidjs/uuid/commit/4e75adf435196f28e3fbbe0185d654b5ded7ca2c)), closes [#345](https://github.com/uuidjs/uuid/issues/345) +- add various es module and CommonJS examples ([b238510](https://github.com/uuidjs/uuid/commit/b238510bf352463521f74bab175a3af9b7a42555)) +- ensure that docs are up-to-date in CI ([ee5e77d](https://github.com/uuidjs/uuid/commit/ee5e77db547474f5a8f23d6c857a6d399209986b)) +- hybrid CommonJS & ECMAScript modules build ([a3f078f](https://github.com/uuidjs/uuid/commit/a3f078faa0baff69ab41aed08e041f8f9c8993d0)) +- remove insecure fallback random number generator ([3a5842b](https://github.com/uuidjs/uuid/commit/3a5842b141a6e5de0ae338f391661e6b84b167c9)), closes [#173](https://github.com/uuidjs/uuid/issues/173) +- remove support for pre Node.js v4 Buffer API ([#356](https://github.com/uuidjs/uuid/issues/356)) ([b59b5c5](https://github.com/uuidjs/uuid/commit/b59b5c5ecad271c5453f1a156f011671f6d35627)) +- rename repository to github:uuidjs/uuid ([#351](https://github.com/uuidjs/uuid/issues/351)) ([c37a518](https://github.com/uuidjs/uuid/commit/c37a518e367ac4b6d0aa62dba1bc6ce9e85020f7)), closes [#338](https://github.com/uuidjs/uuid/issues/338) + +### Bug Fixes + +- add deep-require proxies for local testing and adjust tests ([#365](https://github.com/uuidjs/uuid/issues/365)) ([7fedc79](https://github.com/uuidjs/uuid/commit/7fedc79ac8fda4bfd1c566c7f05ef4ac13b2db48)) +- add note about removal of default export ([#372](https://github.com/uuidjs/uuid/issues/372)) ([12749b7](https://github.com/uuidjs/uuid/commit/12749b700eb49db8a9759fd306d8be05dbfbd58c)), closes [#370](https://github.com/uuidjs/uuid/issues/370) +- deprecated deep requiring of the different algorithm versions ([#361](https://github.com/uuidjs/uuid/issues/361)) ([c0bdf15](https://github.com/uuidjs/uuid/commit/c0bdf15e417639b1aeb0b247b2fb11f7a0a26b23)) + +## [3.4.0](https://github.com/uuidjs/uuid/compare/v3.3.3...v3.4.0) (2020-01-16) + +### Features + +- rename repository to github:uuidjs/uuid ([#351](https://github.com/uuidjs/uuid/issues/351)) ([e2d7314](https://github.com/uuidjs/uuid/commit/e2d7314)), closes [#338](https://github.com/uuidjs/uuid/issues/338) + +## [3.3.3](https://github.com/uuidjs/uuid/compare/v3.3.2...v3.3.3) (2019-08-19) + +### Bug Fixes + +- no longer run ci tests on node v4 +- upgrade dependencies + +## [3.3.2](https://github.com/uuidjs/uuid/compare/v3.3.1...v3.3.2) (2018-06-28) + +### Bug Fixes + +- typo ([305d877](https://github.com/uuidjs/uuid/commit/305d877)) + +## [3.3.1](https://github.com/uuidjs/uuid/compare/v3.3.0...v3.3.1) (2018-06-28) + +### Bug Fixes + +- fix [#284](https://github.com/uuidjs/uuid/issues/284) by setting function name in try-catch ([f2a60f2](https://github.com/uuidjs/uuid/commit/f2a60f2)) + +# [3.3.0](https://github.com/uuidjs/uuid/compare/v3.2.1...v3.3.0) (2018-06-22) + +### Bug Fixes + +- assignment to readonly property to allow running in strict mode ([#270](https://github.com/uuidjs/uuid/issues/270)) ([d062fdc](https://github.com/uuidjs/uuid/commit/d062fdc)) +- fix [#229](https://github.com/uuidjs/uuid/issues/229) ([c9684d4](https://github.com/uuidjs/uuid/commit/c9684d4)) +- Get correct version of IE11 crypto ([#274](https://github.com/uuidjs/uuid/issues/274)) ([153d331](https://github.com/uuidjs/uuid/commit/153d331)) +- mem issue when generating uuid ([#267](https://github.com/uuidjs/uuid/issues/267)) ([c47702c](https://github.com/uuidjs/uuid/commit/c47702c)) + +### Features + +- enforce Conventional Commit style commit messages ([#282](https://github.com/uuidjs/uuid/issues/282)) ([cc9a182](https://github.com/uuidjs/uuid/commit/cc9a182)) + +## [3.2.1](https://github.com/uuidjs/uuid/compare/v3.2.0...v3.2.1) (2018-01-16) + +### Bug Fixes + +- use msCrypto if available. Fixes [#241](https://github.com/uuidjs/uuid/issues/241) ([#247](https://github.com/uuidjs/uuid/issues/247)) ([1fef18b](https://github.com/uuidjs/uuid/commit/1fef18b)) + +# [3.2.0](https://github.com/uuidjs/uuid/compare/v3.1.0...v3.2.0) (2018-01-16) + +### Bug Fixes + +- remove mistakenly added typescript dependency, rollback version (standard-version will auto-increment) ([09fa824](https://github.com/uuidjs/uuid/commit/09fa824)) +- use msCrypto if available. Fixes [#241](https://github.com/uuidjs/uuid/issues/241) ([#247](https://github.com/uuidjs/uuid/issues/247)) ([1fef18b](https://github.com/uuidjs/uuid/commit/1fef18b)) + +### Features + +- Add v3 Support ([#217](https://github.com/uuidjs/uuid/issues/217)) ([d94f726](https://github.com/uuidjs/uuid/commit/d94f726)) + +# [3.1.0](https://github.com/uuidjs/uuid/compare/v3.1.0...v3.0.1) (2017-06-17) + +### Bug Fixes + +- (fix) Add .npmignore file to exclude test/ and other non-essential files from packing. (#183) +- Fix typo (#178) +- Simple typo fix (#165) + +### Features + +- v5 support in CLI (#197) +- V5 support (#188) + +# 3.0.1 (2016-11-28) + +- split uuid versions into separate files + +# 3.0.0 (2016-11-17) + +- remove .parse and .unparse + +# 2.0.0 + +- Removed uuid.BufferClass + +# 1.4.0 + +- Improved module context detection +- Removed public RNG functions + +# 1.3.2 + +- Improve tests and handling of v1() options (Issue #24) +- Expose RNG option to allow for perf testing with different generators + +# 1.3.0 + +- Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)! +- Support for node.js crypto API +- De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code diff --git a/node_modules/uuid/CONTRIBUTING.md b/node_modules/uuid/CONTRIBUTING.md new file mode 100644 index 000000000..4a4503d02 --- /dev/null +++ b/node_modules/uuid/CONTRIBUTING.md @@ -0,0 +1,18 @@ +# Contributing + +Please feel free to file GitHub Issues or propose Pull Requests. We're always happy to discuss improvements to this library! + +## Testing + +```shell +npm test +``` + +## Releasing + +Releases are supposed to be done from master, version bumping is automated through [`standard-version`](https://github.com/conventional-changelog/standard-version): + +```shell +npm run release -- --dry-run # verify output manually +npm run release # follow the instructions from the output of this command +``` diff --git a/node_modules/uuid/LICENSE.md b/node_modules/uuid/LICENSE.md new file mode 100644 index 000000000..393416836 --- /dev/null +++ b/node_modules/uuid/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/uuid/README.md b/node_modules/uuid/README.md new file mode 100644 index 000000000..4f51e0980 --- /dev/null +++ b/node_modules/uuid/README.md @@ -0,0 +1,466 @@ + + + +# uuid [![CI](https://github.com/uuidjs/uuid/workflows/CI/badge.svg)](https://github.com/uuidjs/uuid/actions?query=workflow%3ACI) [![Browser](https://github.com/uuidjs/uuid/workflows/Browser/badge.svg)](https://github.com/uuidjs/uuid/actions?query=workflow%3ABrowser) + +For the creation of [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) UUIDs + +- **Complete** - Support for RFC4122 version 1, 3, 4, and 5 UUIDs +- **Cross-platform** - Support for ... + - CommonJS, [ECMAScript Modules](#ecmascript-modules) and [CDN builds](#cdn-builds) + - NodeJS 12+ ([LTS releases](https://github.com/nodejs/Release)) + - Chrome, Safari, Firefox, Edge browsers + - Webpack and rollup.js module bundlers + - [React Native / Expo](#react-native--expo) +- **Secure** - Cryptographically-strong random values +- **Small** - Zero-dependency, small footprint, plays nice with "tree shaking" packagers +- **CLI** - Includes the [`uuid` command line](#command-line) utility + +> **Note** Upgrading from `uuid@3`? Your code is probably okay, but check out [Upgrading From `uuid@3`](#upgrading-from-uuid3) for details. + +> **Note** Only interested in creating a version 4 UUID? You might be able to use [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID), eliminating the need to install this library. + +## Quickstart + +To create a random UUID... + +**1. Install** + +```shell +npm install uuid +``` + +**2. Create a UUID** (ES6 module syntax) + +```javascript +import { v4 as uuidv4 } from 'uuid'; +uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d' +``` + +... or using CommonJS syntax: + +```javascript +const { v4: uuidv4 } = require('uuid'); +uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' +``` + +For timestamp UUIDs, namespace UUIDs, and other options read on ... + +## API Summary + +| | | | +| --- | --- | --- | +| [`uuid.NIL`](#uuidnil) | The nil UUID string (all zeros) | New in `uuid@8.3` | +| [`uuid.parse()`](#uuidparsestr) | Convert UUID string to array of bytes | New in `uuid@8.3` | +| [`uuid.stringify()`](#uuidstringifyarr-offset) | Convert array of bytes to UUID string | New in `uuid@8.3` | +| [`uuid.v1()`](#uuidv1options-buffer-offset) | Create a version 1 (timestamp) UUID | | +| [`uuid.v3()`](#uuidv3name-namespace-buffer-offset) | Create a version 3 (namespace w/ MD5) UUID | | +| [`uuid.v4()`](#uuidv4options-buffer-offset) | Create a version 4 (random) UUID | | +| [`uuid.v5()`](#uuidv5name-namespace-buffer-offset) | Create a version 5 (namespace w/ SHA-1) UUID | | +| [`uuid.validate()`](#uuidvalidatestr) | Test a string to see if it is a valid UUID | New in `uuid@8.3` | +| [`uuid.version()`](#uuidversionstr) | Detect RFC version of a UUID | New in `uuid@8.3` | + +## API + +### uuid.NIL + +The nil UUID string (all zeros). + +Example: + +```javascript +import { NIL as NIL_UUID } from 'uuid'; + +NIL_UUID; // ⇨ '00000000-0000-0000-0000-000000000000' +``` + +### uuid.parse(str) + +Convert UUID string to array of bytes + +| | | +| --------- | ---------------------------------------- | +| `str` | A valid UUID `String` | +| _returns_ | `Uint8Array[16]` | +| _throws_ | `TypeError` if `str` is not a valid UUID | + +Note: Ordering of values in the byte arrays used by `parse()` and `stringify()` follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below. + +Example: + +```javascript +import { parse as uuidParse } from 'uuid'; + +// Parse a UUID +const bytes = uuidParse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); + +// Convert to hex strings to show byte order (for documentation purposes) +[...bytes].map((v) => v.toString(16).padStart(2, '0')); // ⇨ + // [ + // '6e', 'c0', 'bd', '7f', + // '11', 'c0', '43', 'da', + // '97', '5e', '2a', '8a', + // 'd9', 'eb', 'ae', '0b' + // ] +``` + +### uuid.stringify(arr[, offset]) + +Convert array of bytes to UUID string + +| | | +| -------------- | ---------------------------------------------------------------------------- | +| `arr` | `Array`-like collection of 16 values (starting from `offset`) between 0-255. | +| [`offset` = 0] | `Number` Starting index in the Array | +| _returns_ | `String` | +| _throws_ | `TypeError` if a valid UUID string cannot be generated | + +Note: Ordering of values in the byte arrays used by `parse()` and `stringify()` follows the left ↠ right order of hex-pairs in UUID strings. As shown in the example below. + +Example: + +```javascript +import { stringify as uuidStringify } from 'uuid'; + +const uuidBytes = [ + 0x6e, 0xc0, 0xbd, 0x7f, 0x11, 0xc0, 0x43, 0xda, 0x97, 0x5e, 0x2a, 0x8a, 0xd9, 0xeb, 0xae, 0x0b, +]; + +uuidStringify(uuidBytes); // ⇨ '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b' +``` + +### uuid.v1([options[, buffer[, offset]]]) + +Create an RFC version 1 (timestamp) UUID + +| | | +| --- | --- | +| [`options`] | `Object` with one or more of the following properties: | +| [`options.node` ] | RFC "node" field as an `Array[6]` of byte values (per 4.1.6) | +| [`options.clockseq`] | RFC "clock sequence" as a `Number` between 0 - 0x3fff | +| [`options.msecs`] | RFC "timestamp" field (`Number` of milliseconds, unix epoch) | +| [`options.nsecs`] | RFC "timestamp" field (`Number` of nanoseconds to add to `msecs`, should be 0-10,000) | +| [`options.random`] | `Array` of 16 random bytes (0-255) | +| [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | +| _throws_ | `Error` if more than 10M UUIDs/sec are requested | + +Note: The default [node id](https://tools.ietf.org/html/rfc4122#section-4.1.6) (the last 12 digits in the UUID) is generated once, randomly, on process startup, and then remains unchanged for the duration of the process. + +Note: `options.random` and `options.rng` are only meaningful on the very first call to `v1()`, where they may be passed to initialize the internal `node` and `clockseq` fields. + +Example: + +```javascript +import { v1 as uuidv1 } from 'uuid'; + +uuidv1(); // ⇨ '2c5ea4c0-4067-11e9-8bad-9b1deb4d3b7d' +``` + +Example using `options`: + +```javascript +import { v1 as uuidv1 } from 'uuid'; + +const v1options = { + node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], + clockseq: 0x1234, + msecs: new Date('2011-11-01').getTime(), + nsecs: 5678, +}; +uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab' +``` + +### uuid.v3(name, namespace[, buffer[, offset]]) + +Create an RFC version 3 (namespace w/ MD5) UUID + +API is identical to `v5()`, but uses "v3" instead. + +⚠️ Note: Per the RFC, "_If backward compatibility is not an issue, SHA-1 [Version 5] is preferred_." + +### uuid.v4([options[, buffer[, offset]]]) + +Create an RFC version 4 (random) UUID + +| | | +| --- | --- | +| [`options`] | `Object` with one or more of the following properties: | +| [`options.random`] | `Array` of 16 random bytes (0-255) | +| [`options.rng`] | Alternative to `options.random`, a `Function` that returns an `Array` of 16 random bytes (0-255) | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | + +Example: + +```javascript +import { v4 as uuidv4 } from 'uuid'; + +uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' +``` + +Example using predefined `random` values: + +```javascript +import { v4 as uuidv4 } from 'uuid'; + +const v4options = { + random: [ + 0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea, 0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36, + ], +}; +uuidv4(v4options); // ⇨ '109156be-c4fb-41ea-b1b4-efe1671c5836' +``` + +### uuid.v5(name, namespace[, buffer[, offset]]) + +Create an RFC version 5 (namespace w/ SHA-1) UUID + +| | | +| --- | --- | +| `name` | `String \| Array` | +| `namespace` | `String \| Array[16]` Namespace UUID | +| [`buffer`] | `Array \| Buffer` If specified, uuid will be written here in byte-form, starting at `offset` | +| [`offset` = 0] | `Number` Index to start writing UUID bytes in `buffer` | +| _returns_ | UUID `String` if no `buffer` is specified, otherwise returns `buffer` | + +Note: The RFC `DNS` and `URL` namespaces are available as `v5.DNS` and `v5.URL`. + +Example with custom namespace: + +```javascript +import { v5 as uuidv5 } from 'uuid'; + +// Define a custom namespace. Readers, create your own using something like +// https://www.uuidgenerator.net/ +const MY_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; + +uuidv5('Hello, World!', MY_NAMESPACE); // ⇨ '630eb68f-e0fa-5ecc-887a-7c7a62614681' +``` + +Example with RFC `URL` namespace: + +```javascript +import { v5 as uuidv5 } from 'uuid'; + +uuidv5('https://www.w3.org/', uuidv5.URL); // ⇨ 'c106a26a-21bb-5538-8bf2-57095d1976c1' +``` + +### uuid.validate(str) + +Test a string to see if it is a valid UUID + +| | | +| --------- | --------------------------------------------------- | +| `str` | `String` to validate | +| _returns_ | `true` if string is a valid UUID, `false` otherwise | + +Example: + +```javascript +import { validate as uuidValidate } from 'uuid'; + +uuidValidate('not a UUID'); // ⇨ false +uuidValidate('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ true +``` + +Using `validate` and `version` together it is possible to do per-version validation, e.g. validate for only v4 UUIds. + +```javascript +import { version as uuidVersion } from 'uuid'; +import { validate as uuidValidate } from 'uuid'; + +function uuidValidateV4(uuid) { + return uuidValidate(uuid) && uuidVersion(uuid) === 4; +} + +const v1Uuid = 'd9428888-122b-11e1-b85c-61cd3cbb3210'; +const v4Uuid = '109156be-c4fb-41ea-b1b4-efe1671c5836'; + +uuidValidateV4(v4Uuid); // ⇨ true +uuidValidateV4(v1Uuid); // ⇨ false +``` + +### uuid.version(str) + +Detect RFC version of a UUID + +| | | +| --------- | ---------------------------------------- | +| `str` | A valid UUID `String` | +| _returns_ | `Number` The RFC version of the UUID | +| _throws_ | `TypeError` if `str` is not a valid UUID | + +Example: + +```javascript +import { version as uuidVersion } from 'uuid'; + +uuidVersion('45637ec4-c85f-11ea-87d0-0242ac130003'); // ⇨ 1 +uuidVersion('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'); // ⇨ 4 +``` + +## Command Line + +UUIDs can be generated from the command line using `uuid`. + +```shell +$ npx uuid +ddeb27fb-d9a0-4624-be4d-4615062daed4 +``` + +The default is to generate version 4 UUIDS, however the other versions are supported. Type `uuid --help` for details: + +```shell +$ npx uuid --help + +Usage: + uuid + uuid v1 + uuid v3 + uuid v4 + uuid v5 + uuid --help + +Note: may be "URL" or "DNS" to use the corresponding UUIDs +defined by RFC4122 +``` + +## ECMAScript Modules + +This library comes with [ECMAScript Modules](https://www.ecma-international.org/ecma-262/6.0/#sec-modules) (ESM) support for Node.js versions that support it ([example](./examples/node-esmodules/)) as well as bundlers like [rollup.js](https://rollupjs.org/guide/en/#tree-shaking) ([example](./examples/browser-rollup/)) and [webpack](https://webpack.js.org/guides/tree-shaking/) ([example](./examples/browser-webpack/)) (targeting both, Node.js and browser environments). + +```javascript +import { v4 as uuidv4 } from 'uuid'; +uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed' +``` + +To run the examples you must first create a dist build of this library in the module root: + +```shell +npm run build +``` + +## CDN Builds + +### ECMAScript Modules + +To load this module directly into modern browsers that [support loading ECMAScript Modules](https://caniuse.com/#feat=es6-module) you can make use of [jspm](https://jspm.org/): + +```html + +``` + +### UMD + +As of `uuid@9` [UMD (Universal Module Definition)](https://github.com/umdjs/umd) builds are no longer shipped with this library. + +If you need a UMD build of this library, use a bundler like Webpack or Rollup. Alternatively, refer to the documentation of [`uuid@8.3.2`](https://github.com/uuidjs/uuid/blob/v8.3.2/README.md#umd) which was the last version that shipped UMD builds. + +## Known issues + +### Duplicate UUIDs (Googlebot) + +This module may generate duplicate UUIDs when run in clients with _deterministic_ random number generators, such as [Googlebot crawlers](https://developers.google.com/search/docs/advanced/crawling/overview-google-crawlers). This can cause problems for apps that expect client-generated UUIDs to always be unique. Developers should be prepared for this and have a strategy for dealing with possible collisions, such as: + +- Check for duplicate UUIDs, fail gracefully +- Disable write operations for Googlebot clients + +### "getRandomValues() not supported" + +This error occurs in environments where the standard [`crypto.getRandomValues()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) API is not supported. This issue can be resolved by adding an appropriate polyfill: + +### React Native / Expo + +1. Install [`react-native-get-random-values`](https://github.com/LinusU/react-native-get-random-values#readme) +1. Import it _before_ `uuid`. Since `uuid` might also appear as a transitive dependency of some other imports it's safest to just import `react-native-get-random-values` as the very first thing in your entry point: + +```javascript +import 'react-native-get-random-values'; +import { v4 as uuidv4 } from 'uuid'; +``` + +Note: If you are using Expo, you must be using at least `react-native-get-random-values@1.5.0` and `expo@39.0.0`. + +### Web Workers / Service Workers (Edge <= 18) + +[In Edge <= 18, Web Crypto is not supported in Web Workers or Service Workers](https://caniuse.com/#feat=cryptography) and we are not aware of a polyfill (let us know if you find one, please). + +### IE 11 (Internet Explorer) + +Support for IE11 and other legacy browsers has been dropped as of `uuid@9`. If you need to support legacy browsers, you can always transpile the uuid module source yourself (e.g. using [Babel](https://babeljs.io/)). + +## Upgrading From `uuid@7` + +### Only Named Exports Supported When Using with Node.js ESM + +`uuid@7` did not come with native ECMAScript Module (ESM) support for Node.js. Importing it in Node.js ESM consequently imported the CommonJS source with a default export. This library now comes with true Node.js ESM support and only provides named exports. + +Instead of doing: + +```javascript +import uuid from 'uuid'; +uuid.v4(); +``` + +you will now have to use the named exports: + +```javascript +import { v4 as uuidv4 } from 'uuid'; +uuidv4(); +``` + +### Deep Requires No Longer Supported + +Deep requires like `require('uuid/v4')` [which have been deprecated in `uuid@7`](#deep-requires-now-deprecated) are no longer supported. + +## Upgrading From `uuid@3` + +"_Wait... what happened to `uuid@4` thru `uuid@6`?!?_" + +In order to avoid confusion with RFC [version 4](#uuidv4options-buffer-offset) and [version 5](#uuidv5name-namespace-buffer-offset) UUIDs, and a possible [version 6](http://gh.peabody.io/uuidv6/), releases 4 thru 6 of this module have been skipped. + +### Deep Requires Now Deprecated + +`uuid@3` encouraged the use of deep requires to minimize the bundle size of browser builds: + +```javascript +const uuidv4 = require('uuid/v4'); // <== NOW DEPRECATED! +uuidv4(); +``` + +As of `uuid@7` this library now provides ECMAScript modules builds, which allow packagers like Webpack and Rollup to do "tree-shaking" to remove dead code. Instead, use the `import` syntax: + +```javascript +import { v4 as uuidv4 } from 'uuid'; +uuidv4(); +``` + +... or for CommonJS: + +```javascript +const { v4: uuidv4 } = require('uuid'); +uuidv4(); +``` + +### Default Export Removed + +`uuid@3` was exporting the Version 4 UUID method as a default export: + +```javascript +const uuid = require('uuid'); // <== REMOVED! +``` + +This usage pattern was already discouraged in `uuid@3` and has been removed in `uuid@7`. + +--- + +Markdown generated from [README_js.md](README_js.md) by diff --git a/node_modules/uuid/dist/bin/uuid b/node_modules/uuid/dist/bin/uuid new file mode 100755 index 000000000..f38d2ee19 --- /dev/null +++ b/node_modules/uuid/dist/bin/uuid @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../uuid-bin'); diff --git a/node_modules/uuid/dist/commonjs-browser/index.js b/node_modules/uuid/dist/commonjs-browser/index.js new file mode 100644 index 000000000..5586dd3d0 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/index.js @@ -0,0 +1,79 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "NIL", { + enumerable: true, + get: function get() { + return _nil.default; + } +}); +Object.defineProperty(exports, "parse", { + enumerable: true, + get: function get() { + return _parse.default; + } +}); +Object.defineProperty(exports, "stringify", { + enumerable: true, + get: function get() { + return _stringify.default; + } +}); +Object.defineProperty(exports, "v1", { + enumerable: true, + get: function get() { + return _v.default; + } +}); +Object.defineProperty(exports, "v3", { + enumerable: true, + get: function get() { + return _v2.default; + } +}); +Object.defineProperty(exports, "v4", { + enumerable: true, + get: function get() { + return _v3.default; + } +}); +Object.defineProperty(exports, "v5", { + enumerable: true, + get: function get() { + return _v4.default; + } +}); +Object.defineProperty(exports, "validate", { + enumerable: true, + get: function get() { + return _validate.default; + } +}); +Object.defineProperty(exports, "version", { + enumerable: true, + get: function get() { + return _version.default; + } +}); + +var _v = _interopRequireDefault(require("./v1.js")); + +var _v2 = _interopRequireDefault(require("./v3.js")); + +var _v3 = _interopRequireDefault(require("./v4.js")); + +var _v4 = _interopRequireDefault(require("./v5.js")); + +var _nil = _interopRequireDefault(require("./nil.js")); + +var _version = _interopRequireDefault(require("./version.js")); + +var _validate = _interopRequireDefault(require("./validate.js")); + +var _stringify = _interopRequireDefault(require("./stringify.js")); + +var _parse = _interopRequireDefault(require("./parse.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/md5.js b/node_modules/uuid/dist/commonjs-browser/md5.js new file mode 100644 index 000000000..7a4582ace --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/md5.js @@ -0,0 +1,223 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +/* + * Browser-compatible JavaScript MD5 + * + * Modification of JavaScript MD5 + * https://github.com/blueimp/JavaScript-MD5 + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + * + * Based on + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ +function md5(bytes) { + if (typeof bytes === 'string') { + const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + + bytes = new Uint8Array(msg.length); + + for (let i = 0; i < msg.length; ++i) { + bytes[i] = msg.charCodeAt(i); + } + } + + return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8)); +} +/* + * Convert an array of little-endian words to an array of bytes + */ + + +function md5ToHexEncodedArray(input) { + const output = []; + const length32 = input.length * 32; + const hexTab = '0123456789abcdef'; + + for (let i = 0; i < length32; i += 8) { + const x = input[i >> 5] >>> i % 32 & 0xff; + const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16); + output.push(hex); + } + + return output; +} +/** + * Calculate output length with padding and bit length + */ + + +function getOutputLength(inputLength8) { + return (inputLength8 + 64 >>> 9 << 4) + 14 + 1; +} +/* + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ + + +function wordsToMd5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[getOutputLength(len) - 1] = len; + let a = 1732584193; + let b = -271733879; + let c = -1732584194; + let d = 271733878; + + for (let i = 0; i < x.length; i += 16) { + const olda = a; + const oldb = b; + const oldc = c; + const oldd = d; + a = md5ff(a, b, c, d, x[i], 7, -680876936); + d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); + a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5gg(b, c, d, a, x[i], 20, -373897302); + a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); + a = md5hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5hh(d, a, b, c, x[i], 11, -358537222); + c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); + a = md5ii(a, b, c, d, x[i], 6, -198630844); + d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); + a = safeAdd(a, olda); + b = safeAdd(b, oldb); + c = safeAdd(c, oldc); + d = safeAdd(d, oldd); + } + + return [a, b, c, d]; +} +/* + * Convert an array bytes to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ + + +function bytesToWords(input) { + if (input.length === 0) { + return []; + } + + const length8 = input.length * 8; + const output = new Uint32Array(getOutputLength(length8)); + + for (let i = 0; i < length8; i += 8) { + output[i >> 5] |= (input[i / 8] & 0xff) << i % 32; + } + + return output; +} +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + + +function safeAdd(x, y) { + const lsw = (x & 0xffff) + (y & 0xffff); + const msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return msw << 16 | lsw & 0xffff; +} +/* + * Bitwise rotate a 32-bit number to the left. + */ + + +function bitRotateLeft(num, cnt) { + return num << cnt | num >>> 32 - cnt; +} +/* + * These functions implement the four basic operations the algorithm uses. + */ + + +function md5cmn(q, a, b, x, s, t) { + return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); +} + +function md5ff(a, b, c, d, x, s, t) { + return md5cmn(b & c | ~b & d, a, b, x, s, t); +} + +function md5gg(a, b, c, d, x, s, t) { + return md5cmn(b & d | c & ~d, a, b, x, s, t); +} + +function md5hh(a, b, c, d, x, s, t) { + return md5cmn(b ^ c ^ d, a, b, x, s, t); +} + +function md5ii(a, b, c, d, x, s, t) { + return md5cmn(c ^ (b | ~d), a, b, x, s, t); +} + +var _default = md5; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/native.js b/node_modules/uuid/dist/commonjs-browser/native.js new file mode 100644 index 000000000..c2eea59d0 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/native.js @@ -0,0 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); +var _default = { + randomUUID +}; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/nil.js b/node_modules/uuid/dist/commonjs-browser/nil.js new file mode 100644 index 000000000..7ade577b2 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/nil.js @@ -0,0 +1,8 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _default = '00000000-0000-0000-0000-000000000000'; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/parse.js b/node_modules/uuid/dist/commonjs-browser/parse.js new file mode 100644 index 000000000..4c69fc39e --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/parse.js @@ -0,0 +1,45 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _validate = _interopRequireDefault(require("./validate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function parse(uuid) { + if (!(0, _validate.default)(uuid)) { + throw TypeError('Invalid UUID'); + } + + let v; + const arr = new Uint8Array(16); // Parse ########-....-....-....-............ + + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = v >>> 16 & 0xff; + arr[2] = v >>> 8 & 0xff; + arr[3] = v & 0xff; // Parse ........-####-....-....-............ + + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; // Parse ........-....-####-....-............ + + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; // Parse ........-....-....-####-............ + + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + + arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; + arr[11] = v / 0x100000000 & 0xff; + arr[12] = v >>> 24 & 0xff; + arr[13] = v >>> 16 & 0xff; + arr[14] = v >>> 8 & 0xff; + arr[15] = v & 0xff; + return arr; +} + +var _default = parse; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/regex.js b/node_modules/uuid/dist/commonjs-browser/regex.js new file mode 100644 index 000000000..1ef91d64c --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/regex.js @@ -0,0 +1,8 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/rng.js b/node_modules/uuid/dist/commonjs-browser/rng.js new file mode 100644 index 000000000..d067cdb04 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/rng.js @@ -0,0 +1,25 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = rng; +// Unique ID creation requires a high quality random # generator. In the browser we therefore +// require the crypto API and do not support built-in fallback to lower quality random number +// generators (like Math.random()). +let getRandomValues; +const rnds8 = new Uint8Array(16); + +function rng() { + // lazy load so that environments that need to polyfill have a chance to do so + if (!getRandomValues) { + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. + getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); + + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); + } + } + + return getRandomValues(rnds8); +} \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/sha1.js b/node_modules/uuid/dist/commonjs-browser/sha1.js new file mode 100644 index 000000000..24cbcedca --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/sha1.js @@ -0,0 +1,104 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +// Adapted from Chris Veness' SHA1 code at +// http://www.movable-type.co.uk/scripts/sha1.html +function f(s, x, y, z) { + switch (s) { + case 0: + return x & y ^ ~x & z; + + case 1: + return x ^ y ^ z; + + case 2: + return x & y ^ x & z ^ y & z; + + case 3: + return x ^ y ^ z; + } +} + +function ROTL(x, n) { + return x << n | x >>> 32 - n; +} + +function sha1(bytes) { + const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; + + if (typeof bytes === 'string') { + const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + + bytes = []; + + for (let i = 0; i < msg.length; ++i) { + bytes.push(msg.charCodeAt(i)); + } + } else if (!Array.isArray(bytes)) { + // Convert Array-like to Array + bytes = Array.prototype.slice.call(bytes); + } + + bytes.push(0x80); + const l = bytes.length / 4 + 2; + const N = Math.ceil(l / 16); + const M = new Array(N); + + for (let i = 0; i < N; ++i) { + const arr = new Uint32Array(16); + + for (let j = 0; j < 16; ++j) { + arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3]; + } + + M[i] = arr; + } + + M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); + M[N - 1][14] = Math.floor(M[N - 1][14]); + M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; + + for (let i = 0; i < N; ++i) { + const W = new Uint32Array(80); + + for (let t = 0; t < 16; ++t) { + W[t] = M[i][t]; + } + + for (let t = 16; t < 80; ++t) { + W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } + + let a = H[0]; + let b = H[1]; + let c = H[2]; + let d = H[3]; + let e = H[4]; + + for (let t = 0; t < 80; ++t) { + const s = Math.floor(t / 20); + const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0; + e = d; + d = c; + c = ROTL(b, 30) >>> 0; + b = a; + a = T; + } + + H[0] = H[0] + a >>> 0; + H[1] = H[1] + b >>> 0; + H[2] = H[2] + c >>> 0; + H[3] = H[3] + d >>> 0; + H[4] = H[4] + e >>> 0; + } + + return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; +} + +var _default = sha1; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/stringify.js b/node_modules/uuid/dist/commonjs-browser/stringify.js new file mode 100644 index 000000000..390bf8918 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/stringify.js @@ -0,0 +1,44 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +exports.unsafeStringify = unsafeStringify; + +var _validate = _interopRequireDefault(require("./validate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ +const byteToHex = []; + +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).slice(1)); +} + +function unsafeStringify(arr, offset = 0) { + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; +} + +function stringify(arr, offset = 0) { + const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!(0, _validate.default)(uuid)) { + throw TypeError('Stringified UUID is invalid'); + } + + return uuid; +} + +var _default = stringify; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/v1.js b/node_modules/uuid/dist/commonjs-browser/v1.js new file mode 100644 index 000000000..125bc58f7 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/v1.js @@ -0,0 +1,107 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _rng = _interopRequireDefault(require("./rng.js")); + +var _stringify = require("./stringify.js"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// **`v1()` - Generate time-based UUID** +// +// Inspired by https://github.com/LiosK/UUID.js +// and http://docs.python.org/library/uuid.html +let _nodeId; + +let _clockseq; // Previous uuid creation time + + +let _lastMSecs = 0; +let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details + +function v1(options, buf, offset) { + let i = buf && offset || 0; + const b = buf || new Array(16); + options = options || {}; + let node = options.node || _nodeId; + let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not + // specified. We do this lazily to minimize issues related to insufficient + // system entropy. See #189 + + if (node == null || clockseq == null) { + const seedBytes = options.random || (options.rng || _rng.default)(); + + if (node == null) { + // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) + node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; + } + + if (clockseq == null) { + // Per 4.2.2, randomize (14 bit) clockseq + clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; + } + } // UUID timestamps are 100 nano-second units since the Gregorian epoch, + // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so + // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' + // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. + + + let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock + // cycle to simulate higher resolution clock + + let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) + + const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression + + if (dt < 0 && options.clockseq === undefined) { + clockseq = clockseq + 1 & 0x3fff; + } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new + // time interval + + + if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { + nsecs = 0; + } // Per 4.2.1.2 Throw error if too many uuids are requested + + + if (nsecs >= 10000) { + throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); + } + + _lastMSecs = msecs; + _lastNSecs = nsecs; + _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch + + msecs += 12219292800000; // `time_low` + + const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; + b[i++] = tl >>> 24 & 0xff; + b[i++] = tl >>> 16 & 0xff; + b[i++] = tl >>> 8 & 0xff; + b[i++] = tl & 0xff; // `time_mid` + + const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; + b[i++] = tmh >>> 8 & 0xff; + b[i++] = tmh & 0xff; // `time_high_and_version` + + b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + + b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) + + b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` + + b[i++] = clockseq & 0xff; // `node` + + for (let n = 0; n < 6; ++n) { + b[i + n] = node[n]; + } + + return buf || (0, _stringify.unsafeStringify)(b); +} + +var _default = v1; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/v3.js b/node_modules/uuid/dist/commonjs-browser/v3.js new file mode 100644 index 000000000..6b47ff517 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/v3.js @@ -0,0 +1,16 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _v = _interopRequireDefault(require("./v35.js")); + +var _md = _interopRequireDefault(require("./md5.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const v3 = (0, _v.default)('v3', 0x30, _md.default); +var _default = v3; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/v35.js b/node_modules/uuid/dist/commonjs-browser/v35.js new file mode 100644 index 000000000..7c522d97a --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/v35.js @@ -0,0 +1,80 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.URL = exports.DNS = void 0; +exports.default = v35; + +var _stringify = require("./stringify.js"); + +var _parse = _interopRequireDefault(require("./parse.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function stringToBytes(str) { + str = unescape(encodeURIComponent(str)); // UTF8 escape + + const bytes = []; + + for (let i = 0; i < str.length; ++i) { + bytes.push(str.charCodeAt(i)); + } + + return bytes; +} + +const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; +exports.DNS = DNS; +const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; +exports.URL = URL; + +function v35(name, version, hashfunc) { + function generateUUID(value, namespace, buf, offset) { + var _namespace; + + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = (0, _parse.default)(namespace); + } + + if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); + } // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + + + let bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); + bytes[6] = bytes[6] & 0x0f | version; + bytes[8] = bytes[8] & 0x3f | 0x80; + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; + } + + return buf; + } + + return (0, _stringify.unsafeStringify)(bytes); + } // Function#name is not settable on some platforms (#270) + + + try { + generateUUID.name = name; // eslint-disable-next-line no-empty + } catch (err) {} // For CommonJS default export support + + + generateUUID.DNS = DNS; + generateUUID.URL = URL; + return generateUUID; +} \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/v4.js b/node_modules/uuid/dist/commonjs-browser/v4.js new file mode 100644 index 000000000..959d69869 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/v4.js @@ -0,0 +1,43 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _native = _interopRequireDefault(require("./native.js")); + +var _rng = _interopRequireDefault(require("./rng.js")); + +var _stringify = require("./stringify.js"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function v4(options, buf, offset) { + if (_native.default.randomUUID && !buf && !options) { + return _native.default.randomUUID(); + } + + options = options || {}; + + const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + + return buf; + } + + return (0, _stringify.unsafeStringify)(rnds); +} + +var _default = v4; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/v5.js b/node_modules/uuid/dist/commonjs-browser/v5.js new file mode 100644 index 000000000..99d615e09 --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/v5.js @@ -0,0 +1,16 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _v = _interopRequireDefault(require("./v35.js")); + +var _sha = _interopRequireDefault(require("./sha1.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const v5 = (0, _v.default)('v5', 0x50, _sha.default); +var _default = v5; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/validate.js b/node_modules/uuid/dist/commonjs-browser/validate.js new file mode 100644 index 000000000..fd052157d --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/validate.js @@ -0,0 +1,17 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _regex = _interopRequireDefault(require("./regex.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function validate(uuid) { + return typeof uuid === 'string' && _regex.default.test(uuid); +} + +var _default = validate; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/commonjs-browser/version.js b/node_modules/uuid/dist/commonjs-browser/version.js new file mode 100644 index 000000000..f63af01ad --- /dev/null +++ b/node_modules/uuid/dist/commonjs-browser/version.js @@ -0,0 +1,21 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _validate = _interopRequireDefault(require("./validate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function version(uuid) { + if (!(0, _validate.default)(uuid)) { + throw TypeError('Invalid UUID'); + } + + return parseInt(uuid.slice(14, 15), 16); +} + +var _default = version; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/index.js b/node_modules/uuid/dist/esm-browser/index.js new file mode 100644 index 000000000..1db6f6d25 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/index.js @@ -0,0 +1,9 @@ +export { default as v1 } from './v1.js'; +export { default as v3 } from './v3.js'; +export { default as v4 } from './v4.js'; +export { default as v5 } from './v5.js'; +export { default as NIL } from './nil.js'; +export { default as version } from './version.js'; +export { default as validate } from './validate.js'; +export { default as stringify } from './stringify.js'; +export { default as parse } from './parse.js'; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/md5.js b/node_modules/uuid/dist/esm-browser/md5.js new file mode 100644 index 000000000..f12212ea3 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/md5.js @@ -0,0 +1,215 @@ +/* + * Browser-compatible JavaScript MD5 + * + * Modification of JavaScript MD5 + * https://github.com/blueimp/JavaScript-MD5 + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + * + * Based on + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ +function md5(bytes) { + if (typeof bytes === 'string') { + const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + + bytes = new Uint8Array(msg.length); + + for (let i = 0; i < msg.length; ++i) { + bytes[i] = msg.charCodeAt(i); + } + } + + return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8)); +} +/* + * Convert an array of little-endian words to an array of bytes + */ + + +function md5ToHexEncodedArray(input) { + const output = []; + const length32 = input.length * 32; + const hexTab = '0123456789abcdef'; + + for (let i = 0; i < length32; i += 8) { + const x = input[i >> 5] >>> i % 32 & 0xff; + const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16); + output.push(hex); + } + + return output; +} +/** + * Calculate output length with padding and bit length + */ + + +function getOutputLength(inputLength8) { + return (inputLength8 + 64 >>> 9 << 4) + 14 + 1; +} +/* + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ + + +function wordsToMd5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[getOutputLength(len) - 1] = len; + let a = 1732584193; + let b = -271733879; + let c = -1732584194; + let d = 271733878; + + for (let i = 0; i < x.length; i += 16) { + const olda = a; + const oldb = b; + const oldc = c; + const oldd = d; + a = md5ff(a, b, c, d, x[i], 7, -680876936); + d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); + a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5gg(b, c, d, a, x[i], 20, -373897302); + a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); + a = md5hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5hh(d, a, b, c, x[i], 11, -358537222); + c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); + a = md5ii(a, b, c, d, x[i], 6, -198630844); + d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); + a = safeAdd(a, olda); + b = safeAdd(b, oldb); + c = safeAdd(c, oldc); + d = safeAdd(d, oldd); + } + + return [a, b, c, d]; +} +/* + * Convert an array bytes to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ + + +function bytesToWords(input) { + if (input.length === 0) { + return []; + } + + const length8 = input.length * 8; + const output = new Uint32Array(getOutputLength(length8)); + + for (let i = 0; i < length8; i += 8) { + output[i >> 5] |= (input[i / 8] & 0xff) << i % 32; + } + + return output; +} +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + + +function safeAdd(x, y) { + const lsw = (x & 0xffff) + (y & 0xffff); + const msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return msw << 16 | lsw & 0xffff; +} +/* + * Bitwise rotate a 32-bit number to the left. + */ + + +function bitRotateLeft(num, cnt) { + return num << cnt | num >>> 32 - cnt; +} +/* + * These functions implement the four basic operations the algorithm uses. + */ + + +function md5cmn(q, a, b, x, s, t) { + return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); +} + +function md5ff(a, b, c, d, x, s, t) { + return md5cmn(b & c | ~b & d, a, b, x, s, t); +} + +function md5gg(a, b, c, d, x, s, t) { + return md5cmn(b & d | c & ~d, a, b, x, s, t); +} + +function md5hh(a, b, c, d, x, s, t) { + return md5cmn(b ^ c ^ d, a, b, x, s, t); +} + +function md5ii(a, b, c, d, x, s, t) { + return md5cmn(c ^ (b | ~d), a, b, x, s, t); +} + +export default md5; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/native.js b/node_modules/uuid/dist/esm-browser/native.js new file mode 100644 index 000000000..b22292cd1 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/native.js @@ -0,0 +1,4 @@ +const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); +export default { + randomUUID +}; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/nil.js b/node_modules/uuid/dist/esm-browser/nil.js new file mode 100644 index 000000000..b36324c2a --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/nil.js @@ -0,0 +1 @@ +export default '00000000-0000-0000-0000-000000000000'; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/parse.js b/node_modules/uuid/dist/esm-browser/parse.js new file mode 100644 index 000000000..6421c5d5a --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/parse.js @@ -0,0 +1,35 @@ +import validate from './validate.js'; + +function parse(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + + let v; + const arr = new Uint8Array(16); // Parse ########-....-....-....-............ + + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = v >>> 16 & 0xff; + arr[2] = v >>> 8 & 0xff; + arr[3] = v & 0xff; // Parse ........-####-....-....-............ + + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; // Parse ........-....-####-....-............ + + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; // Parse ........-....-....-####-............ + + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + + arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; + arr[11] = v / 0x100000000 & 0xff; + arr[12] = v >>> 24 & 0xff; + arr[13] = v >>> 16 & 0xff; + arr[14] = v >>> 8 & 0xff; + arr[15] = v & 0xff; + return arr; +} + +export default parse; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/regex.js b/node_modules/uuid/dist/esm-browser/regex.js new file mode 100644 index 000000000..3da8673a5 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/regex.js @@ -0,0 +1 @@ +export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/rng.js b/node_modules/uuid/dist/esm-browser/rng.js new file mode 100644 index 000000000..6e652346d --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/rng.js @@ -0,0 +1,18 @@ +// Unique ID creation requires a high quality random # generator. In the browser we therefore +// require the crypto API and do not support built-in fallback to lower quality random number +// generators (like Math.random()). +let getRandomValues; +const rnds8 = new Uint8Array(16); +export default function rng() { + // lazy load so that environments that need to polyfill have a chance to do so + if (!getRandomValues) { + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. + getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); + + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); + } + } + + return getRandomValues(rnds8); +} \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/sha1.js b/node_modules/uuid/dist/esm-browser/sha1.js new file mode 100644 index 000000000..d3c25659a --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/sha1.js @@ -0,0 +1,96 @@ +// Adapted from Chris Veness' SHA1 code at +// http://www.movable-type.co.uk/scripts/sha1.html +function f(s, x, y, z) { + switch (s) { + case 0: + return x & y ^ ~x & z; + + case 1: + return x ^ y ^ z; + + case 2: + return x & y ^ x & z ^ y & z; + + case 3: + return x ^ y ^ z; + } +} + +function ROTL(x, n) { + return x << n | x >>> 32 - n; +} + +function sha1(bytes) { + const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; + + if (typeof bytes === 'string') { + const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + + bytes = []; + + for (let i = 0; i < msg.length; ++i) { + bytes.push(msg.charCodeAt(i)); + } + } else if (!Array.isArray(bytes)) { + // Convert Array-like to Array + bytes = Array.prototype.slice.call(bytes); + } + + bytes.push(0x80); + const l = bytes.length / 4 + 2; + const N = Math.ceil(l / 16); + const M = new Array(N); + + for (let i = 0; i < N; ++i) { + const arr = new Uint32Array(16); + + for (let j = 0; j < 16; ++j) { + arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3]; + } + + M[i] = arr; + } + + M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); + M[N - 1][14] = Math.floor(M[N - 1][14]); + M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; + + for (let i = 0; i < N; ++i) { + const W = new Uint32Array(80); + + for (let t = 0; t < 16; ++t) { + W[t] = M[i][t]; + } + + for (let t = 16; t < 80; ++t) { + W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } + + let a = H[0]; + let b = H[1]; + let c = H[2]; + let d = H[3]; + let e = H[4]; + + for (let t = 0; t < 80; ++t) { + const s = Math.floor(t / 20); + const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0; + e = d; + d = c; + c = ROTL(b, 30) >>> 0; + b = a; + a = T; + } + + H[0] = H[0] + a >>> 0; + H[1] = H[1] + b >>> 0; + H[2] = H[2] + c >>> 0; + H[3] = H[3] + d >>> 0; + H[4] = H[4] + e >>> 0; + } + + return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; +} + +export default sha1; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/stringify.js b/node_modules/uuid/dist/esm-browser/stringify.js new file mode 100644 index 000000000..a6e4c8864 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/stringify.js @@ -0,0 +1,33 @@ +import validate from './validate.js'; +/** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ + +const byteToHex = []; + +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).slice(1)); +} + +export function unsafeStringify(arr, offset = 0) { + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; +} + +function stringify(arr, offset = 0) { + const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!validate(uuid)) { + throw TypeError('Stringified UUID is invalid'); + } + + return uuid; +} + +export default stringify; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/v1.js b/node_modules/uuid/dist/esm-browser/v1.js new file mode 100644 index 000000000..382e5d795 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/v1.js @@ -0,0 +1,95 @@ +import rng from './rng.js'; +import { unsafeStringify } from './stringify.js'; // **`v1()` - Generate time-based UUID** +// +// Inspired by https://github.com/LiosK/UUID.js +// and http://docs.python.org/library/uuid.html + +let _nodeId; + +let _clockseq; // Previous uuid creation time + + +let _lastMSecs = 0; +let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details + +function v1(options, buf, offset) { + let i = buf && offset || 0; + const b = buf || new Array(16); + options = options || {}; + let node = options.node || _nodeId; + let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not + // specified. We do this lazily to minimize issues related to insufficient + // system entropy. See #189 + + if (node == null || clockseq == null) { + const seedBytes = options.random || (options.rng || rng)(); + + if (node == null) { + // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) + node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; + } + + if (clockseq == null) { + // Per 4.2.2, randomize (14 bit) clockseq + clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; + } + } // UUID timestamps are 100 nano-second units since the Gregorian epoch, + // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so + // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' + // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. + + + let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock + // cycle to simulate higher resolution clock + + let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) + + const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression + + if (dt < 0 && options.clockseq === undefined) { + clockseq = clockseq + 1 & 0x3fff; + } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new + // time interval + + + if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { + nsecs = 0; + } // Per 4.2.1.2 Throw error if too many uuids are requested + + + if (nsecs >= 10000) { + throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); + } + + _lastMSecs = msecs; + _lastNSecs = nsecs; + _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch + + msecs += 12219292800000; // `time_low` + + const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; + b[i++] = tl >>> 24 & 0xff; + b[i++] = tl >>> 16 & 0xff; + b[i++] = tl >>> 8 & 0xff; + b[i++] = tl & 0xff; // `time_mid` + + const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; + b[i++] = tmh >>> 8 & 0xff; + b[i++] = tmh & 0xff; // `time_high_and_version` + + b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + + b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) + + b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` + + b[i++] = clockseq & 0xff; // `node` + + for (let n = 0; n < 6; ++n) { + b[i + n] = node[n]; + } + + return buf || unsafeStringify(b); +} + +export default v1; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/v3.js b/node_modules/uuid/dist/esm-browser/v3.js new file mode 100644 index 000000000..09063b860 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/v3.js @@ -0,0 +1,4 @@ +import v35 from './v35.js'; +import md5 from './md5.js'; +const v3 = v35('v3', 0x30, md5); +export default v3; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/v35.js b/node_modules/uuid/dist/esm-browser/v35.js new file mode 100644 index 000000000..3355e1f55 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/v35.js @@ -0,0 +1,66 @@ +import { unsafeStringify } from './stringify.js'; +import parse from './parse.js'; + +function stringToBytes(str) { + str = unescape(encodeURIComponent(str)); // UTF8 escape + + const bytes = []; + + for (let i = 0; i < str.length; ++i) { + bytes.push(str.charCodeAt(i)); + } + + return bytes; +} + +export const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; +export const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; +export default function v35(name, version, hashfunc) { + function generateUUID(value, namespace, buf, offset) { + var _namespace; + + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = parse(namespace); + } + + if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); + } // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + + + let bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); + bytes[6] = bytes[6] & 0x0f | version; + bytes[8] = bytes[8] & 0x3f | 0x80; + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; + } + + return buf; + } + + return unsafeStringify(bytes); + } // Function#name is not settable on some platforms (#270) + + + try { + generateUUID.name = name; // eslint-disable-next-line no-empty + } catch (err) {} // For CommonJS default export support + + + generateUUID.DNS = DNS; + generateUUID.URL = URL; + return generateUUID; +} \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/v4.js b/node_modules/uuid/dist/esm-browser/v4.js new file mode 100644 index 000000000..95ea87991 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/v4.js @@ -0,0 +1,29 @@ +import native from './native.js'; +import rng from './rng.js'; +import { unsafeStringify } from './stringify.js'; + +function v4(options, buf, offset) { + if (native.randomUUID && !buf && !options) { + return native.randomUUID(); + } + + options = options || {}; + const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + + return buf; + } + + return unsafeStringify(rnds); +} + +export default v4; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/v5.js b/node_modules/uuid/dist/esm-browser/v5.js new file mode 100644 index 000000000..e87fe317d --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/v5.js @@ -0,0 +1,4 @@ +import v35 from './v35.js'; +import sha1 from './sha1.js'; +const v5 = v35('v5', 0x50, sha1); +export default v5; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/validate.js b/node_modules/uuid/dist/esm-browser/validate.js new file mode 100644 index 000000000..f1cdc7af4 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/validate.js @@ -0,0 +1,7 @@ +import REGEX from './regex.js'; + +function validate(uuid) { + return typeof uuid === 'string' && REGEX.test(uuid); +} + +export default validate; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-browser/version.js b/node_modules/uuid/dist/esm-browser/version.js new file mode 100644 index 000000000..936307630 --- /dev/null +++ b/node_modules/uuid/dist/esm-browser/version.js @@ -0,0 +1,11 @@ +import validate from './validate.js'; + +function version(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + + return parseInt(uuid.slice(14, 15), 16); +} + +export default version; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/index.js b/node_modules/uuid/dist/esm-node/index.js new file mode 100644 index 000000000..1db6f6d25 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/index.js @@ -0,0 +1,9 @@ +export { default as v1 } from './v1.js'; +export { default as v3 } from './v3.js'; +export { default as v4 } from './v4.js'; +export { default as v5 } from './v5.js'; +export { default as NIL } from './nil.js'; +export { default as version } from './version.js'; +export { default as validate } from './validate.js'; +export { default as stringify } from './stringify.js'; +export { default as parse } from './parse.js'; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/md5.js b/node_modules/uuid/dist/esm-node/md5.js new file mode 100644 index 000000000..4d68b040f --- /dev/null +++ b/node_modules/uuid/dist/esm-node/md5.js @@ -0,0 +1,13 @@ +import crypto from 'crypto'; + +function md5(bytes) { + if (Array.isArray(bytes)) { + bytes = Buffer.from(bytes); + } else if (typeof bytes === 'string') { + bytes = Buffer.from(bytes, 'utf8'); + } + + return crypto.createHash('md5').update(bytes).digest(); +} + +export default md5; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/native.js b/node_modules/uuid/dist/esm-node/native.js new file mode 100644 index 000000000..f0d199261 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/native.js @@ -0,0 +1,4 @@ +import crypto from 'crypto'; +export default { + randomUUID: crypto.randomUUID +}; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/nil.js b/node_modules/uuid/dist/esm-node/nil.js new file mode 100644 index 000000000..b36324c2a --- /dev/null +++ b/node_modules/uuid/dist/esm-node/nil.js @@ -0,0 +1 @@ +export default '00000000-0000-0000-0000-000000000000'; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/parse.js b/node_modules/uuid/dist/esm-node/parse.js new file mode 100644 index 000000000..6421c5d5a --- /dev/null +++ b/node_modules/uuid/dist/esm-node/parse.js @@ -0,0 +1,35 @@ +import validate from './validate.js'; + +function parse(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + + let v; + const arr = new Uint8Array(16); // Parse ########-....-....-....-............ + + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = v >>> 16 & 0xff; + arr[2] = v >>> 8 & 0xff; + arr[3] = v & 0xff; // Parse ........-####-....-....-............ + + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; // Parse ........-....-####-....-............ + + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; // Parse ........-....-....-####-............ + + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + + arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; + arr[11] = v / 0x100000000 & 0xff; + arr[12] = v >>> 24 & 0xff; + arr[13] = v >>> 16 & 0xff; + arr[14] = v >>> 8 & 0xff; + arr[15] = v & 0xff; + return arr; +} + +export default parse; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/regex.js b/node_modules/uuid/dist/esm-node/regex.js new file mode 100644 index 000000000..3da8673a5 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/regex.js @@ -0,0 +1 @@ +export default /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/rng.js b/node_modules/uuid/dist/esm-node/rng.js new file mode 100644 index 000000000..80062449a --- /dev/null +++ b/node_modules/uuid/dist/esm-node/rng.js @@ -0,0 +1,12 @@ +import crypto from 'crypto'; +const rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate + +let poolPtr = rnds8Pool.length; +export default function rng() { + if (poolPtr > rnds8Pool.length - 16) { + crypto.randomFillSync(rnds8Pool); + poolPtr = 0; + } + + return rnds8Pool.slice(poolPtr, poolPtr += 16); +} \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/sha1.js b/node_modules/uuid/dist/esm-node/sha1.js new file mode 100644 index 000000000..e23850b44 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/sha1.js @@ -0,0 +1,13 @@ +import crypto from 'crypto'; + +function sha1(bytes) { + if (Array.isArray(bytes)) { + bytes = Buffer.from(bytes); + } else if (typeof bytes === 'string') { + bytes = Buffer.from(bytes, 'utf8'); + } + + return crypto.createHash('sha1').update(bytes).digest(); +} + +export default sha1; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/stringify.js b/node_modules/uuid/dist/esm-node/stringify.js new file mode 100644 index 000000000..a6e4c8864 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/stringify.js @@ -0,0 +1,33 @@ +import validate from './validate.js'; +/** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ + +const byteToHex = []; + +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).slice(1)); +} + +export function unsafeStringify(arr, offset = 0) { + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; +} + +function stringify(arr, offset = 0) { + const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!validate(uuid)) { + throw TypeError('Stringified UUID is invalid'); + } + + return uuid; +} + +export default stringify; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/v1.js b/node_modules/uuid/dist/esm-node/v1.js new file mode 100644 index 000000000..382e5d795 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/v1.js @@ -0,0 +1,95 @@ +import rng from './rng.js'; +import { unsafeStringify } from './stringify.js'; // **`v1()` - Generate time-based UUID** +// +// Inspired by https://github.com/LiosK/UUID.js +// and http://docs.python.org/library/uuid.html + +let _nodeId; + +let _clockseq; // Previous uuid creation time + + +let _lastMSecs = 0; +let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details + +function v1(options, buf, offset) { + let i = buf && offset || 0; + const b = buf || new Array(16); + options = options || {}; + let node = options.node || _nodeId; + let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not + // specified. We do this lazily to minimize issues related to insufficient + // system entropy. See #189 + + if (node == null || clockseq == null) { + const seedBytes = options.random || (options.rng || rng)(); + + if (node == null) { + // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) + node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; + } + + if (clockseq == null) { + // Per 4.2.2, randomize (14 bit) clockseq + clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; + } + } // UUID timestamps are 100 nano-second units since the Gregorian epoch, + // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so + // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' + // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. + + + let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock + // cycle to simulate higher resolution clock + + let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) + + const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression + + if (dt < 0 && options.clockseq === undefined) { + clockseq = clockseq + 1 & 0x3fff; + } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new + // time interval + + + if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { + nsecs = 0; + } // Per 4.2.1.2 Throw error if too many uuids are requested + + + if (nsecs >= 10000) { + throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); + } + + _lastMSecs = msecs; + _lastNSecs = nsecs; + _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch + + msecs += 12219292800000; // `time_low` + + const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; + b[i++] = tl >>> 24 & 0xff; + b[i++] = tl >>> 16 & 0xff; + b[i++] = tl >>> 8 & 0xff; + b[i++] = tl & 0xff; // `time_mid` + + const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; + b[i++] = tmh >>> 8 & 0xff; + b[i++] = tmh & 0xff; // `time_high_and_version` + + b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + + b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) + + b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` + + b[i++] = clockseq & 0xff; // `node` + + for (let n = 0; n < 6; ++n) { + b[i + n] = node[n]; + } + + return buf || unsafeStringify(b); +} + +export default v1; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/v3.js b/node_modules/uuid/dist/esm-node/v3.js new file mode 100644 index 000000000..09063b860 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/v3.js @@ -0,0 +1,4 @@ +import v35 from './v35.js'; +import md5 from './md5.js'; +const v3 = v35('v3', 0x30, md5); +export default v3; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/v35.js b/node_modules/uuid/dist/esm-node/v35.js new file mode 100644 index 000000000..3355e1f55 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/v35.js @@ -0,0 +1,66 @@ +import { unsafeStringify } from './stringify.js'; +import parse from './parse.js'; + +function stringToBytes(str) { + str = unescape(encodeURIComponent(str)); // UTF8 escape + + const bytes = []; + + for (let i = 0; i < str.length; ++i) { + bytes.push(str.charCodeAt(i)); + } + + return bytes; +} + +export const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; +export const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; +export default function v35(name, version, hashfunc) { + function generateUUID(value, namespace, buf, offset) { + var _namespace; + + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = parse(namespace); + } + + if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); + } // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + + + let bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); + bytes[6] = bytes[6] & 0x0f | version; + bytes[8] = bytes[8] & 0x3f | 0x80; + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; + } + + return buf; + } + + return unsafeStringify(bytes); + } // Function#name is not settable on some platforms (#270) + + + try { + generateUUID.name = name; // eslint-disable-next-line no-empty + } catch (err) {} // For CommonJS default export support + + + generateUUID.DNS = DNS; + generateUUID.URL = URL; + return generateUUID; +} \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/v4.js b/node_modules/uuid/dist/esm-node/v4.js new file mode 100644 index 000000000..95ea87991 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/v4.js @@ -0,0 +1,29 @@ +import native from './native.js'; +import rng from './rng.js'; +import { unsafeStringify } from './stringify.js'; + +function v4(options, buf, offset) { + if (native.randomUUID && !buf && !options) { + return native.randomUUID(); + } + + options = options || {}; + const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + + return buf; + } + + return unsafeStringify(rnds); +} + +export default v4; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/v5.js b/node_modules/uuid/dist/esm-node/v5.js new file mode 100644 index 000000000..e87fe317d --- /dev/null +++ b/node_modules/uuid/dist/esm-node/v5.js @@ -0,0 +1,4 @@ +import v35 from './v35.js'; +import sha1 from './sha1.js'; +const v5 = v35('v5', 0x50, sha1); +export default v5; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/validate.js b/node_modules/uuid/dist/esm-node/validate.js new file mode 100644 index 000000000..f1cdc7af4 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/validate.js @@ -0,0 +1,7 @@ +import REGEX from './regex.js'; + +function validate(uuid) { + return typeof uuid === 'string' && REGEX.test(uuid); +} + +export default validate; \ No newline at end of file diff --git a/node_modules/uuid/dist/esm-node/version.js b/node_modules/uuid/dist/esm-node/version.js new file mode 100644 index 000000000..936307630 --- /dev/null +++ b/node_modules/uuid/dist/esm-node/version.js @@ -0,0 +1,11 @@ +import validate from './validate.js'; + +function version(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); + } + + return parseInt(uuid.slice(14, 15), 16); +} + +export default version; \ No newline at end of file diff --git a/node_modules/uuid/dist/index.js b/node_modules/uuid/dist/index.js new file mode 100644 index 000000000..88d676a29 --- /dev/null +++ b/node_modules/uuid/dist/index.js @@ -0,0 +1,79 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +Object.defineProperty(exports, "NIL", { + enumerable: true, + get: function () { + return _nil.default; + } +}); +Object.defineProperty(exports, "parse", { + enumerable: true, + get: function () { + return _parse.default; + } +}); +Object.defineProperty(exports, "stringify", { + enumerable: true, + get: function () { + return _stringify.default; + } +}); +Object.defineProperty(exports, "v1", { + enumerable: true, + get: function () { + return _v.default; + } +}); +Object.defineProperty(exports, "v3", { + enumerable: true, + get: function () { + return _v2.default; + } +}); +Object.defineProperty(exports, "v4", { + enumerable: true, + get: function () { + return _v3.default; + } +}); +Object.defineProperty(exports, "v5", { + enumerable: true, + get: function () { + return _v4.default; + } +}); +Object.defineProperty(exports, "validate", { + enumerable: true, + get: function () { + return _validate.default; + } +}); +Object.defineProperty(exports, "version", { + enumerable: true, + get: function () { + return _version.default; + } +}); + +var _v = _interopRequireDefault(require("./v1.js")); + +var _v2 = _interopRequireDefault(require("./v3.js")); + +var _v3 = _interopRequireDefault(require("./v4.js")); + +var _v4 = _interopRequireDefault(require("./v5.js")); + +var _nil = _interopRequireDefault(require("./nil.js")); + +var _version = _interopRequireDefault(require("./version.js")); + +var _validate = _interopRequireDefault(require("./validate.js")); + +var _stringify = _interopRequireDefault(require("./stringify.js")); + +var _parse = _interopRequireDefault(require("./parse.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } \ No newline at end of file diff --git a/node_modules/uuid/dist/md5-browser.js b/node_modules/uuid/dist/md5-browser.js new file mode 100644 index 000000000..7a4582ace --- /dev/null +++ b/node_modules/uuid/dist/md5-browser.js @@ -0,0 +1,223 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +/* + * Browser-compatible JavaScript MD5 + * + * Modification of JavaScript MD5 + * https://github.com/blueimp/JavaScript-MD5 + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * https://opensource.org/licenses/MIT + * + * Based on + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ +function md5(bytes) { + if (typeof bytes === 'string') { + const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + + bytes = new Uint8Array(msg.length); + + for (let i = 0; i < msg.length; ++i) { + bytes[i] = msg.charCodeAt(i); + } + } + + return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8)); +} +/* + * Convert an array of little-endian words to an array of bytes + */ + + +function md5ToHexEncodedArray(input) { + const output = []; + const length32 = input.length * 32; + const hexTab = '0123456789abcdef'; + + for (let i = 0; i < length32; i += 8) { + const x = input[i >> 5] >>> i % 32 & 0xff; + const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16); + output.push(hex); + } + + return output; +} +/** + * Calculate output length with padding and bit length + */ + + +function getOutputLength(inputLength8) { + return (inputLength8 + 64 >>> 9 << 4) + 14 + 1; +} +/* + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ + + +function wordsToMd5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[getOutputLength(len) - 1] = len; + let a = 1732584193; + let b = -271733879; + let c = -1732584194; + let d = 271733878; + + for (let i = 0; i < x.length; i += 16) { + const olda = a; + const oldb = b; + const oldc = c; + const oldd = d; + a = md5ff(a, b, c, d, x[i], 7, -680876936); + d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); + a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5gg(b, c, d, a, x[i], 20, -373897302); + a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); + a = md5hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5hh(d, a, b, c, x[i], 11, -358537222); + c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); + a = md5ii(a, b, c, d, x[i], 6, -198630844); + d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); + a = safeAdd(a, olda); + b = safeAdd(b, oldb); + c = safeAdd(c, oldc); + d = safeAdd(d, oldd); + } + + return [a, b, c, d]; +} +/* + * Convert an array bytes to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ + + +function bytesToWords(input) { + if (input.length === 0) { + return []; + } + + const length8 = input.length * 8; + const output = new Uint32Array(getOutputLength(length8)); + + for (let i = 0; i < length8; i += 8) { + output[i >> 5] |= (input[i / 8] & 0xff) << i % 32; + } + + return output; +} +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ + + +function safeAdd(x, y) { + const lsw = (x & 0xffff) + (y & 0xffff); + const msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return msw << 16 | lsw & 0xffff; +} +/* + * Bitwise rotate a 32-bit number to the left. + */ + + +function bitRotateLeft(num, cnt) { + return num << cnt | num >>> 32 - cnt; +} +/* + * These functions implement the four basic operations the algorithm uses. + */ + + +function md5cmn(q, a, b, x, s, t) { + return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); +} + +function md5ff(a, b, c, d, x, s, t) { + return md5cmn(b & c | ~b & d, a, b, x, s, t); +} + +function md5gg(a, b, c, d, x, s, t) { + return md5cmn(b & d | c & ~d, a, b, x, s, t); +} + +function md5hh(a, b, c, d, x, s, t) { + return md5cmn(b ^ c ^ d, a, b, x, s, t); +} + +function md5ii(a, b, c, d, x, s, t) { + return md5cmn(c ^ (b | ~d), a, b, x, s, t); +} + +var _default = md5; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/md5.js b/node_modules/uuid/dist/md5.js new file mode 100644 index 000000000..824d48167 --- /dev/null +++ b/node_modules/uuid/dist/md5.js @@ -0,0 +1,23 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _crypto = _interopRequireDefault(require("crypto")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function md5(bytes) { + if (Array.isArray(bytes)) { + bytes = Buffer.from(bytes); + } else if (typeof bytes === 'string') { + bytes = Buffer.from(bytes, 'utf8'); + } + + return _crypto.default.createHash('md5').update(bytes).digest(); +} + +var _default = md5; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/native-browser.js b/node_modules/uuid/dist/native-browser.js new file mode 100644 index 000000000..c2eea59d0 --- /dev/null +++ b/node_modules/uuid/dist/native-browser.js @@ -0,0 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto); +var _default = { + randomUUID +}; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/native.js b/node_modules/uuid/dist/native.js new file mode 100644 index 000000000..de8046913 --- /dev/null +++ b/node_modules/uuid/dist/native.js @@ -0,0 +1,15 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _crypto = _interopRequireDefault(require("crypto")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var _default = { + randomUUID: _crypto.default.randomUUID +}; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/nil.js b/node_modules/uuid/dist/nil.js new file mode 100644 index 000000000..7ade577b2 --- /dev/null +++ b/node_modules/uuid/dist/nil.js @@ -0,0 +1,8 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _default = '00000000-0000-0000-0000-000000000000'; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/parse.js b/node_modules/uuid/dist/parse.js new file mode 100644 index 000000000..4c69fc39e --- /dev/null +++ b/node_modules/uuid/dist/parse.js @@ -0,0 +1,45 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _validate = _interopRequireDefault(require("./validate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function parse(uuid) { + if (!(0, _validate.default)(uuid)) { + throw TypeError('Invalid UUID'); + } + + let v; + const arr = new Uint8Array(16); // Parse ########-....-....-....-............ + + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = v >>> 16 & 0xff; + arr[2] = v >>> 8 & 0xff; + arr[3] = v & 0xff; // Parse ........-####-....-....-............ + + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; // Parse ........-....-####-....-............ + + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; // Parse ........-....-....-####-............ + + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + + arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; + arr[11] = v / 0x100000000 & 0xff; + arr[12] = v >>> 24 & 0xff; + arr[13] = v >>> 16 & 0xff; + arr[14] = v >>> 8 & 0xff; + arr[15] = v & 0xff; + return arr; +} + +var _default = parse; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/regex.js b/node_modules/uuid/dist/regex.js new file mode 100644 index 000000000..1ef91d64c --- /dev/null +++ b/node_modules/uuid/dist/regex.js @@ -0,0 +1,8 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/rng-browser.js b/node_modules/uuid/dist/rng-browser.js new file mode 100644 index 000000000..d067cdb04 --- /dev/null +++ b/node_modules/uuid/dist/rng-browser.js @@ -0,0 +1,25 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = rng; +// Unique ID creation requires a high quality random # generator. In the browser we therefore +// require the crypto API and do not support built-in fallback to lower quality random number +// generators (like Math.random()). +let getRandomValues; +const rnds8 = new Uint8Array(16); + +function rng() { + // lazy load so that environments that need to polyfill have a chance to do so + if (!getRandomValues) { + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. + getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto); + + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); + } + } + + return getRandomValues(rnds8); +} \ No newline at end of file diff --git a/node_modules/uuid/dist/rng.js b/node_modules/uuid/dist/rng.js new file mode 100644 index 000000000..3507f9377 --- /dev/null +++ b/node_modules/uuid/dist/rng.js @@ -0,0 +1,24 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = rng; + +var _crypto = _interopRequireDefault(require("crypto")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate + +let poolPtr = rnds8Pool.length; + +function rng() { + if (poolPtr > rnds8Pool.length - 16) { + _crypto.default.randomFillSync(rnds8Pool); + + poolPtr = 0; + } + + return rnds8Pool.slice(poolPtr, poolPtr += 16); +} \ No newline at end of file diff --git a/node_modules/uuid/dist/sha1-browser.js b/node_modules/uuid/dist/sha1-browser.js new file mode 100644 index 000000000..24cbcedca --- /dev/null +++ b/node_modules/uuid/dist/sha1-browser.js @@ -0,0 +1,104 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +// Adapted from Chris Veness' SHA1 code at +// http://www.movable-type.co.uk/scripts/sha1.html +function f(s, x, y, z) { + switch (s) { + case 0: + return x & y ^ ~x & z; + + case 1: + return x ^ y ^ z; + + case 2: + return x & y ^ x & z ^ y & z; + + case 3: + return x ^ y ^ z; + } +} + +function ROTL(x, n) { + return x << n | x >>> 32 - n; +} + +function sha1(bytes) { + const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; + + if (typeof bytes === 'string') { + const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + + bytes = []; + + for (let i = 0; i < msg.length; ++i) { + bytes.push(msg.charCodeAt(i)); + } + } else if (!Array.isArray(bytes)) { + // Convert Array-like to Array + bytes = Array.prototype.slice.call(bytes); + } + + bytes.push(0x80); + const l = bytes.length / 4 + 2; + const N = Math.ceil(l / 16); + const M = new Array(N); + + for (let i = 0; i < N; ++i) { + const arr = new Uint32Array(16); + + for (let j = 0; j < 16; ++j) { + arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3]; + } + + M[i] = arr; + } + + M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); + M[N - 1][14] = Math.floor(M[N - 1][14]); + M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; + + for (let i = 0; i < N; ++i) { + const W = new Uint32Array(80); + + for (let t = 0; t < 16; ++t) { + W[t] = M[i][t]; + } + + for (let t = 16; t < 80; ++t) { + W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1); + } + + let a = H[0]; + let b = H[1]; + let c = H[2]; + let d = H[3]; + let e = H[4]; + + for (let t = 0; t < 80; ++t) { + const s = Math.floor(t / 20); + const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0; + e = d; + d = c; + c = ROTL(b, 30) >>> 0; + b = a; + a = T; + } + + H[0] = H[0] + a >>> 0; + H[1] = H[1] + b >>> 0; + H[2] = H[2] + c >>> 0; + H[3] = H[3] + d >>> 0; + H[4] = H[4] + e >>> 0; + } + + return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; +} + +var _default = sha1; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/sha1.js b/node_modules/uuid/dist/sha1.js new file mode 100644 index 000000000..03bdd63ce --- /dev/null +++ b/node_modules/uuid/dist/sha1.js @@ -0,0 +1,23 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _crypto = _interopRequireDefault(require("crypto")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function sha1(bytes) { + if (Array.isArray(bytes)) { + bytes = Buffer.from(bytes); + } else if (typeof bytes === 'string') { + bytes = Buffer.from(bytes, 'utf8'); + } + + return _crypto.default.createHash('sha1').update(bytes).digest(); +} + +var _default = sha1; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/stringify.js b/node_modules/uuid/dist/stringify.js new file mode 100644 index 000000000..390bf8918 --- /dev/null +++ b/node_modules/uuid/dist/stringify.js @@ -0,0 +1,44 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +exports.unsafeStringify = unsafeStringify; + +var _validate = _interopRequireDefault(require("./validate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + */ +const byteToHex = []; + +for (let i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).slice(1)); +} + +function unsafeStringify(arr, offset = 0) { + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]; +} + +function stringify(arr, offset = 0) { + const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!(0, _validate.default)(uuid)) { + throw TypeError('Stringified UUID is invalid'); + } + + return uuid; +} + +var _default = stringify; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/uuid-bin.js b/node_modules/uuid/dist/uuid-bin.js new file mode 100644 index 000000000..50a7a9f17 --- /dev/null +++ b/node_modules/uuid/dist/uuid-bin.js @@ -0,0 +1,85 @@ +"use strict"; + +var _assert = _interopRequireDefault(require("assert")); + +var _v = _interopRequireDefault(require("./v1.js")); + +var _v2 = _interopRequireDefault(require("./v3.js")); + +var _v3 = _interopRequireDefault(require("./v4.js")); + +var _v4 = _interopRequireDefault(require("./v5.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function usage() { + console.log('Usage:'); + console.log(' uuid'); + console.log(' uuid v1'); + console.log(' uuid v3 '); + console.log(' uuid v4'); + console.log(' uuid v5 '); + console.log(' uuid --help'); + console.log('\nNote: may be "URL" or "DNS" to use the corresponding UUIDs defined by RFC4122'); +} + +const args = process.argv.slice(2); + +if (args.indexOf('--help') >= 0) { + usage(); + process.exit(0); +} + +const version = args.shift() || 'v4'; + +switch (version) { + case 'v1': + console.log((0, _v.default)()); + break; + + case 'v3': + { + const name = args.shift(); + let namespace = args.shift(); + (0, _assert.default)(name != null, 'v3 name not specified'); + (0, _assert.default)(namespace != null, 'v3 namespace not specified'); + + if (namespace === 'URL') { + namespace = _v2.default.URL; + } + + if (namespace === 'DNS') { + namespace = _v2.default.DNS; + } + + console.log((0, _v2.default)(name, namespace)); + break; + } + + case 'v4': + console.log((0, _v3.default)()); + break; + + case 'v5': + { + const name = args.shift(); + let namespace = args.shift(); + (0, _assert.default)(name != null, 'v5 name not specified'); + (0, _assert.default)(namespace != null, 'v5 namespace not specified'); + + if (namespace === 'URL') { + namespace = _v4.default.URL; + } + + if (namespace === 'DNS') { + namespace = _v4.default.DNS; + } + + console.log((0, _v4.default)(name, namespace)); + break; + } + + default: + usage(); + process.exit(1); +} \ No newline at end of file diff --git a/node_modules/uuid/dist/v1.js b/node_modules/uuid/dist/v1.js new file mode 100644 index 000000000..125bc58f7 --- /dev/null +++ b/node_modules/uuid/dist/v1.js @@ -0,0 +1,107 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _rng = _interopRequireDefault(require("./rng.js")); + +var _stringify = require("./stringify.js"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +// **`v1()` - Generate time-based UUID** +// +// Inspired by https://github.com/LiosK/UUID.js +// and http://docs.python.org/library/uuid.html +let _nodeId; + +let _clockseq; // Previous uuid creation time + + +let _lastMSecs = 0; +let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details + +function v1(options, buf, offset) { + let i = buf && offset || 0; + const b = buf || new Array(16); + options = options || {}; + let node = options.node || _nodeId; + let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not + // specified. We do this lazily to minimize issues related to insufficient + // system entropy. See #189 + + if (node == null || clockseq == null) { + const seedBytes = options.random || (options.rng || _rng.default)(); + + if (node == null) { + // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) + node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; + } + + if (clockseq == null) { + // Per 4.2.2, randomize (14 bit) clockseq + clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; + } + } // UUID timestamps are 100 nano-second units since the Gregorian epoch, + // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so + // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' + // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. + + + let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock + // cycle to simulate higher resolution clock + + let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) + + const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression + + if (dt < 0 && options.clockseq === undefined) { + clockseq = clockseq + 1 & 0x3fff; + } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new + // time interval + + + if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { + nsecs = 0; + } // Per 4.2.1.2 Throw error if too many uuids are requested + + + if (nsecs >= 10000) { + throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); + } + + _lastMSecs = msecs; + _lastNSecs = nsecs; + _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch + + msecs += 12219292800000; // `time_low` + + const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; + b[i++] = tl >>> 24 & 0xff; + b[i++] = tl >>> 16 & 0xff; + b[i++] = tl >>> 8 & 0xff; + b[i++] = tl & 0xff; // `time_mid` + + const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; + b[i++] = tmh >>> 8 & 0xff; + b[i++] = tmh & 0xff; // `time_high_and_version` + + b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + + b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) + + b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` + + b[i++] = clockseq & 0xff; // `node` + + for (let n = 0; n < 6; ++n) { + b[i + n] = node[n]; + } + + return buf || (0, _stringify.unsafeStringify)(b); +} + +var _default = v1; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/v3.js b/node_modules/uuid/dist/v3.js new file mode 100644 index 000000000..6b47ff517 --- /dev/null +++ b/node_modules/uuid/dist/v3.js @@ -0,0 +1,16 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _v = _interopRequireDefault(require("./v35.js")); + +var _md = _interopRequireDefault(require("./md5.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const v3 = (0, _v.default)('v3', 0x30, _md.default); +var _default = v3; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/v35.js b/node_modules/uuid/dist/v35.js new file mode 100644 index 000000000..7c522d97a --- /dev/null +++ b/node_modules/uuid/dist/v35.js @@ -0,0 +1,80 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.URL = exports.DNS = void 0; +exports.default = v35; + +var _stringify = require("./stringify.js"); + +var _parse = _interopRequireDefault(require("./parse.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function stringToBytes(str) { + str = unescape(encodeURIComponent(str)); // UTF8 escape + + const bytes = []; + + for (let i = 0; i < str.length; ++i) { + bytes.push(str.charCodeAt(i)); + } + + return bytes; +} + +const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; +exports.DNS = DNS; +const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; +exports.URL = URL; + +function v35(name, version, hashfunc) { + function generateUUID(value, namespace, buf, offset) { + var _namespace; + + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = (0, _parse.default)(namespace); + } + + if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); + } // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + + + let bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); + bytes[6] = bytes[6] & 0x0f | version; + bytes[8] = bytes[8] & 0x3f | 0x80; + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; + } + + return buf; + } + + return (0, _stringify.unsafeStringify)(bytes); + } // Function#name is not settable on some platforms (#270) + + + try { + generateUUID.name = name; // eslint-disable-next-line no-empty + } catch (err) {} // For CommonJS default export support + + + generateUUID.DNS = DNS; + generateUUID.URL = URL; + return generateUUID; +} \ No newline at end of file diff --git a/node_modules/uuid/dist/v4.js b/node_modules/uuid/dist/v4.js new file mode 100644 index 000000000..959d69869 --- /dev/null +++ b/node_modules/uuid/dist/v4.js @@ -0,0 +1,43 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _native = _interopRequireDefault(require("./native.js")); + +var _rng = _interopRequireDefault(require("./rng.js")); + +var _stringify = require("./stringify.js"); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function v4(options, buf, offset) { + if (_native.default.randomUUID && !buf && !options) { + return _native.default.randomUUID(); + } + + options = options || {}; + + const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (let i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; + } + + return buf; + } + + return (0, _stringify.unsafeStringify)(rnds); +} + +var _default = v4; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/v5.js b/node_modules/uuid/dist/v5.js new file mode 100644 index 000000000..99d615e09 --- /dev/null +++ b/node_modules/uuid/dist/v5.js @@ -0,0 +1,16 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _v = _interopRequireDefault(require("./v35.js")); + +var _sha = _interopRequireDefault(require("./sha1.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const v5 = (0, _v.default)('v5', 0x50, _sha.default); +var _default = v5; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/validate.js b/node_modules/uuid/dist/validate.js new file mode 100644 index 000000000..fd052157d --- /dev/null +++ b/node_modules/uuid/dist/validate.js @@ -0,0 +1,17 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _regex = _interopRequireDefault(require("./regex.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function validate(uuid) { + return typeof uuid === 'string' && _regex.default.test(uuid); +} + +var _default = validate; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/dist/version.js b/node_modules/uuid/dist/version.js new file mode 100644 index 000000000..f63af01ad --- /dev/null +++ b/node_modules/uuid/dist/version.js @@ -0,0 +1,21 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _validate = _interopRequireDefault(require("./validate.js")); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function version(uuid) { + if (!(0, _validate.default)(uuid)) { + throw TypeError('Invalid UUID'); + } + + return parseInt(uuid.slice(14, 15), 16); +} + +var _default = version; +exports.default = _default; \ No newline at end of file diff --git a/node_modules/uuid/package.json b/node_modules/uuid/package.json new file mode 100644 index 000000000..6cc33618c --- /dev/null +++ b/node_modules/uuid/package.json @@ -0,0 +1,135 @@ +{ + "name": "uuid", + "version": "9.0.1", + "description": "RFC4122 (v1, v4, and v5) UUIDs", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "commitlint": { + "extends": [ + "@commitlint/config-conventional" + ] + }, + "keywords": [ + "uuid", + "guid", + "rfc4122" + ], + "license": "MIT", + "bin": { + "uuid": "./dist/bin/uuid" + }, + "sideEffects": false, + "main": "./dist/index.js", + "exports": { + ".": { + "node": { + "module": "./dist/esm-node/index.js", + "require": "./dist/index.js", + "import": "./wrapper.mjs" + }, + "browser": { + "import": "./dist/esm-browser/index.js", + "require": "./dist/commonjs-browser/index.js" + }, + "default": "./dist/esm-browser/index.js" + }, + "./package.json": "./package.json" + }, + "module": "./dist/esm-node/index.js", + "browser": { + "./dist/md5.js": "./dist/md5-browser.js", + "./dist/native.js": "./dist/native-browser.js", + "./dist/rng.js": "./dist/rng-browser.js", + "./dist/sha1.js": "./dist/sha1-browser.js", + "./dist/esm-node/index.js": "./dist/esm-browser/index.js" + }, + "files": [ + "CHANGELOG.md", + "CONTRIBUTING.md", + "LICENSE.md", + "README.md", + "dist", + "wrapper.mjs" + ], + "devDependencies": { + "@babel/cli": "7.18.10", + "@babel/core": "7.18.10", + "@babel/eslint-parser": "7.18.9", + "@babel/preset-env": "7.18.10", + "@commitlint/cli": "17.0.3", + "@commitlint/config-conventional": "17.0.3", + "bundlewatch": "0.3.3", + "eslint": "8.21.0", + "eslint-config-prettier": "8.5.0", + "eslint-config-standard": "17.0.0", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-prettier": "4.2.1", + "eslint-plugin-promise": "6.0.0", + "husky": "8.0.1", + "jest": "28.1.3", + "lint-staged": "13.0.3", + "npm-run-all": "4.1.5", + "optional-dev-dependency": "2.0.1", + "prettier": "2.7.1", + "random-seed": "0.3.0", + "runmd": "1.3.9", + "standard-version": "9.5.0" + }, + "optionalDevDependencies": { + "@wdio/browserstack-service": "7.16.10", + "@wdio/cli": "7.16.10", + "@wdio/jasmine-framework": "7.16.6", + "@wdio/local-runner": "7.16.10", + "@wdio/spec-reporter": "7.16.9", + "@wdio/static-server-service": "7.16.6" + }, + "scripts": { + "examples:browser:webpack:build": "cd examples/browser-webpack && npm install && npm run build", + "examples:browser:rollup:build": "cd examples/browser-rollup && npm install && npm run build", + "examples:node:commonjs:test": "cd examples/node-commonjs && npm install && npm test", + "examples:node:esmodules:test": "cd examples/node-esmodules && npm install && npm test", + "examples:node:jest:test": "cd examples/node-jest && npm install && npm test", + "prepare": "cd $( git rev-parse --show-toplevel ) && husky install", + "lint": "npm run eslint:check && npm run prettier:check", + "eslint:check": "eslint src/ test/ examples/ *.js", + "eslint:fix": "eslint --fix src/ test/ examples/ *.js", + "pretest": "[ -n $CI ] || npm run build", + "test": "BABEL_ENV=commonjsNode node --throw-deprecation node_modules/.bin/jest test/unit/", + "pretest:browser": "optional-dev-dependency && npm run build && npm-run-all --parallel examples:browser:**", + "test:browser": "wdio run ./wdio.conf.js", + "pretest:node": "npm run build", + "test:node": "npm-run-all --parallel examples:node:**", + "test:pack": "./scripts/testpack.sh", + "pretest:benchmark": "npm run build", + "test:benchmark": "cd examples/benchmark && npm install && npm test", + "prettier:check": "prettier --check '**/*.{js,jsx,json,md}'", + "prettier:fix": "prettier --write '**/*.{js,jsx,json,md}'", + "bundlewatch": "npm run pretest:browser && bundlewatch --config bundlewatch.config.json", + "md": "runmd --watch --output=README.md README_js.md", + "docs": "( node --version | grep -q 'v18' ) && ( npm run build && npx runmd --output=README.md README_js.md )", + "docs:diff": "npm run docs && git diff --quiet README.md", + "build": "./scripts/build.sh", + "prepack": "npm run build", + "release": "standard-version --no-verify" + }, + "repository": { + "type": "git", + "url": "https://github.com/uuidjs/uuid.git" + }, + "lint-staged": { + "*.{js,jsx,json,md}": [ + "prettier --write" + ], + "*.{js,jsx}": [ + "eslint --fix" + ] + }, + "standard-version": { + "scripts": { + "postchangelog": "prettier --write CHANGELOG.md" + } + } +} diff --git a/node_modules/uuid/wrapper.mjs b/node_modules/uuid/wrapper.mjs new file mode 100644 index 000000000..c31e9cef4 --- /dev/null +++ b/node_modules/uuid/wrapper.mjs @@ -0,0 +1,10 @@ +import uuid from './dist/index.js'; +export const v1 = uuid.v1; +export const v3 = uuid.v3; +export const v4 = uuid.v4; +export const v5 = uuid.v5; +export const NIL = uuid.NIL; +export const version = uuid.version; +export const validate = uuid.validate; +export const stringify = uuid.stringify; +export const parse = uuid.parse; diff --git a/package.json b/package.json new file mode 100644 index 000000000..7c18dc8fa --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "uuid": "^9.0.1" + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..7b075058f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== From 5017338e4debf346eefc831b1de5310a56e7863c Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Mon, 9 Oct 2023 11:08:42 +0300 Subject: [PATCH 13/43] renaming refactoring of the components --- .../videoControlButton.tsx | 0 .../meetingComp}/videoControllerComp.tsx | 70 +----- .../videoStreamComp.tsx} | 102 -------- .../videobuttonCompConstants.tsx | 0 .../comps/comps/videoComp/videoContolComp.tsx | 226 ------------------ .../lowcoder/src/comps/hooks/hookComp.tsx | 2 +- client/packages/lowcoder/src/comps/index.tsx | 6 +- 7 files changed, 10 insertions(+), 396 deletions(-) rename client/packages/lowcoder/src/comps/comps/{videoComp => meetingComp}/videoControlButton.tsx (100%) rename client/packages/lowcoder/src/comps/{hooks => comps/meetingComp}/videoControllerComp.tsx (87%) rename client/packages/lowcoder/src/comps/comps/{videoComp/videoMeetingComp.tsx => meetingComp/videoStreamComp.tsx} (63%) rename client/packages/lowcoder/src/comps/comps/{videoComp => meetingComp}/videobuttonCompConstants.tsx (100%) delete mode 100644 client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoControlButton.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoControlButton.tsx similarity index 100% rename from client/packages/lowcoder/src/comps/comps/videoComp/videoControlButton.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/videoControlButton.tsx diff --git a/client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoControllerComp.tsx similarity index 87% rename from client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/videoControllerComp.tsx index f5cb68aca..74ba992ad 100644 --- a/client/packages/lowcoder/src/comps/hooks/videoControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoControllerComp.tsx @@ -8,12 +8,9 @@ import { import { AutoHeightControl } from "comps/controls/autoHeightControl"; import { BoolControl } from "comps/controls/boolControl"; import { - JSONObjectArrayControl, - NumberControl, StringControl, } from "comps/controls/codeControl"; import { - arrayStringExposingStateControl, booleanExposingStateControl, jsonObjectExposingStateControl, jsonValueExposingStateControl, @@ -39,22 +36,19 @@ import { Section, sectionNames, } from "lowcoder-design"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect } from "react"; import { ResizeHandle } from "react-resizable"; import styled from "styled-components"; import { useUserViewMode } from "util/hooks"; import { isNumeric } from "util/stringUtils"; -import { NameConfig, withExposingConfigs } from "../generators/withExposing"; -import { v4 as uuidv4 } from "uuid"; +import { NameConfig, withExposingConfigs } from "../../generators/withExposing"; import AgoraRTC, { ICameraVideoTrack, IMicrophoneAudioTrack, IAgoraRTCClient, IAgoraRTCRemoteUser, - IRemoteVideoTrack, } from "agora-rtc-sdk-ng"; -import { JSONObject } from "@lowcoder-ee/index.sdk"; const EventOptions = [closeEvent] as const; @@ -100,24 +94,6 @@ function transToPxSize(size: string | number) { return isNumeric(size) ? size + "px" : (size as string); } -const PlacementOptions = [ - { - label: trans("drawer.top"), - value: "top", - }, - { - label: trans("drawer.right"), - value: "right", - }, - { - label: trans("drawer.bottom"), - value: "bottom", - }, - { - label: trans("drawer.left"), - value: "left", - }, -] as const; let client: IAgoraRTCClient = AgoraRTC.createClient({ mode: "rtc", @@ -144,8 +120,6 @@ const turnOnMicrophone = async (flag?: boolean) => { }; const leaveChannel = async () => { - console.log("isJoined", isJoined); - if (!client) { console.error("Agora client is not initialized"); return; @@ -156,19 +130,19 @@ const leaveChannel = async () => { return; } if (videoTrack) { - // await turnOnCamera(false); + await turnOnCamera(false); await client.unpublish(videoTrack); videoTrack.stop(); } if (audioTrack) { - // await turnOnMicrophone(false); + await turnOnMicrophone(false); await client.unpublish(audioTrack); audioTrack.stop(); } await client.leave(); - isJoined = false; // Update the flag to indicate that you have left the channel + isJoined = false; }; let isJoined = false; @@ -181,8 +155,6 @@ const joinChannel = async (appId: any, channel: any, token: any) => { await leaveChannel(); } - // client.on("user-published", onUserPublish); - await client.join( appId, channel, @@ -194,7 +166,6 @@ const joinChannel = async (appId: any, channel: any, token: any) => { }; const publishVideo = async (appId: any, channel: any, height: any) => { - console.log("publishVideo", appId, channel, isJoined); await turnOnCamera(true); console.log(appId, channel); @@ -202,11 +173,7 @@ const publishVideo = async (appId: any, channel: any, height: any) => { await joinChannel(appId, channel, null); } - console.log("publish videoTrack ", videoTrack); - await client.publish(videoTrack); - - // turnOnCamera(true); const mediaStreamTrack = videoTrack.getMediaStreamTrack(); if (mediaStreamTrack) { @@ -276,16 +243,12 @@ let MTComp = (function () { [dispatch, isTopBom] ); - const usersWithVideoTracks: any = {}; - useEffect(() => { console.log("nnnn ", props.participants); }, [props.participants.value]); useEffect(() => { if (client) { - console.log("REGISTERING LISTNERS"); - client.on( "user-published", async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { @@ -297,26 +260,10 @@ let MTComp = (function () { const remoteTrack = await client.subscribe(user, mediaType); remoteTrack.play(); } - const remoteVideoTrack = user.videoTrack; - if (remoteVideoTrack) { - props.participants.onChange([JSON.stringify(user.uid)]); - console.log("usersWithVideoTracks", props.participants); - } } ); - client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - // usersWithVideoTracks[user.uid] = { user, videoTracks: [] }; - // props.participants.onChange(usersWithVideoTracks); - // console.log( - // "userJoined", - // user.uid, - // props.participants.value, - // usersWithVideoTracks - // ); - // const uid = user.uid; - // usersWithVideoTracks[uid] = { user, videoTracks: [] }; - }); + client.on("user-joined", (user: IAgoraRTCRemoteUser) => {}); client.on("user-offline", (uid: any, reason: any) => { console.log(`User ${uid} left the channel.`); }); @@ -328,13 +275,8 @@ let MTComp = (function () { }); client.on("stream-added", (user: IAgoraRTCRemoteUser) => { console.log("stream-added"); - - if (user.hasVideo) { - console.log(`Stream from user ${user.videoTrack} added.`); - } }); } - // turnOnCamera(true); }, [client]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoStreamComp.tsx similarity index 63% rename from client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/videoStreamComp.tsx index 9892499d0..67e687277 100644 --- a/client/packages/lowcoder/src/comps/comps/videoComp/videoMeetingComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoStreamComp.tsx @@ -165,19 +165,12 @@ let VideoCompBuilder = (function (props) { suffixIcon: IconControl, style: ButtonStyleControl, viewRef: RefControl, - appId: withDefault(StringControl, trans("prop.appid")), /// - videokey: withDefault(StringControl, trans("prop.videokey")), - participants: arrayStringExposingStateControl("participants"), userId: stringExposingStateControl( "text", trans("meeting.userId", { name: "{{currentUser.name}}" }) ), }; - // const { client, videoHeight, videoWidth, setHeight, setWidth } = useAgora(); - return new UICompBuilder(childrenMap, (props) => { - console.log("userId", props.userId.value); - // "afd10eabe68a4de68a76461be92c693c" const videoRef = useRef(null); const conRef = useRef(null); @@ -185,11 +178,6 @@ let VideoCompBuilder = (function (props) { onResize(); }, []); - useEffect(() => { - if (props.participants.value.length > 0) { - console.log("bbb", props.participants.value); - } - }, [props.participants.value]); const onResize = async () => { const container = conRef.current; @@ -205,7 +193,6 @@ let VideoCompBuilder = (function (props) { @@ -216,46 +203,6 @@ let VideoCompBuilder = (function (props) { }) .setPropertyViewFn((children) => ( <> - {/*
- {children.userId.propertyView({ - label: trans("meeting.userId"), - })} - {children.autoHeight.getPropertyView()} - {children.videokey.propertyView({ - label: trans("prop.videokey"), - })} -
*/} - {/*
- {/* {hiddenPropertyView(children)} -
*/} - - {/*
- {children.type.propertyView({ - label: trans("prop.type"), - radioButton: true, - })} */} - {/* {isDefault(children.type.getView()) - ? [ - children.onEvent.getPropertyView(), - disabledPropertyView(children), - loadingPropertyView(children), - ] - : children.form.getPropertyView()} */} - {/*
*/} - - {/*
- {children.prefixIcon.propertyView({ - label: trans("button.prefixIcon"), - })} - {children.suffixIcon.propertyView({ - label: trans("button.suffixIcon"), - })} - {hiddenPropertyView(children)} -
- -
- {children.style.getPropertyView()} -
*/} )) .build(); @@ -267,57 +214,8 @@ VideoCompBuilder = class extends VideoCompBuilder { } }; -VideoCompBuilder = withMethodExposing(VideoCompBuilder, [ - { - method: { - name: "audioControl", - description: trans("meeting.actionBtnDesc"), - params: [], - }, - execute: (comp, values) => { - // let value = !comp.children.audioControl.getView().value; - // turnOnMicrophone(value); - // comp.children.audioControl.change(value); - }, - }, - // { - // method: { - // name: "videoControl", - // description: trans("meeting.actionBtnDesc"), - // params: [], - // }, - // execute: (comp, values) => { - // let value = !comp.children.videoControl.getView().value; - // turnOnCamera(value); - // comp.children.videoControl.change(value); - // }, - // }, - // { - // method: { - // name: "startMeeting", - // description: trans("meeting.actionBtnDesc"), - // params: [], - // }, - // execute: (comp, values) => { - // publishVideo(comp.children.appId.getView(), "testsdaadasdsa"); - // }, - // }, - // { - // method: { - // name: "endCall", - // description: trans("meeting.actionBtnDesc"), - // params: [], - // }, - // execute: (comp, values) => { - // let value = !comp.children.endCall.getView().value; - // leaveChannel(); - // comp.children.endCall.change(value); - // }, - // }, -]); export const VideoMeetingComp = withExposingConfigs(VideoCompBuilder, [ - // new NameConfig("appId", trans("button.textDesc")), new NameConfig("loading", trans("button.loadingDesc")), ...CommonNameConfig, ]); diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videobuttonCompConstants.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videobuttonCompConstants.tsx similarity index 100% rename from client/packages/lowcoder/src/comps/comps/videoComp/videobuttonCompConstants.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/videobuttonCompConstants.tsx diff --git a/client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx b/client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx deleted file mode 100644 index 6e3bd8c96..000000000 --- a/client/packages/lowcoder/src/comps/comps/videoComp/videoContolComp.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import styled, { css } from "styled-components"; -import { Section, sectionNames } from "lowcoder-design"; -import { - clickEvent, - eventHandlerControl, -} from "../../controls/eventHandlerControl"; -import { StringStateControl } from "../../controls/codeStateControl"; -import { UICompBuilder, withDefault } from "../../generators"; -import { - NameConfig, - NameConfigHidden, - withExposingConfigs, -} from "../../generators/withExposing"; -import { RecordConstructorToView } from "lowcoder-core"; -import { useEffect, useRef, useState } from "react"; -import _ from "lodash"; -import ReactResizeDetector from "react-resize-detector"; -import { styleControl } from "comps/controls/styleControl"; -import { - ImageStyle, - ImageStyleType, - heightCalculator, - widthCalculator, -} from "comps/controls/styleControlConstants"; -import { hiddenPropertyView } from "comps/utils/propertyUtils"; -import { trans } from "i18n"; -import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { BoolControl } from "comps/controls/boolControl"; -import { Image as AntImage } from "antd"; -import { DEFAULT_IMG_URL } from "util/stringUtils"; -import { - Button100, - ButtonCompWrapper, - ButtonStyleControl, -} from "./videobuttonCompConstants"; - -const Container = styled.div<{ $style: ImageStyleType | undefined }>` - height: 100%; - width: 100%; - display: flex; - align-items: center; - justify-content: center; - .ant-image, - img { - width: 100%; - height: 100%; - } - - img { - object-fit: contain; - pointer-events: auto; - } - - ${(props) => props.$style && getStyle(props.$style)} -`; - -const getStyle = (style: ImageStyleType) => { - return css` - img { - border: 1px solid ${style.border}; - border-radius: ${style.radius}; - margin: ${style.margin}; - padding: ${style.padding}; - max-width: ${widthCalculator(style.margin)}; - max-height: ${heightCalculator(style.margin)}; - } - - .ant-image-mask { - border-radius: ${style.radius}; - } - `; -}; - -const EventOptions = [clickEvent] as const; - -const ContainerImg = (props: RecordConstructorToView) => { - const imgRef = useRef(null); - const conRef = useRef(null); - const [width, setWidth] = useState(0); - const [height, setHeight] = useState(0); - - const imgOnload = (img: HTMLImageElement) => { - img.onload = function () { - setWidth(img.naturalWidth); - setHeight(img.naturalHeight); - }; - }; - - useEffect(() => { - const newImage = new Image(0, 0); - newImage.src = props.src.value; - imgOnload(newImage); - newImage.onerror = function (e) { - newImage.src = DEFAULT_IMG_URL; - imgOnload(newImage); - }; - }, [props.src.value]); - - useEffect(() => { - if (height && width) { - onResize(); - } - }, [height, width]); - - // on safari - const setStyle = (height: string, width: string) => { - console.log(width, height); - - const img = imgRef.current; - console.log("img", img); - const imgDiv = img?.getElementsByTagName("button")[0]; - console.log("button", imgDiv); - - const imgCurrent = img?.getElementsByTagName("button")[0]; - img!.style.height = height; - img!.style.width = width; - imgDiv!.style.height = height; - imgDiv!.style.width = width; - // imgCurrent!.style.height = height; - // imgCurrent!.style.width = width; - }; - - const onResize = () => { - const img = imgRef.current; - const container = conRef.current; - console.log(container?.clientWidth, container?.clientHeight); - - if (!img?.clientWidth || !img?.clientHeight || props.autoHeight || !width) { - return; - } - // fixme border style bug on safari - setStyle(container?.clientHeight + "px", container?.clientWidth + "px"); - // if ( - // (_.divide(container?.clientWidth!, container?.clientHeight!) || 0) > - // (_.divide(Number(width), Number(height)) || 0) - // ) { - // setStyle("100%", "auto"); - // } else { - // setStyle("auto", "100%"); - // } - }; - return ( - - -
- - // isDefault(props.type) - // ? props.onEvent("click") - // : submitForm(editorState, props.form) - // } - > - m - -
-
-
- ); -}; - -const childrenMap = { - src: withDefault(StringStateControl, "https://temp.im/350x400"), - onEvent: eventHandlerControl(EventOptions), - style: styleControl(ImageStyle), - autoHeight: withDefault(AutoHeightControl, "fixed"), - supportPreview: BoolControl, -}; - -let ImageBasicComp = new UICompBuilder(childrenMap, (props) => { - return ; -}) - .setPropertyViewFn((children) => { - return ( - <> -
- {children.src.propertyView({ - label: trans("image.src"), - })} - {children.supportPreview.propertyView({ - label: trans("image.supportPreview"), - tooltip: trans("image.supportPreviewTip"), - })} -
- -
- {children.onEvent.getPropertyView()} -
- -
- {children.autoHeight.getPropertyView()} - {hiddenPropertyView(children)} -
- -
- {children.style.getPropertyView()} -
- - ); - }) - .build(); - -ImageBasicComp = class extends ImageBasicComp { - override autoHeight(): boolean { - return this.children.autoHeight.getView(); - } -}; - -export const VideoContolComp = withExposingConfigs(ImageBasicComp, [ - new NameConfig("src", trans("image.srcDesc")), - NameConfigHidden, -]); diff --git a/client/packages/lowcoder/src/comps/hooks/hookComp.tsx b/client/packages/lowcoder/src/comps/hooks/hookComp.tsx index e5fa4d598..7d6943c0c 100644 --- a/client/packages/lowcoder/src/comps/hooks/hookComp.tsx +++ b/client/packages/lowcoder/src/comps/hooks/hookComp.tsx @@ -32,7 +32,7 @@ import { MessageComp } from "./messageComp"; import { ThemeComp } from "./themeComp"; import UrlParamsHookComp from "./UrlParamsHookComp"; import { UtilsComp } from "./utilsComp"; -import { VideoCOntrollerComp } from "./videoControllerComp"; +import { VideoCOntrollerComp } from "../comps/meetingComp/videoControllerComp"; window._ = _; window.dayjs = dayjs; diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index e48516ac3..faadc87bf 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -136,9 +136,9 @@ import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp"; //Added by Aqib Mirza import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp"; import { ResponsiveLayoutComp } from "./comps/responsiveLayout"; -import { VideoMeetingComp } from "./comps/videoComp/videoMeetingComp"; -import { VideoControlButton } from "./comps/videoComp/videoControlButton"; -import { VideoCOntrollerComp } from "./hooks/videoControllerComp"; +import { VideoMeetingComp } from "./comps/meetingComp/videoStreamComp"; +import { VideoControlButton } from "./comps/meetingComp/videoControlButton"; +import { VideoCOntrollerComp } from "./comps/meetingComp/videoControllerComp"; type Registry = { [key in UICompType]?: UICompManifest; From d1050eb93a134705d793e82043c9cca3f6afece8 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Mon, 9 Oct 2023 12:39:11 +0300 Subject: [PATCH 14/43] more meeting components name refactoring fixes --- .../src/components/Meeting.tsx | 93 ------------------- .../src/components/meeting.tsx | 43 --------- client/packages/lowcoder-design/src/index.ts | 3 +- ...omp.tsx => videoMeetingControllerComp.tsx} | 7 +- ...eamComp.tsx => videoMeetingStreamComp.tsx} | 2 +- .../lowcoder/src/comps/hooks/hookComp.tsx | 4 +- client/packages/lowcoder/src/comps/index.tsx | 8 +- .../lowcoder/src/comps/uiCompRegistry.ts | 2 +- .../packages/lowcoder/src/i18n/locales/en.ts | 4 +- 9 files changed, 13 insertions(+), 153 deletions(-) delete mode 100644 client/packages/lowcoder-design/src/components/Meeting.tsx delete mode 100644 client/packages/lowcoder-design/src/components/meeting.tsx rename client/packages/lowcoder/src/comps/comps/meetingComp/{videoControllerComp.tsx => videoMeetingControllerComp.tsx} (99%) rename client/packages/lowcoder/src/comps/comps/meetingComp/{videoStreamComp.tsx => videoMeetingStreamComp.tsx} (98%) diff --git a/client/packages/lowcoder-design/src/components/Meeting.tsx b/client/packages/lowcoder-design/src/components/Meeting.tsx deleted file mode 100644 index a438f905b..000000000 --- a/client/packages/lowcoder-design/src/components/Meeting.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Drawer as AntdDrawer, DrawerProps as AntdDrawerProps } from "antd"; -import Handle from "./Modal/handler"; -import { useEffect, useMemo, useState } from "react"; -import { Resizable, ResizeHandle } from "react-resizable"; -import { useResizeDetector } from "react-resize-detector"; -import styled from "styled-components"; - -const StyledMeeting = styled(AntdDrawer)` - & .ant-drawer-content-wrapper { - transition-duration: 0s; - } -`; - -type Placement = "top" | "bottom" | "left" | "right"; -function getResizeHandle(placement?: Placement): ResizeHandle { - switch (placement) { - case "top": - return "s"; - case "bottom": - return "n"; - case "left": - return "e"; - } - return "w"; -} - -type MeetingProps = { - resizable?: boolean; - onResizeStart?: ( - e: React.SyntheticEvent, - node: HTMLElement, - size: { width: number; height: number }, - handle: ResizeHandle - ) => void; - onResize?: ( - e: React.SyntheticEvent, - node: HTMLElement, - size: { width: number; height: number }, - handle: ResizeHandle - ) => void; - onResizeStop?: ( - e: React.SyntheticEvent, - node: HTMLElement, - size: { width: number; height: number }, - handle: ResizeHandle - ) => void; -} & AntdDrawerProps; - -export function Meeting(props: MeetingProps) { - const { resizable, width: drawerWidth, height: drawerHeight, children, ...otherProps } = props; - const placement = useMemo(() => props.placement ?? "right", [props.placement]); - const resizeHandles = useMemo( - () => (resizable ? [getResizeHandle(placement)] : []), - [placement, resizable] - ); - const isTopBom = ["top", "bottom"].includes(placement); - const [width, setWidth] = useState(); - const [height, setHeight] = useState(); - useEffect(() => { - setWidth(undefined); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [drawerWidth]); - useEffect(() => { - setHeight(undefined); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [drawerHeight]); - const { width: detectWidth, height: detectHeight, ref } = useResizeDetector(); - // log.info("Drawer. drawerWidth: ", drawerWidth, " width: ", width, "detectWidth: ", detectWidth); - return ( - - - props.onResizeStart?.(event, node, size, handle) - } - onResize={(event, { node, size, handle }) => { - isTopBom ? setHeight(size.height) : setWidth(size.width); - props.onResize?.(event, node, size, handle); - }} - onResizeStop={(event, { node, size, handle }) => - props.onResizeStop?.(event, node, size, handle) - } - > -
- {children} -
-
-
- ); -} diff --git a/client/packages/lowcoder-design/src/components/meeting.tsx b/client/packages/lowcoder-design/src/components/meeting.tsx deleted file mode 100644 index 829044cf1..000000000 --- a/client/packages/lowcoder-design/src/components/meeting.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { trans } from "i18n/design"; -import { ReactNode } from "react"; -import styled from "styled-components"; -import { ReactComponent as MeetingContainerDrag } from "icons/icon-left-comp-video.svg"; - -type MeetingContainerPlaceholderProps = { - children?: ReactNode; -}; - -const HintText = styled.span` - font-size: 13px; - color: #b8b9bf; - text-align: center; -`; - -export function MeetingContainerPlaceholder( - props: MeetingContainerPlaceholderProps -) { - return ( -
- - - {props.children} - -
- ); -} - -export const MeetingHintPlaceHolder = ( - - {trans("container.hintPlaceHolder")} - -); diff --git a/client/packages/lowcoder-design/src/index.ts b/client/packages/lowcoder-design/src/index.ts index 133417f7c..a2a7ca495 100644 --- a/client/packages/lowcoder-design/src/index.ts +++ b/client/packages/lowcoder-design/src/index.ts @@ -1,7 +1,6 @@ export * from "./components/Collapase"; export * from "./components/CustomModal"; -export * from "./components/Drawer"; -export * from "./components/Meeting"; +export * from "./components/Drawer"; export * from "./components/Dropdown"; export * from "./components/ExternalLink"; export * from "./components/GlobalInstances"; diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx similarity index 99% rename from client/packages/lowcoder/src/comps/comps/meetingComp/videoControllerComp.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 74ba992ad..d068ace93 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -7,9 +7,7 @@ import { } from "comps/comps/containerComp/containerView"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; import { BoolControl } from "comps/controls/boolControl"; -import { - StringControl, -} from "comps/controls/codeControl"; +import { StringControl } from "comps/controls/codeControl"; import { booleanExposingStateControl, jsonObjectExposingStateControl, @@ -94,7 +92,6 @@ function transToPxSize(size: string | number) { return isNumeric(size) ? size + "px" : (size as string); } - let client: IAgoraRTCClient = AgoraRTC.createClient({ mode: "rtc", codec: "vp8", @@ -461,7 +458,7 @@ MTComp = withMethodExposing(MTComp, [ }, ]); -export const VideoCOntrollerComp = withExposingConfigs(MTComp, [ +export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("visible", trans("export.visibleDesc")), new NameConfig("appId", trans("prop.appid")), new NameConfig("participants", trans("prop.participants")), diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx similarity index 98% rename from client/packages/lowcoder/src/comps/comps/meetingComp/videoStreamComp.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 67e687277..d2963c4c3 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -215,7 +215,7 @@ VideoCompBuilder = class extends VideoCompBuilder { }; -export const VideoMeetingComp = withExposingConfigs(VideoCompBuilder, [ +export const VideoMeetingStreamComp = withExposingConfigs(VideoCompBuilder, [ new NameConfig("loading", trans("button.loadingDesc")), ...CommonNameConfig, ]); diff --git a/client/packages/lowcoder/src/comps/hooks/hookComp.tsx b/client/packages/lowcoder/src/comps/hooks/hookComp.tsx index 7d6943c0c..43e44b7c7 100644 --- a/client/packages/lowcoder/src/comps/hooks/hookComp.tsx +++ b/client/packages/lowcoder/src/comps/hooks/hookComp.tsx @@ -32,7 +32,7 @@ import { MessageComp } from "./messageComp"; import { ThemeComp } from "./themeComp"; import UrlParamsHookComp from "./UrlParamsHookComp"; import { UtilsComp } from "./utilsComp"; -import { VideoCOntrollerComp } from "../comps/meetingComp/videoControllerComp"; +import { VideoMeetingControllerComp } from "../comps/meetingComp/videoMeetingControllerComp"; window._ = _; window.dayjs = dayjs; @@ -95,7 +95,7 @@ const HookMap: HookCompMapRawType = { message: MessageComp, localStorage: LocalStorageComp, modal: ModalComp, - meeting: VideoCOntrollerComp, + meeting: VideoMeetingControllerComp, currentUser: CurrentUserHookComp, urlParams: UrlParamsHookComp, drawer: DrawerComp, diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index faadc87bf..c2ffb9951 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -136,9 +136,9 @@ import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp"; //Added by Aqib Mirza import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp"; import { ResponsiveLayoutComp } from "./comps/responsiveLayout"; -import { VideoMeetingComp } from "./comps/meetingComp/videoStreamComp"; +import { VideoMeetingStreamComp } from "./comps/meetingComp/videoMeetingStreamComp"; import { VideoControlButton } from "./comps/meetingComp/videoControlButton"; -import { VideoCOntrollerComp } from "./comps/meetingComp/videoControllerComp"; +import { VideoMeetingControllerComp } from "./comps/meetingComp/videoMeetingControllerComp"; type Registry = { [key in UICompType]?: UICompManifest; @@ -565,7 +565,7 @@ const uiCompMap: Registry = { categories: ["meeting"], icon: VideoCompIcon, keywords: trans("meeting.meetingCompKeywords"), - comp: VideoMeetingComp, + comp: VideoMeetingStreamComp, withoutLoading: true, }, meetingcontrols: { @@ -781,7 +781,7 @@ const uiCompMap: Registry = { categories: ["meeting"], icon: DrawerCompIcon, keywords: trans("meeting.meetingCompKeywords"), - comp: VideoCOntrollerComp, + comp: VideoMeetingControllerComp, withoutLoading: true, }, carousel: { diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index 1aa9778bb..1dcf740bb 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -24,7 +24,7 @@ export interface UICompLayoutInfo { export const uiCompCategoryNames = { common: trans("uiCompCategory.common"), - meeting: trans("uiCompCategory.meeting"), + meeting: trans("meeting.meeting"), dataInputText: trans("uiCompCategory.dataInputText"), dataInputNumber: trans("uiCompCategory.dataInputNumber"), dataInputSelect: trans("uiCompCategory.dataInputSelect"), diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 67e118864..6eef4054d 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -697,7 +697,6 @@ export const en = { }, uiCompCategory: { common: "Commonly used", - meeting: "Meeting Settings", dataInputText: "Text inputs", dataInputNumber: "Number inputs", dataInputSelect: "Select inputs", @@ -1436,7 +1435,8 @@ export const en = { height: "Drawer height", }, meeting: { - placement: "Drawer placement", + placement: "Meeting placement", + meeting: "Meeting Settings", size: "Size", top: "Top", right: "Right", From db0753fc3df7bb97287ce194552ff8fc7c311cca Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Tue, 10 Oct 2023 17:37:23 +0300 Subject: [PATCH 15/43] initial-participants listview with videos --- .../videoMeetingControllerComp.tsx | 71 ++++++------------- .../meetingComp/videoMeetingStreamComp.tsx | 70 +++++++++++------- 2 files changed, 65 insertions(+), 76 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index d068ace93..cc9ccabb8 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -11,7 +11,6 @@ import { StringControl } from "comps/controls/codeControl"; import { booleanExposingStateControl, jsonObjectExposingStateControl, - jsonValueExposingStateControl, numberExposingStateControl, } from "comps/controls/codeStateControl"; import { PositionControl } from "comps/controls/dropdownControl"; @@ -21,7 +20,7 @@ import { } from "comps/controls/eventHandlerControl"; import { styleControl } from "comps/controls/styleControl"; import { DrawerStyle } from "comps/controls/styleControlConstants"; -import { withDefault } from "comps/generators"; +import { stateComp, withDefault } from "comps/generators"; import { withMethodExposing } from "comps/generators/withMethodExposing"; import { BackgroundColorContext } from "comps/utils/backgroundColorContext"; import { CanvasContainerID } from "constants/domLocators"; @@ -34,7 +33,7 @@ import { Section, sectionNames, } from "lowcoder-design"; -import { useCallback, useEffect } from "react"; +import { useCallback, useEffect, useState } from "react"; import { ResizeHandle } from "react-resizable"; import styled from "styled-components"; import { useUserViewMode } from "util/hooks"; @@ -47,6 +46,8 @@ import AgoraRTC, { IAgoraRTCClient, IAgoraRTCRemoteUser, } from "agora-rtc-sdk-ng"; +import { JSONValue } from "@lowcoder-ee/index.sdk"; +import { getData } from "../listViewComp/listViewUtils"; const EventOptions = [closeEvent] as const; @@ -92,11 +93,10 @@ function transToPxSize(size: string | number) { return isNumeric(size) ? size + "px" : (size as string); } -let client: IAgoraRTCClient = AgoraRTC.createClient({ +export const client: IAgoraRTCClient = AgoraRTC.createClient({ mode: "rtc", codec: "vp8", }); - let audioTrack: IMicrophoneAudioTrack; let videoTrack: ICameraVideoTrack; @@ -105,7 +105,7 @@ const turnOnCamera = async (flag?: boolean) => { return videoTrack.setEnabled(flag!); } videoTrack = await AgoraRTC.createCameraVideoTrack(); - videoTrack.play("camera-video"); + videoTrack.play("host-video"); }; const turnOnMicrophone = async (flag?: boolean) => { @@ -151,13 +151,9 @@ const joinChannel = async (appId: any, channel: any, token: any) => { if (isJoined) { await leaveChannel(); } - - await client.join( - appId, - channel, - token || null, - Math.floor(100000 + Math.random() * 900000) - ); + let userId = Math.floor(100000 + Math.random() * 900000); + console.log("me joining ", userId); + await client.join(appId, channel, token || null, userId); isJoined = true; }; @@ -177,30 +173,13 @@ const publishVideo = async (appId: any, channel: any, height: any) => { const videoSettings = mediaStreamTrack.getSettings(); const videoWidth = videoSettings.width; const videoHeight = videoSettings.height; - console.log("videoHeight ", videoHeight); - height.videoWidth.change(videoWidth); height.videoHeight.change(videoHeight); - console.log(`Video width: ${videoWidth}px, height: ${videoHeight}px`); } else { console.error("Media stream track not found"); } }; -const onUserPublish = async ( - user: IAgoraRTCRemoteUser, - mediaType: "video" | "audio" -) => { - if (mediaType === "video") { - const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play("remote-video"); - } - if (mediaType === "audio") { - const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play(); - } -}; - let MTComp = (function () { const childrenMap = { visible: booleanExposingStateControl("visible"), @@ -219,7 +198,7 @@ let MTComp = (function () { videoWidth: numberExposingStateControl("videoWidth", 200), videoHeight: numberExposingStateControl("videoHeight", 200), appId: withDefault(StringControl, trans("prop.appid")), - participants: jsonValueExposingStateControl("participants"), + participants: stateComp([]), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { const isTopBom = ["top", "bottom"].includes(props.placement); @@ -239,34 +218,20 @@ let MTComp = (function () { }, [dispatch, isTopBom] ); + const [userIds, setUserIds] = useState([]); useEffect(() => { - console.log("nnnn ", props.participants); - }, [props.participants.value]); + dispatch(changeChildAction("participants", getData(userIds).data, false)); + }, [userIds]); useEffect(() => { if (client) { - client.on( - "user-published", - async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { - if (mediaType === "video") { - const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play("remote-video"); - } - if (mediaType === "audio") { - const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play(); - } - } - ); - - client.on("user-joined", (user: IAgoraRTCRemoteUser) => {}); + client.on("user-joined", (user: IAgoraRTCRemoteUser) => { + setUserIds((userIds: any) => [...userIds, { user: user.uid }]); + }); client.on("user-offline", (uid: any, reason: any) => { console.log(`User ${uid} left the channel.`); }); - client.on("user-published", (user, mediaType) => { - console.log(`User ${user.uid} published ${user.videoTrack} stream.`); - }); client.on("stream-removed", (user: IAgoraRTCRemoteUser) => { console.log(`Stream from user ${user.uid} removed.`); }); @@ -463,3 +428,7 @@ export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("appId", trans("prop.appid")), new NameConfig("participants", trans("prop.participants")), ]); + +export function agoraClient() { + return client; +} diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index d2963c4c3..b880d2deb 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -1,11 +1,4 @@ -import { - ArrayControl, - ArrayOrJSONObjectControl, - BoolCodeControl, - JSONObjectArrayControl, - NumberControl, - StringControl, -} from "comps/controls/codeControl"; +import { BoolCodeControl } from "comps/controls/codeControl"; import { dropdownControl } from "comps/controls/dropdownControl"; import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; import { IconControl } from "comps/controls/iconControl"; @@ -36,13 +29,11 @@ import { RefControl } from "comps/controls/refControl"; import { useEffect, useRef, useState } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { - arrayStringExposingStateControl, - booleanExposingStateControl, - jsonObjectExposingStateControl, - stringExposingStateControl, - withMethodExposing, -} from "@lowcoder-ee/index.sdk"; +import { client } from "./videoMeetingControllerComp"; + +import { IAgoraRTCRemoteUser, UID } from "agora-rtc-sdk-ng"; + +import { stringExposingStateControl } from "@lowcoder-ee/index.sdk"; // import useAgora from "@lowcoder-ee/comps/hooks/agoraFunctions"; const FormLabel = styled(CommonBlueLabel)` @@ -50,10 +41,6 @@ const FormLabel = styled(CommonBlueLabel)` margin-right: 4px; `; -const IconWrapper = styled.div` - display: flex; -`; - function getFormOptions(editorState: EditorState) { return editorState .uiCompInfoList() @@ -165,10 +152,7 @@ let VideoCompBuilder = (function (props) { suffixIcon: IconControl, style: ButtonStyleControl, viewRef: RefControl, - userId: stringExposingStateControl( - "text", - trans("meeting.userId", { name: "{{currentUser.name}}" }) - ), + userId: stringExposingStateControl("user id", trans("meeting.userId")), }; return new UICompBuilder(childrenMap, (props) => { const videoRef = useRef(null); @@ -178,7 +162,6 @@ let VideoCompBuilder = (function (props) { onResize(); }, []); - const onResize = async () => { const container = conRef.current; let videoCo = videoRef.current; @@ -186,6 +169,39 @@ let VideoCompBuilder = (function (props) { videoCo!.style.width = container?.clientWidth + "px"; }; + useEffect(() => { + client.on( + "user-published", + async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + if (mediaType === "video") { + + // const videoElement = document.createElement("video"); + // videoElement.id = user.uid + ""; + // videoElement.width = 640; + // videoElement.height = 360; + + // if (conRef.current) { + // conRef.current.appendChild(videoElement); + // } + + // console.log("elementHtml", document.getElementById(user.uid + "")); + + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play(user.uid + "_v"); + console.log("user-published ", user.uid); + } + if (mediaType === "audio") { + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play(); + } + } + ); + + client.on("user-joined", (user: IAgoraRTCRemoteUser) => { + console.log("drawer joined", user.uid); + }); + }, [props.userId]); + return ( {(editorState) => ( @@ -193,6 +209,7 @@ let VideoCompBuilder = (function (props) { @@ -203,6 +220,10 @@ let VideoCompBuilder = (function (props) { }) .setPropertyViewFn((children) => ( <> +
+ {children.userId.propertyView({ label: trans("text") })} + {children.autoHeight.getPropertyView()} +
)) .build(); @@ -214,7 +235,6 @@ VideoCompBuilder = class extends VideoCompBuilder { } }; - export const VideoMeetingStreamComp = withExposingConfigs(VideoCompBuilder, [ new NameConfig("loading", trans("button.loadingDesc")), ...CommonNameConfig, From 26a980ab4cc03ecd249ab8d5d53d24f463e5e34e Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Thu, 12 Oct 2023 14:26:42 +0300 Subject: [PATCH 16/43] implemented user leaving the call and removing the user from the list of users to refresh all other users in the room to see one user has left --- .DS_Store | Bin 0 -> 6148 bytes client/packages/lowcoder/docker-compose.yaml | 99 ++++++++++++++++++ .../videoMeetingControllerComp.tsx | 36 +++---- .../meetingComp/videoMeetingStreamComp.tsx | 26 +---- 4 files changed, 115 insertions(+), 46 deletions(-) create mode 100644 .DS_Store create mode 100644 client/packages/lowcoder/docker-compose.yaml diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8cd8f4f0b42ebab53a9ee4a7866540c3f64ac38f GIT binary patch literal 6148 zcmeHKu}&L75Pj<$*oG8VB&48FoM@mjqNO^JQ${Heqy!sVn8cT}VvK~8C|4vYqtK^F z6-1XR;s??}OOZAu4J8#~W_NAR+8m-nDB6*B-`>vb%)58KTQ2~$(ycE7B>)9#jKKtT zHyHc5jabgk%n&Nh(b`^I-Ady2NTi?e3U~z`q5}Nx1}I}2JJ^-)Z}GVNP5R=bQmM6) z8qF1oN52nFUjJEk{qk<9Z5dqwkkIJ{+Ded@;Xe<{@GR&oC=S@|b!SF^{_%?b&RFNrS%k3U~#)0(}Me z`w&uNj4Y-G^{0b6eFPv3Xj&VMOFSS9Ek+hogXAGoW+|ars_YR%ndLMe+PKJKYS1i) zvWE|4D=T|KQMx+i4|O { }; const leaveChannel = async () => { - if (!client) { - console.error("Agora client is not initialized"); - return; - } - - if (!client.localTracks.length) { - console.error("No local tracks to unpublish"); - return; - } + console.log("user leaving 3"); if (videoTrack) { await turnOnCamera(false); await client.unpublish(videoTrack); videoTrack.stop(); } + console.log("user leaving 2"); if (audioTrack) { await turnOnMicrophone(false); await client.unpublish(audioTrack); audioTrack.stop(); } + console.log("user leaving"); await client.leave(); isJoined = false; @@ -225,20 +219,14 @@ let MTComp = (function () { }, [userIds]); useEffect(() => { - if (client) { - client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - setUserIds((userIds: any) => [...userIds, { user: user.uid }]); - }); - client.on("user-offline", (uid: any, reason: any) => { - console.log(`User ${uid} left the channel.`); - }); - client.on("stream-removed", (user: IAgoraRTCRemoteUser) => { - console.log(`Stream from user ${user.uid} removed.`); - }); - client.on("stream-added", (user: IAgoraRTCRemoteUser) => { - console.log("stream-added"); - }); - } + client.on("user-joined", (user: IAgoraRTCRemoteUser) => { + setUserIds((userIds: any) => [...userIds, { user: user.uid }]); + }); + client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { + setUserIds((userIds: any) => + userIds.filter((item: any) => item.user !== user.uid) + ); + }); }, [client]); return ( @@ -407,6 +395,8 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { let value = !comp.children.endCall.getView().value; + console.log(""); + await leaveChannel(); comp.children.endCall.change(value); }, diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index b880d2deb..b5d07de62 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -34,7 +34,6 @@ import { client } from "./videoMeetingControllerComp"; import { IAgoraRTCRemoteUser, UID } from "agora-rtc-sdk-ng"; import { stringExposingStateControl } from "@lowcoder-ee/index.sdk"; -// import useAgora from "@lowcoder-ee/comps/hooks/agoraFunctions"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -168,27 +167,13 @@ let VideoCompBuilder = (function (props) { videoCo!.style.height = container?.clientHeight + "px"; videoCo!.style.width = container?.clientWidth + "px"; }; - useEffect(() => { client.on( "user-published", async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { if (mediaType === "video") { - - // const videoElement = document.createElement("video"); - // videoElement.id = user.uid + ""; - // videoElement.width = 640; - // videoElement.height = 360; - - // if (conRef.current) { - // conRef.current.appendChild(videoElement); - // } - - // console.log("elementHtml", document.getElementById(user.uid + "")); - const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play(user.uid + "_v"); - console.log("user-published ", user.uid); + remoteTrack.play(user.uid + ""); } if (mediaType === "audio") { const remoteTrack = await client.subscribe(user, mediaType); @@ -196,12 +181,7 @@ let VideoCompBuilder = (function (props) { } } ); - - client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - console.log("drawer joined", user.uid); - }); - }, [props.userId]); - + }, [props.userId.value]); return ( {(editorState) => ( @@ -209,7 +189,7 @@ let VideoCompBuilder = (function (props) { From 36de39ca6f9bb494b11e76819a546b9cbba7ed91 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Thu, 12 Oct 2023 17:41:56 +0300 Subject: [PATCH 17/43] added sharing of screen --- .../videoMeetingControllerComp.tsx | 55 +++++++++++++++---- .../meetingComp/videoMeetingStreamComp.tsx | 10 +++- .../packages/lowcoder/src/i18n/locales/en.ts | 1 + 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 7d0b8fd12..4344565b8 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -12,6 +12,7 @@ import { booleanExposingStateControl, jsonObjectExposingStateControl, numberExposingStateControl, + stringExposingStateControl, } from "comps/controls/codeStateControl"; import { PositionControl } from "comps/controls/dropdownControl"; import { @@ -45,6 +46,8 @@ import AgoraRTC, { IMicrophoneAudioTrack, IAgoraRTCClient, IAgoraRTCRemoteUser, + UID, + ILocalVideoTrack, } from "agora-rtc-sdk-ng"; import { JSONValue } from "@lowcoder-ee/index.sdk"; import { getData } from "../listViewComp/listViewUtils"; @@ -99,13 +102,14 @@ export const client: IAgoraRTCClient = AgoraRTC.createClient({ }); let audioTrack: IMicrophoneAudioTrack; let videoTrack: ICameraVideoTrack; - +let screenShareStream: ILocalVideoTrack; +let userId: UID | null | undefined; const turnOnCamera = async (flag?: boolean) => { if (videoTrack) { return videoTrack.setEnabled(flag!); } videoTrack = await AgoraRTC.createCameraVideoTrack(); - videoTrack.play("host-video"); + videoTrack.play(userId + ""); }; const turnOnMicrophone = async (flag?: boolean) => { @@ -115,24 +119,42 @@ const turnOnMicrophone = async (flag?: boolean) => { audioTrack = await AgoraRTC.createMicrophoneAudioTrack(); audioTrack.play(); }; - +const shareScreen = async (sharing: boolean) => { + try { + if (sharing == false) { + await client.unpublish(screenShareStream); + await client.publish(videoTrack); + videoTrack.play(userId + ""); + } else { + screenShareStream = await AgoraRTC.createScreenVideoTrack( + { + screenSourceType: "screen", + }, + "disable" + ); + await client.unpublish(videoTrack); + screenShareStream.play(userId + ""); + await client.publish(screenShareStream); + } + } catch (error) { + console.error("Failed to create screen share stream:", error); + } +}; const leaveChannel = async () => { - console.log("user leaving 3"); if (videoTrack) { await turnOnCamera(false); await client.unpublish(videoTrack); videoTrack.stop(); } - console.log("user leaving 2"); if (audioTrack) { await turnOnMicrophone(false); await client.unpublish(audioTrack); audioTrack.stop(); } - console.log("user leaving"); await client.leave(); + window.location.reload(); //FixMe: this reloads the page when user leaves isJoined = false; }; let isJoined = false; @@ -145,7 +167,6 @@ const joinChannel = async (appId: any, channel: any, token: any) => { if (isJoined) { await leaveChannel(); } - let userId = Math.floor(100000 + Math.random() * 900000); console.log("me joining ", userId); await client.join(appId, channel, token || null, userId); @@ -154,8 +175,6 @@ const joinChannel = async (appId: any, channel: any, token: any) => { const publishVideo = async (appId: any, channel: any, height: any) => { await turnOnCamera(true); - console.log(appId, channel); - if (!isJoined) { await joinChannel(appId, channel, null); } @@ -188,11 +207,13 @@ let MTComp = (function () { audioControl: booleanExposingStateControl("false"), videoControl: booleanExposingStateControl("true"), endCall: booleanExposingStateControl("false"), + sharingScreen: booleanExposingStateControl("false"), videoSettings: jsonObjectExposingStateControl(""), videoWidth: numberExposingStateControl("videoWidth", 200), videoHeight: numberExposingStateControl("videoHeight", 200), appId: withDefault(StringControl, trans("prop.appid")), participants: stateComp([]), + host: stringExposingStateControl("host"), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { const isTopBom = ["top", "bottom"].includes(props.placement); @@ -349,6 +370,18 @@ MTComp = withMethodExposing(MTComp, [ comp.children.visible.getView().onChange(true); }, }, + { + method: { + name: "startSharing", + description: trans("drawer.openDrawerDesc"), + params: [], + }, + execute: async (comp, values) => { + let sharing = !comp.children.sharingScreen.getView().value; + comp.children.sharingScreen.change(sharing); + await shareScreen(sharing); + }, + }, { method: { name: "audioControl", @@ -380,6 +413,8 @@ MTComp = withMethodExposing(MTComp, [ params: [], }, execute: async (comp, values) => { + userId = Math.floor(100000 + Math.random() * 900000); + comp.children.host.change(userId + ""); await publishVideo( comp.children.appId.getView(), "testsdaadasdsa", @@ -395,7 +430,6 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { let value = !comp.children.endCall.getView().value; - console.log(""); await leaveChannel(); comp.children.endCall.change(value); @@ -416,6 +450,7 @@ MTComp = withMethodExposing(MTComp, [ export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("visible", trans("export.visibleDesc")), new NameConfig("appId", trans("prop.appid")), + new NameConfig("host", trans("prop.appid")), new NameConfig("participants", trans("prop.participants")), ]); diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index b5d07de62..8966e93ec 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -31,7 +31,7 @@ import { useEffect, useRef, useState } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; import { client } from "./videoMeetingControllerComp"; -import { IAgoraRTCRemoteUser, UID } from "agora-rtc-sdk-ng"; +import AgoraRTC, { IAgoraRTCRemoteUser, UID } from "agora-rtc-sdk-ng"; import { stringExposingStateControl } from "@lowcoder-ee/index.sdk"; @@ -168,12 +168,18 @@ let VideoCompBuilder = (function (props) { videoCo!.style.width = container?.clientWidth + "px"; }; useEffect(() => { + client.on( "user-published", async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { if (mediaType === "video") { const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play(user.uid + ""); + let userId = user.uid + ""; + const element = document.getElementById(userId); + if (element) { + console.log("userId", element); + remoteTrack.play(userId); + } } if (mediaType === "audio") { const remoteTrack = await client.subscribe(user, mediaType); diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 6eef4054d..89aab914c 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1452,6 +1452,7 @@ export const en = { title: "Meeting title", meetingCompName: "Meeting Controller", videoCompName: "Video Stream", + videoSharingCompName: "Video Sharing", meetingControlCompName: "Controls Buttons", meetingCompDesc: "Meeting component", meetingCompControls: "Meeting control", From 834c8250815cf56a70b8d71c7adf4e59d63ba95e Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Thu, 12 Oct 2023 18:26:18 +0300 Subject: [PATCH 18/43] refactored control buttons --- .../{videoControlButton.tsx => controlButton.tsx} | 14 ++------------ client/packages/lowcoder/src/comps/index.tsx | 6 +++--- .../packages/lowcoder/src/comps/uiCompRegistry.ts | 2 +- .../lowcoder/src/pages/editor/editorConstants.tsx | 2 +- 4 files changed, 7 insertions(+), 17 deletions(-) rename client/packages/lowcoder/src/comps/comps/meetingComp/{videoControlButton.tsx => controlButton.tsx} (95%) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoControlButton.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx similarity index 95% rename from client/packages/lowcoder/src/comps/comps/meetingComp/videoControlButton.tsx rename to client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx index 217cb1bc6..17fca3adb 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoControlButton.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx @@ -306,17 +306,7 @@ let ButtonTmpComp = (function () { {props.prefixIcon} )} - { - props.text || - (props.prefixIcon || props.suffixIcon ? undefined : " ") // Avoid button disappearing - } - {props.suffixIcon && ( - - {props.suffixIcon} - - )} +
@@ -369,7 +359,7 @@ ButtonTmpComp = class extends ButtonTmpComp { return this.children.autoHeight.getView(); } }; -export const VideoControlButton = withExposingConfigs(ButtonTmpComp, [ +export const ControlButton = withExposingConfigs(ButtonTmpComp, [ new NameConfig("text", trans("button.textDesc")), new NameConfig("loading", trans("button.loadingDesc")), ...CommonNameConfig, diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index c2ffb9951..f2098742b 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -137,7 +137,7 @@ import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp"; import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp"; import { ResponsiveLayoutComp } from "./comps/responsiveLayout"; import { VideoMeetingStreamComp } from "./comps/meetingComp/videoMeetingStreamComp"; -import { VideoControlButton } from "./comps/meetingComp/videoControlButton"; +import { ControlButton } from "./comps/meetingComp/controlButton"; import { VideoMeetingControllerComp } from "./comps/meetingComp/videoMeetingControllerComp"; type Registry = { @@ -568,14 +568,14 @@ const uiCompMap: Registry = { comp: VideoMeetingStreamComp, withoutLoading: true, }, - meetingcontrols: { + controlButton: { name: trans("meeting.meetingControlCompName"), enName: "Controls", description: trans("meeting.meetingCompDesc"), categories: ["meeting"], icon: ButtonCompIcon, keywords: trans("meeting.meetingCompKeywords"), - comp: VideoControlButton, + comp: ControlButton, withoutLoading: true, }, tabbedContainer: { diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index 1dcf740bb..a43e5e9e2 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -58,7 +58,7 @@ export type UICompType = | "chart" | "meeting" | "videocomponent" - | "meetingcontrols" + | "controlButton" | "imageEditor" | "calendar" | "password" diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index c70e599c8..9a437761c 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -86,7 +86,7 @@ export const CompStateIcon: { container: , meeting: , videocomponent: , - meetingcontrols: , + controlButton: , tabbedContainer: , modal: , listView: , From 5472d95244cf66de5cc19879774c436ed5b33a7b Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Fri, 13 Oct 2023 11:13:28 +0300 Subject: [PATCH 19/43] fixed button data fields --- .../comps/comps/meetingComp/controlButton.tsx | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx index 17fca3adb..a56355e94 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx @@ -30,13 +30,11 @@ import { IForm } from "../formComp/formDataConstants"; import { SimpleNameComp } from "../simpleNameComp"; import { Button100, - ButtonCompWrapper, ButtonStyleControl, } from "./videobuttonCompConstants"; import { RefControl } from "comps/controls/refControl"; import { AutoHeightControl, - ImageStyleType, heightCalculator, widthCalculator, } from "@lowcoder-ee/index.sdk"; @@ -85,14 +83,6 @@ function getStyleIcon(style: any) { `; } -// const IconWrapper = styled.div<{ $styled: any }>` -// display: flex; -// svg { -// width: ${styled.width}px !important; -// height: ${styled.height}30px !important; -// } -// `; - function getFormOptions(editorState: EditorState) { return editorState .uiCompInfoList() @@ -186,7 +176,6 @@ function submitForm(editorState: EditorState, formName: string) { let ButtonTmpComp = (function () { const childrenMap = { - text: withDefault(StringControl, trans("button.button")), iconSize: withDefault(StringControl, "20px"), type: dropdownControl(typeOptions, ""), autoHeight: withDefault(AutoHeightControl, "fixed"), @@ -195,7 +184,6 @@ let ButtonTmpComp = (function () { loading: BoolCodeControl, form: SelectFormControl, prefixIcon: IconControl, - suffixIcon: IconControl, style: ButtonStyleControl, viewRef: RefControl, }; @@ -209,39 +197,23 @@ let ButtonTmpComp = (function () { useEffect(() => { if (height && width) { onResize(); - console.log("props", props, height, width); } }, [height, width]); const setStyle = (height: string, width: string) => { - console.log(width, height); - const img = imgRef.current; const imgDiv = img?.getElementsByTagName("button")[0]; - console.log("img 1", img); const imgCurrent = img?.getElementsByTagName("button")[0]; - console.log("img 2", imgCurrent); img!.style.height = height; img!.style.width = width; imgDiv!.style.height = height; imgDiv!.style.width = width; - // imgCurrent!.style.height = height; - // imgCurrent!.style.width = width; }; const onResize = () => { const img = imgRef.current; - console.log("img", img); const container = conRef.current; - // console.log("img", container); - console.log( - "img", - !img?.clientWidth, - !img?.clientHeight, - props.autoHeight, - !width - ); if ( !img?.clientWidth || !img?.clientHeight || @@ -250,20 +222,12 @@ let ButtonTmpComp = (function () { ) { return; } - // fixme border style bug on safari - // if ( - // (_.divide(container?.clientWidth!, container?.clientHeight!) || 0) > - // (_.divide(Number(width), Number(height)) || 0) - // ) { - // setStyle("100%", "auto"); - // } else { console.log( container?.clientHeight + "px", container?.clientWidth + "px" ); setStyle(container?.clientHeight + "px", container?.clientWidth + "px"); - // } }; return ( @@ -318,7 +282,6 @@ let ButtonTmpComp = (function () { .setPropertyViewFn((children) => ( <>
- {children.text.propertyView({ label: trans("text") })} {children.autoHeight.getPropertyView()}
@@ -339,9 +302,6 @@ let ButtonTmpComp = (function () { {children.prefixIcon.propertyView({ label: trans("button.prefixIcon"), })} - {children.suffixIcon.propertyView({ - label: trans("button.suffixIcon"), - })} {children.iconSize.propertyView({ label: trans("meeting.iconSize"), })} @@ -360,7 +320,6 @@ ButtonTmpComp = class extends ButtonTmpComp { } }; export const ControlButton = withExposingConfigs(ButtonTmpComp, [ - new NameConfig("text", trans("button.textDesc")), new NameConfig("loading", trans("button.loadingDesc")), ...CommonNameConfig, ]); From b808ac9948f7a0191b071b38bee4a6ca1a6cad4a Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Fri, 13 Oct 2023 12:02:03 +0300 Subject: [PATCH 20/43] added styling of the video component --- .../comps/comps/meetingComp/controlButton.tsx | 5 --- .../meetingComp/videoMeetingStreamComp.tsx | 31 +++++++++++++++---- .../packages/lowcoder/src/i18n/locales/en.ts | 1 + 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx index a56355e94..d3ad399a5 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx @@ -204,7 +204,6 @@ let ButtonTmpComp = (function () { const img = imgRef.current; const imgDiv = img?.getElementsByTagName("button")[0]; - const imgCurrent = img?.getElementsByTagName("button")[0]; img!.style.height = height; img!.style.width = width; imgDiv!.style.height = height; @@ -222,10 +221,6 @@ let ButtonTmpComp = (function () { ) { return; } - console.log( - container?.clientHeight + "px", - container?.clientWidth + "px" - ); setStyle(container?.clientHeight + "px", container?.clientWidth + "px"); }; diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 8966e93ec..5ff3ff8da 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -26,14 +26,18 @@ import { IForm } from "../formComp/formDataConstants"; import { SimpleNameComp } from "../simpleNameComp"; import { ButtonStyleControl } from "./videobuttonCompConstants"; import { RefControl } from "comps/controls/refControl"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useRef } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; import { client } from "./videoMeetingControllerComp"; -import AgoraRTC, { IAgoraRTCRemoteUser, UID } from "agora-rtc-sdk-ng"; +import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; -import { stringExposingStateControl } from "@lowcoder-ee/index.sdk"; +import { + hiddenPropertyView, + stringExposingStateControl, +} from "@lowcoder-ee/index.sdk"; +import { BackgroundColorContext } from "@lowcoder-ee/comps/utils/backgroundColorContext"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -60,11 +64,12 @@ const Container = styled.div<{ $style: any }>` const getStyle = (style: any) => { return css` - button { + { border: 1px solid ${style.border}; border-radius: ${style.radius}; margin: ${style.margin}; padding: ${style.padding}; + background-color: ${style.background}; } `; }; @@ -138,6 +143,9 @@ const typeOptions = [ value: "submit", }, ] as const; +function isDefault(type?: string) { + return !type; +} let VideoCompBuilder = (function (props) { const childrenMap = { @@ -168,7 +176,6 @@ let VideoCompBuilder = (function (props) { videoCo!.style.width = container?.clientWidth + "px"; }; useEffect(() => { - client.on( "user-published", async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { @@ -188,6 +195,9 @@ let VideoCompBuilder = (function (props) { } ); }, [props.userId.value]); + + console.log(props); + return ( {(editorState) => ( @@ -207,9 +217,18 @@ let VideoCompBuilder = (function (props) { .setPropertyViewFn((children) => ( <>
- {children.userId.propertyView({ label: trans("text") })} + {children.userId.propertyView({ label: trans("meeting.videoId") })} {children.autoHeight.getPropertyView()}
+
+ {children.onEvent.getPropertyView()} +
+
+ {hiddenPropertyView(children)} +
+
+ {children.style.getPropertyView()} +
)) .build(); diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 89aab914c..1ba24dc43 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1441,6 +1441,7 @@ export const en = { top: "Top", right: "Right", bottom: "Bottom", + videoId: "Video Id", left: "Left", widthTooltip: "Number or percentage, e.g. 520, 60%", heightTooltip: "Number, e.g. 378", From e62d64c85b58b30d62000158f1758381f791770a Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Fri, 13 Oct 2023 12:15:49 +0300 Subject: [PATCH 21/43] added meeting name to the meeting controller data field --- .../videoMeetingControllerComp.tsx | 19 +++++++++++++------ .../packages/lowcoder/src/i18n/locales/en.ts | 6 ++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 4344565b8..69237d0ff 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -211,9 +211,10 @@ let MTComp = (function () { videoSettings: jsonObjectExposingStateControl(""), videoWidth: numberExposingStateControl("videoWidth", 200), videoHeight: numberExposingStateControl("videoHeight", 200), - appId: withDefault(StringControl, trans("prop.appid")), + appId: withDefault(StringControl, trans("meeting.appid")), participants: stateComp([]), host: stringExposingStateControl("host"), + meetingName: stringExposingStateControl("meetingName"), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { const isTopBom = ["top", "bottom"].includes(props.placement); @@ -316,7 +317,10 @@ let MTComp = (function () { .setPropertyViewFn((children) => ( <>
- {children.appId.propertyView({ label: trans("prop.appid") })} + {children.appId.propertyView({ label: trans("meeting.appid") })} + {children.meetingName.propertyView({ + label: trans("meeting.meetingName"), + })} {children.placement.propertyView({ label: trans("drawer.placement"), radioButton: true, @@ -417,7 +421,9 @@ MTComp = withMethodExposing(MTComp, [ comp.children.host.change(userId + ""); await publishVideo( comp.children.appId.getView(), - "testsdaadasdsa", + comp.children.meetingName.getView().value == "" + ? userId + "_meetingId" + : comp.children.meetingName.getView().value, comp.children ); }, @@ -449,9 +455,10 @@ MTComp = withMethodExposing(MTComp, [ export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("visible", trans("export.visibleDesc")), - new NameConfig("appId", trans("prop.appid")), - new NameConfig("host", trans("prop.appid")), - new NameConfig("participants", trans("prop.participants")), + new NameConfig("appId", trans("meeting.appid")), + new NameConfig("host", trans("meeting.host")), + new NameConfig("participants", trans("meeting.participants")), + new NameConfig("meetingName", trans("meeting.meetingName")), ]); export function agoraClient() { diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 1ba24dc43..74cbb65ea 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -157,8 +157,6 @@ export const en = { showClear: "Show clear button", showSearch: "Searchable", defaultValue: "Default value", - participants: "Participants", - appid: "Application Id", required: "Required field", readOnly: "Read only", readOnlyTooltip: @@ -1439,6 +1437,10 @@ export const en = { meeting: "Meeting Settings", size: "Size", top: "Top", + host: "Host", + participants: "Participants", + appid: "Application Id", + meetingName: "Meeting Name", right: "Right", bottom: "Bottom", videoId: "Video Id", From 34a001eb228c8616972dd61beeeacbfb0a3fd3ff Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Fri, 13 Oct 2023 15:07:45 +0300 Subject: [PATCH 22/43] fixed video component styling --- .../comps/meetingComp/videoMeetingStreamComp.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 5ff3ff8da..170101822 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -62,6 +62,15 @@ const Container = styled.div<{ $style: any }>` ${(props) => props.$style && getStyle(props.$style)} `; +const VideoContainer = styled.video<{ $style: any }>` + height: 100%; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + ${(props) => props.$style && getStyle(props.$style)} +`; + const getStyle = (style: any) => { return css` { @@ -203,11 +212,12 @@ let VideoCompBuilder = (function (props) { {(editorState) => ( - + > + {/* */} )} From c78a54cdd08c8ec980c2af3be0d214c12dbccc80 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Sat, 14 Oct 2023 15:27:37 +0300 Subject: [PATCH 23/43] added video stream controller events --- .../videoMeetingControllerComp.tsx | 258 ++++++++++-------- .../meetingComp/videoMeetingStreamComp.tsx | 180 ++++++------ .../comps/controls/eventHandlerControl.tsx | 93 ++++++- .../packages/lowcoder/src/i18n/locales/en.ts | 5 + 4 files changed, 321 insertions(+), 215 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 69237d0ff..ca8836a73 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -49,8 +49,10 @@ import AgoraRTC, { UID, ILocalVideoTrack, } from "agora-rtc-sdk-ng"; + import { JSONValue } from "@lowcoder-ee/index.sdk"; import { getData } from "../listViewComp/listViewUtils"; +import { meetingStreamChildren } from "./videoMeetingStreamComp"; const EventOptions = [closeEvent] as const; @@ -104,6 +106,7 @@ let audioTrack: IMicrophoneAudioTrack; let videoTrack: ICameraVideoTrack; let screenShareStream: ILocalVideoTrack; let userId: UID | null | undefined; + const turnOnCamera = async (flag?: boolean) => { if (videoTrack) { return videoTrack.setEnabled(flag!); @@ -172,6 +175,9 @@ const joinChannel = async (appId: any, channel: any, token: any) => { isJoined = true; }; +const hostChanged = (users: any) => {}; + + const publishVideo = async (appId: any, channel: any, height: any) => { await turnOnCamera(true); @@ -193,127 +199,145 @@ const publishVideo = async (appId: any, channel: any, height: any) => { } }; +export const meetingControllerChildren = { + visible: booleanExposingStateControl("visible"), + onEvent: eventHandlerControl(EventOptions), + width: StringControl, + height: StringControl, + autoHeight: AutoHeightControl, + style: styleControl(DrawerStyle), + placement: PositionControl, + maskClosable: withDefault(BoolControl, true), + showMask: withDefault(BoolControl, true), + audioControl: booleanExposingStateControl("false"), + videoControl: booleanExposingStateControl("true"), + endCall: booleanExposingStateControl("false"), + sharingScreen: booleanExposingStateControl("false"), + videoSettings: jsonObjectExposingStateControl(""), + videoWidth: numberExposingStateControl("videoWidth", 200), + videoHeight: numberExposingStateControl("videoHeight", 200), + appId: withDefault(StringControl, trans("meeting.appid")), + participants: stateComp([]), + host: stringExposingStateControl("host"), + meetingName: stringExposingStateControl("meetingName"), +}; let MTComp = (function () { - const childrenMap = { - visible: booleanExposingStateControl("visible"), - onEvent: eventHandlerControl(EventOptions), - width: StringControl, - height: StringControl, - autoHeight: AutoHeightControl, - style: styleControl(DrawerStyle), - placement: PositionControl, - maskClosable: withDefault(BoolControl, true), - showMask: withDefault(BoolControl, true), - audioControl: booleanExposingStateControl("false"), - videoControl: booleanExposingStateControl("true"), - endCall: booleanExposingStateControl("false"), - sharingScreen: booleanExposingStateControl("false"), - videoSettings: jsonObjectExposingStateControl(""), - videoWidth: numberExposingStateControl("videoWidth", 200), - videoHeight: numberExposingStateControl("videoHeight", 200), - appId: withDefault(StringControl, trans("meeting.appid")), - participants: stateComp([]), - host: stringExposingStateControl("host"), - meetingName: stringExposingStateControl("meetingName"), - }; - return new ContainerCompBuilder(childrenMap, (props, dispatch) => { - const isTopBom = ["top", "bottom"].includes(props.placement); - const { items, ...otherContainerProps } = props.container; - const userViewMode = useUserViewMode(); - const resizable = !userViewMode && (!isTopBom || !props.autoHeight); - const onResizeStop = useCallback( - ( - e: React.SyntheticEvent, - node: HTMLElement, - size: { width: number; height: number }, - handle: ResizeHandle - ) => { - isTopBom - ? dispatch(changeChildAction("height", size.height, true)) - : dispatch(changeChildAction("width", size.width, true)); - }, - [dispatch, isTopBom] - ); - const [userIds, setUserIds] = useState([]); - - useEffect(() => { - dispatch(changeChildAction("participants", getData(userIds).data, false)); - }, [userIds]); - - useEffect(() => { - client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - setUserIds((userIds: any) => [...userIds, { user: user.uid }]); - }); - client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { - setUserIds((userIds: any) => - userIds.filter((item: any) => item.user !== user.uid) + return new ContainerCompBuilder( + meetingControllerChildren, + (props, dispatch) => { + const isTopBom = ["top", "bottom"].includes(props.placement); + const { items, ...otherContainerProps } = props.container; + const userViewMode = useUserViewMode(); + const resizable = !userViewMode && (!isTopBom || !props.autoHeight); + const onResizeStop = useCallback( + ( + e: React.SyntheticEvent, + node: HTMLElement, + size: { width: number; height: number }, + handle: ResizeHandle + ) => { + isTopBom + ? dispatch(changeChildAction("height", size.height, true)) + : dispatch(changeChildAction("width", size.width, true)); + }, + [dispatch, isTopBom] + ); + const [userIds, setUserIds] = useState([]); + + useEffect(() => { + dispatch( + changeChildAction("participants", getData(userIds).data, false) ); - }); - }, [client]); - - return ( - - - - document.querySelector(`#${CanvasContainerID}`) || document.body - } - footer={null} - width={transToPxSize(props.width || DEFAULT_SIZE)} - height={ - !props.autoHeight - ? transToPxSize(props.height || DEFAULT_SIZE) - : "" - } - onClose={(e) => { - props.visible.onChange(false); - }} - afterOpenChange={(visible) => { - if (!visible) { - props.onEvent("close"); + }, [userIds]); + + useEffect(() => { + client.on("user-joined", (user: IAgoraRTCRemoteUser) => { + console.log("userData", user); + let userData = { user: user.uid, host: false }; + if (userIds.length == 0) { + userData.host = true; + } else { + userData.host = false; + } + console.log("userData", userData); + + setUserIds((userIds: any) => [...userIds, userData]); + }); + client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { + let newUsers = userIds.filter((item: any) => item.user !== user.uid); + let hostExists = newUsers.filter((f: any) => f.host === true); + if (hostExists.length == 0 && newUsers.length > 0) { + newUsers[0].host = true; + hostChanged(newUsers); + } + setUserIds(newUsers); + }); + }, [client]); + + return ( + + + + document.querySelector(`#${CanvasContainerID}`) || document.body } - }} - zIndex={Layers.drawer} - maskClosable={props.maskClosable} - mask={props.showMask} - > - { + footer={null} + width={transToPxSize(props.width || DEFAULT_SIZE)} + height={ + !props.autoHeight + ? transToPxSize(props.height || DEFAULT_SIZE) + : "" + } + onClose={(e) => { props.visible.onChange(false); }} + afterOpenChange={(visible) => { + if (!visible) { + props.onEvent("close"); + } + }} + zIndex={Layers.drawer} + maskClosable={props.maskClosable} + mask={props.showMask} > - - - - - - - ); - }) + { + props.visible.onChange(false); + }} + > + + + + + + + ); + } + ) .setPropertyViewFn((children) => ( <>
@@ -422,7 +446,7 @@ MTComp = withMethodExposing(MTComp, [ await publishVideo( comp.children.appId.getView(), comp.children.meetingName.getView().value == "" - ? userId + "_meetingId" + ? "_meetingId" : comp.children.meetingName.getView().value, comp.children ); @@ -430,7 +454,7 @@ MTComp = withMethodExposing(MTComp, [ }, { method: { - name: "endCall", + name: "endMeeting", description: trans("meeting.actionBtnDesc"), params: [], }, diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 170101822..01d3f41cc 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -1,6 +1,5 @@ import { BoolCodeControl } from "comps/controls/codeControl"; import { dropdownControl } from "comps/controls/dropdownControl"; -import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; import { IconControl } from "comps/controls/iconControl"; import { CompNameContext, EditorContext, EditorState } from "comps/editorState"; import { withDefault } from "comps/generators"; @@ -29,15 +28,20 @@ import { RefControl } from "comps/controls/refControl"; import { useEffect, useRef } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { client } from "./videoMeetingControllerComp"; +import { + client, + meetingControllerChildren, +} from "./videoMeetingControllerComp"; import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; import { + ButtonEventHandlerControl, + MeetingEventHandlerControl, hiddenPropertyView, + refMethods, stringExposingStateControl, } from "@lowcoder-ee/index.sdk"; -import { BackgroundColorContext } from "@lowcoder-ee/comps/utils/backgroundColorContext"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -155,95 +159,105 @@ const typeOptions = [ function isDefault(type?: string) { return !type; } +export const videoShared = () => { + console.log("data"); + +} +export const meetingStreamChildren = { + autoHeight: withDefault(AutoHeightControl, "fixed"), + type: dropdownControl(typeOptions, ""), + // onEvent: ButtonEventHandlerControl, + onEvent: MeetingEventHandlerControl, + disabled: BoolCodeControl, + loading: BoolCodeControl, + form: SelectFormControl, + prefixIcon: IconControl, + suffixIcon: IconControl, + style: ButtonStyleControl, + viewRef: RefControl, + // viewRef: RefControl, + userId: stringExposingStateControl("user id", trans("meeting.userId")), +}; let VideoCompBuilder = (function (props) { - const childrenMap = { - autoHeight: withDefault(AutoHeightControl, "fixed"), - type: dropdownControl(typeOptions, ""), - onEvent: ButtonEventHandlerControl, - disabled: BoolCodeControl, - loading: BoolCodeControl, - form: SelectFormControl, - prefixIcon: IconControl, - suffixIcon: IconControl, - style: ButtonStyleControl, - viewRef: RefControl, - userId: stringExposingStateControl("user id", trans("meeting.userId")), - }; - return new UICompBuilder(childrenMap, (props) => { - const videoRef = useRef(null); - const conRef = useRef(null); + return ( + new UICompBuilder(meetingStreamChildren, (props) => { + const videoRef = useRef(null); + const conRef = useRef(null); + + useEffect(() => { + onResize(); + }, []); - useEffect(() => { - onResize(); - }, []); + const onResize = async () => { + const container = conRef.current; + let videoCo = videoRef.current; + videoCo!.style.height = container?.clientHeight + "px"; + videoCo!.style.width = container?.clientWidth + "px"; + }; + useEffect(() => { + client.on( + "user-published", + async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + if (mediaType === "video") { + const remoteTrack = await client.subscribe(user, mediaType); + console.log("remoteTrack", remoteTrack); - const onResize = async () => { - const container = conRef.current; - let videoCo = videoRef.current; - videoCo!.style.height = container?.clientHeight + "px"; - videoCo!.style.width = container?.clientWidth + "px"; - }; - useEffect(() => { - client.on( - "user-published", - async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { - if (mediaType === "video") { - const remoteTrack = await client.subscribe(user, mediaType); - let userId = user.uid + ""; - const element = document.getElementById(userId); - if (element) { - console.log("userId", element); - remoteTrack.play(userId); + let userId = user.uid + ""; + const element = document.getElementById(userId); + if (element) { + remoteTrack.play(userId); + } + } + if (mediaType === "audio") { + const remoteTrack = await client.subscribe(user, mediaType); + remoteTrack.play(); } } - if (mediaType === "audio") { - const remoteTrack = await client.subscribe(user, mediaType); - remoteTrack.play(); - } - } - ); - }, [props.userId.value]); - - console.log(props); + ); + }, [props.userId.value]); - return ( - - {(editorState) => ( - - - - {/* */} - - - )} - - ); - }) - .setPropertyViewFn((children) => ( - <> -
- {children.userId.propertyView({ label: trans("meeting.videoId") })} - {children.autoHeight.getPropertyView()} -
-
- {children.onEvent.getPropertyView()} -
-
- {hiddenPropertyView(children)} -
-
- {children.style.getPropertyView()} -
- - )) - .build(); + return ( + + {(editorState) => ( + + + + + + )} + + ); + }) + .setPropertyViewFn((children) => ( + <> +
+ {children.userId.propertyView({ label: trans("meeting.videoId") })} + {children.autoHeight.getPropertyView()} +
+
+ {children.onEvent.getPropertyView()} +
+
+ {hiddenPropertyView(children)} +
+
+ {children.style.getPropertyView()} +
+ + )) + // .setExposeMethodConfigs(refMethods([shareMethod])) + .build() + ); })(); +// interface BaseStreamRef { +// shared: () => void; +// } VideoCompBuilder = class extends VideoCompBuilder { override autoHeight(): boolean { return this.children.autoHeight.getView(); diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index 426357c92..2ea7e66b7 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -47,7 +47,9 @@ const childrenMap = { handler: ActionSelectorControl, }; -class SingleEventHandlerControl extends simpleMultiComp(childrenMap) { +class SingleEventHandlerControl< + T extends EventConfigsType +> extends simpleMultiComp(childrenMap) { // view is function (eventName: ValueFromOption) => void, representing a named event getView() { const name = this.children.name.getView(); @@ -67,14 +69,18 @@ class SingleEventHandlerControl extends simpleMultiC const children = this.children; const { eventConfigs } = props; - const eventName = eventConfigs.find((x) => x.value === name)?.label?.toString(); + const eventName = eventConfigs + .find((x) => x.value === name) + ?.label?.toString(); let content: ReactNode = null; if (props.inline && eventConfigs.length === 1) { content = (
- {trans("eventHandler.inlineEventTitle", { eventName: eventName?.toLowerCase() ?? "" })} + {trans("eventHandler.inlineEventTitle", { + eventName: eventName?.toLowerCase() ?? "", + })}
{children.handler.propertyView({ label: trans("eventHandler.action"), @@ -124,15 +130,27 @@ class SingleEventHandlerControl extends simpleMultiC const EventHandlerControlPropertyView = (props: { dispatch: DispatchType; - pushAction: (value: any) => CustomListAction; - deleteAction: (index: number) => CustomListAction; + pushAction: ( + value: any + ) => CustomListAction; + deleteAction: ( + index: number + ) => CustomListAction; items: InstanceType[]; inline?: boolean; title?: ReactNode; type?: "query"; eventConfigs: EventConfigsType; }) => { - const { dispatch, pushAction, deleteAction, inline = false, items, eventConfigs, type } = props; + const { + dispatch, + pushAction, + deleteAction, + inline = false, + items, + eventConfigs, + type, + } = props; const editorState = useContext(EditorContext); const [showNewCreate, setShowNewCreate] = useState(false); @@ -149,7 +167,9 @@ const EventHandlerControlPropertyView = (props: { const queryExecHandler = { compType: "executeQuery", comp: { - queryName: editorState?.selectedOrFirstQueryComp()?.children.name.getView(), + queryName: editorState + ?.selectedOrFirstQueryComp() + ?.children.name.getView(), }, }; const messageHandler = { @@ -181,7 +201,9 @@ const EventHandlerControlPropertyView = (props: { ))}
) : ( - {trans("eventHandler.emptyEventHandlers")} + + {trans("eventHandler.emptyEventHandlers")} + ); if (props.inline) { return
{renderItems()}
; @@ -210,7 +232,9 @@ const EventHandlerControlPropertyView = (props: { ); }; -class EventHandlerControl extends list(SingleEventHandlerControl) { +class EventHandlerControl extends list( + SingleEventHandlerControl +) { @memo // @ts-ignore getView() { @@ -227,14 +251,21 @@ class EventHandlerControl extends list(SingleEventHa } isBind(eventName: ValueFromOption) { - return super.getView().some((child) => child.children.name.getView() === eventName); + return super + .getView() + .some((child) => child.children.name.getView() === eventName); } override getPropertyView() { return this.propertyView(); } - propertyView(options?: { inline?: boolean; title?: ReactNode; type?: "query"; eventConfigs: T }) { + propertyView(options?: { + inline?: boolean; + title?: ReactNode; + type?: "query"; + eventConfigs: T; + }) { const title = options?.title ?? trans("eventHandler.eventHandlers"); return controlItem( { filterText: title }, @@ -252,13 +283,20 @@ class EventHandlerControl extends list(SingleEventHa } } -export function eventHandlerControl(eventConfigs?: T, type?: "query") { +export function eventHandlerControl( + eventConfigs?: T, + type?: "query" +) { class EventHandlerTempControl extends EventHandlerControl { getEventNames() { return eventConfigs; } - propertyView(options?: { inline?: boolean; title?: ReactNode; eventConfigs?: T }) { + propertyView(options?: { + inline?: boolean; + title?: ReactNode; + eventConfigs?: T; + }) { return super.propertyView({ ...options, type, @@ -310,6 +348,21 @@ export const mentionEvent: EventConfigType = { value: "mention", description: trans("event.mentionDesc"), }; +export const screenShared: EventConfigType = { + label: trans("meeting.screenShared"), + value: "screenShared", + description: trans("meeting.screenSharedDesc"), +}; +export const cameraView: EventConfigType = { + label: trans("meeting.cameraView"), + value: "cameraView", + description: trans("meeting.cameraViewDesc"), +}; +export const audioMuteUnmute: EventConfigType = { + label: trans("meeting.audioMuteUnmute"), + value: "audioMuteUnmute", + description: trans("meeting.audioMuteUnmute"), +}; export const InputEventHandlerControl = eventHandlerControl([ changeEvent, @@ -318,9 +371,13 @@ export const InputEventHandlerControl = eventHandlerControl([ submitEvent, ] as const); -export const ButtonEventHandlerControl = eventHandlerControl([clickEvent] as const); +export const ButtonEventHandlerControl = eventHandlerControl([ + clickEvent, +] as const); -export const ChangeEventHandlerControl = eventHandlerControl([changeEvent] as const); +export const ChangeEventHandlerControl = eventHandlerControl([ + changeEvent, +] as const); export const SelectEventHandlerControl = eventHandlerControl([ changeEvent, @@ -333,3 +390,9 @@ export const ScannerEventHandlerControl = eventHandlerControl([ successEvent, closeEvent, ] as const); + +export const MeetingEventHandlerControl = eventHandlerControl([ + screenShared, + cameraView, + audioMuteUnmute, +] as const); diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 74cbb65ea..eef64917d 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1435,6 +1435,11 @@ export const en = { meeting: { placement: "Meeting placement", meeting: "Meeting Settings", + cameraView: "Camera View", + cameraViewDesc: "Camera View", + screenShared: "Screen Shared", + screenSharedDesc: "Screen Shared", + audioMuteUnmute: "Audio Mute", size: "Size", top: "Top", host: "Host", From 17d0d43443a7f9f3db32fc9ac2c81651645febb5 Mon Sep 17 00:00:00 2001 From: Abdul Qadir Date: Sat, 14 Oct 2023 19:40:23 +0500 Subject: [PATCH 24/43] Fix 2 bugs - Mongo DB Queries were not working because of integer timeout data type - Took into account the enable-register application.props value when loading auth configs --- .../authentication/AuthenticationServiceImpl.java | 6 +++++- .../domain/query/service/QueryExecutionService.java | 2 +- .../src/main/resources/application-lowcoder.yml | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java index cb3104ccb..7f7a8b7af 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java @@ -3,8 +3,10 @@ import lombok.extern.slf4j.Slf4j; import org.lowcoder.domain.organization.service.OrganizationService; import org.lowcoder.sdk.auth.AbstractAuthConfig; +import org.lowcoder.sdk.auth.EmailAuthConfig; import org.lowcoder.sdk.config.AuthProperties; import org.lowcoder.sdk.config.CommonConfig; +import org.lowcoder.sdk.constants.AuthSourceConstants; import org.lowcoder.sdk.constants.WorkspaceMode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -58,7 +60,9 @@ public Flux findAllAuthConfigs(String orgId, boolean enableOnly) } return true; }) - .concatWithValues(new FindAuthConfig(DEFAULT_AUTH_CONFIG, null)); + .concatWithValues(new FindAuthConfig + (new EmailAuthConfig(AuthSourceConstants.EMAIL, authProperties.getEmail().isEnable(), + authProperties.getEmail().isEnableRegister()), null)); } private Flux findAllAuthConfigsByDomain() { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java index 750b375f5..dc345993c 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/query/service/QueryExecutionService.java @@ -48,7 +48,7 @@ public Mono executeQuery(Datasource datasource, Map { if (datasourceMetaInfoService.isJsDatasourcePlugin(datasource.getType())) { diff --git a/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml b/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml index a6a3df204..3488bd1c0 100644 --- a/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml +++ b/server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml @@ -3,9 +3,9 @@ spring: mongodb: authentication-database: admin auto-index-creation: false - uri: mongodb://lowcoder:secret123@127.0.0.1/lowcoder?authSource=admin + uri: mongodb://192.168.8.100:27017/lowcoder?authSource=admin redis: - url: redis://localhost:6379 + url: redis://192.168.8.100:6379 main: allow-bean-definition-overriding: true allow-circular-references: true @@ -41,6 +41,8 @@ common: - '*' version: 1.1.8 block-hound-enable: false + js-executor: + host: http://127.0.0.1:6060 material: mongodb-grid-fs: @@ -52,3 +54,8 @@ springdoc: swagger-ui: path: /api/docs/swagger-ui paths-to-exclude: /api/v1/** + +auth: + email: + enable: true + enable-register: false \ No newline at end of file From 84c9749bf1fe8a0f7d983d8c2d25822bc052d4be Mon Sep 17 00:00:00 2001 From: FalkWolsky Date: Sun, 15 Oct 2023 16:11:07 +0200 Subject: [PATCH 25/43] fixed styling for VideoStream Component --- .../src/comps/comps/meetingComp/videoMeetingStreamComp.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 01d3f41cc..f283011b6 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -63,8 +63,7 @@ const Container = styled.div<{ $style: any }>` display: flex; align-items: center; justify-content: center; - ${(props) => props.$style && getStyle(props.$style)} -`; +`; // ${(props) => props.$style && getStyle(props.$style)} - they should be applyed to VideoContainer only const VideoContainer = styled.video<{ $style: any }>` height: 100%; From c278c6dc40446eeecfca445fb5339da359390c3e Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Mon, 16 Oct 2023 12:27:53 +0300 Subject: [PATCH 26/43] finished audio/mute event on video stream component --- .../videoMeetingControllerComp.tsx | 39 ++++++------------- .../meetingComp/videoMeetingStreamComp.tsx | 37 +++++++++++------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index ca8836a73..d7519e001 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -121,6 +121,12 @@ const turnOnMicrophone = async (flag?: boolean) => { } audioTrack = await AgoraRTC.createMicrophoneAudioTrack(); audioTrack.play(); + + if (!flag) { + await client.unpublish(audioTrack); + } else { + await client.publish(audioTrack); + } }; const shareScreen = async (sharing: boolean) => { try { @@ -162,40 +168,20 @@ const leaveChannel = async () => { }; let isJoined = false; -const joinChannel = async (appId: any, channel: any, token: any) => { - if (!channel) { - channel = "react-room"; - } - - if (isJoined) { - await leaveChannel(); - } - console.log("me joining ", userId); - await client.join(appId, channel, token || null, userId); - - isJoined = true; -}; const hostChanged = (users: any) => {}; - - const publishVideo = async (appId: any, channel: any, height: any) => { await turnOnCamera(true); - if (!isJoined) { - await joinChannel(appId, channel, null); - } - + await client.join(appId, channel, null, userId); await client.publish(videoTrack); - const mediaStreamTrack = videoTrack.getMediaStreamTrack(); + const mediaStreamTrack = videoTrack.getMediaStreamTrack(); if (mediaStreamTrack) { const videoSettings = mediaStreamTrack.getSettings(); const videoWidth = videoSettings.width; const videoHeight = videoSettings.height; height.videoWidth.change(videoWidth); height.videoHeight.change(videoHeight); - } else { - console.error("Media stream track not found"); } }; @@ -252,15 +238,12 @@ let MTComp = (function () { useEffect(() => { client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - console.log("userData", user); let userData = { user: user.uid, host: false }; if (userIds.length == 0) { userData.host = true; } else { userData.host = false; } - console.log("userData", userData); - setUserIds((userIds: any) => [...userIds, userData]); }); client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { @@ -416,9 +399,11 @@ MTComp = withMethodExposing(MTComp, [ description: trans("meeting.actionBtnDesc"), params: [], }, - execute: (comp, values) => { + execute: async (comp, values) => { let value = !comp.children.audioControl.getView().value; - turnOnMicrophone(value); + console.log("turnOnMicrophone", value); + // await audioTrack.setEnabled(value); + await turnOnMicrophone(value); comp.children.audioControl.change(value); }, }, diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 01d3f41cc..043ebe81b 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -28,18 +28,13 @@ import { RefControl } from "comps/controls/refControl"; import { useEffect, useRef } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { - client, - meetingControllerChildren, -} from "./videoMeetingControllerComp"; +import { client } from "./videoMeetingControllerComp"; import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; import { - ButtonEventHandlerControl, MeetingEventHandlerControl, hiddenPropertyView, - refMethods, stringExposingStateControl, } from "@lowcoder-ee/index.sdk"; @@ -156,13 +151,10 @@ const typeOptions = [ value: "submit", }, ] as const; -function isDefault(type?: string) { - return !type; -} + export const videoShared = () => { console.log("data"); - -} +}; export const meetingStreamChildren = { autoHeight: withDefault(AutoHeightControl, "fixed"), type: dropdownControl(typeOptions, ""), @@ -201,8 +193,6 @@ let VideoCompBuilder = (function (props) { async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { if (mediaType === "video") { const remoteTrack = await client.subscribe(user, mediaType); - console.log("remoteTrack", remoteTrack); - let userId = user.uid + ""; const element = document.getElementById(userId); if (element) { @@ -211,10 +201,31 @@ let VideoCompBuilder = (function (props) { } if (mediaType === "audio") { const remoteTrack = await client.subscribe(user, mediaType); + if ( + user.hasAudio && + user.uid + "" != props.userId.value && + props.userId.value != "" + ) { + props.onEvent("audioMuteUnmute"); + } remoteTrack.play(); } } ); + client.on( + "user-unpublished", + (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + if (mediaType === "audio") { + if ( + !user.hasAudio && + user.uid + "" != props.userId.value && + props.userId.value != "" + ) { + props.onEvent("audioMuteUnmute"); + } + } + } + ); }, [props.userId.value]); return ( From d131b71f0f20ebd9be99bb0929ad9132d16707a5 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Mon, 16 Oct 2023 14:10:40 +0300 Subject: [PATCH 27/43] Feat: video toggle event --- .../videoMeetingControllerComp.tsx | 35 +++++++++++-------- .../meetingComp/videoMeetingStreamComp.tsx | 21 ++++++++++- .../comps/controls/eventHandlerControl.tsx | 7 +++- .../packages/lowcoder/src/i18n/locales/en.ts | 1 + 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index d7519e001..6991eb897 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -52,7 +52,6 @@ import AgoraRTC, { import { JSONValue } from "@lowcoder-ee/index.sdk"; import { getData } from "../listViewComp/listViewUtils"; -import { meetingStreamChildren } from "./videoMeetingStreamComp"; const EventOptions = [closeEvent] as const; @@ -151,22 +150,15 @@ const shareScreen = async (sharing: boolean) => { }; const leaveChannel = async () => { if (videoTrack) { - await turnOnCamera(false); await client.unpublish(videoTrack); - videoTrack.stop(); + await turnOnCamera(false); } if (audioTrack) { await turnOnMicrophone(false); - await client.unpublish(audioTrack); - audioTrack.stop(); } - await client.leave(); - window.location.reload(); //FixMe: this reloads the page when user leaves - isJoined = false; }; -let isJoined = false; const hostChanged = (users: any) => {}; @@ -236,6 +228,17 @@ let MTComp = (function () { ); }, [userIds]); + useEffect(() => { + if (props.endCall.value) { + let newUsers = userIds.filter((item: any) => item.user !== userId); + console.log("newUsers", newUsers, userId); + + dispatch( + changeChildAction("participants", getData(newUsers).data, false) + ); + } + }, [props.endCall.value]); + useEffect(() => { client.on("user-joined", (user: IAgoraRTCRemoteUser) => { let userData = { user: user.uid, host: false }; @@ -401,8 +404,6 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { let value = !comp.children.audioControl.getView().value; - console.log("turnOnMicrophone", value); - // await audioTrack.setEnabled(value); await turnOnMicrophone(value); comp.children.audioControl.change(value); }, @@ -413,9 +414,14 @@ MTComp = withMethodExposing(MTComp, [ description: trans("meeting.actionBtnDesc"), params: [], }, - execute: (comp, values) => { + execute: async (comp, values) => { let value = !comp.children.videoControl.getView().value; - turnOnCamera(value); + if (videoTrack) { + videoTrack.setEnabled(value); + } else { + await turnOnCamera(value); + } + comp.children.videoControl.change(value); }, }, @@ -445,9 +451,8 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { let value = !comp.children.endCall.getView().value; - - await leaveChannel(); comp.children.endCall.change(value); + await leaveChannel(); }, }, { diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 76fe5ba6c..7ac21b7b8 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -28,7 +28,10 @@ import { RefControl } from "comps/controls/refControl"; import { useEffect, useRef } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { client } from "./videoMeetingControllerComp"; +import { + client, + meetingControllerChildren, +} from "./videoMeetingControllerComp"; import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; @@ -193,6 +196,13 @@ let VideoCompBuilder = (function (props) { if (mediaType === "video") { const remoteTrack = await client.subscribe(user, mediaType); let userId = user.uid + ""; + if ( + user.hasVideo && + user.uid + "" != props.userId.value && + props.userId.value != "" + ) { + props.onEvent("videoActiveInactive"); + } const element = document.getElementById(userId); if (element) { remoteTrack.play(userId); @@ -223,6 +233,15 @@ let VideoCompBuilder = (function (props) { props.onEvent("audioMuteUnmute"); } } + if (mediaType === "video") { + if ( + !user.hasVideo && + user.uid + "" != props.userId.value && + props.userId.value != "" + ) { + props.onEvent("videoActiveInactive"); + } + } } ); }, [props.userId.value]); diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index 2ea7e66b7..6f0c3e389 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -363,7 +363,11 @@ export const audioMuteUnmute: EventConfigType = { value: "audioMuteUnmute", description: trans("meeting.audioMuteUnmute"), }; - +export const videoActiveInactive: EventConfigType = { + label: trans("meeting.videoActiveInactive"), + value: "videoActiveInactive", + description: trans("meeting.videoActiveInactive"), +}; export const InputEventHandlerControl = eventHandlerControl([ changeEvent, focusEvent, @@ -395,4 +399,5 @@ export const MeetingEventHandlerControl = eventHandlerControl([ screenShared, cameraView, audioMuteUnmute, + videoActiveInactive, ] as const); diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index eef64917d..654e4a29b 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1440,6 +1440,7 @@ export const en = { screenShared: "Screen Shared", screenSharedDesc: "Screen Shared", audioMuteUnmute: "Audio Mute", + videoActiveInactive: "Video Active Inactive", size: "Size", top: "Top", host: "Host", From 2dd01e53c6060afba91b896c5132301eaac0bdac Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Mon, 16 Oct 2023 14:17:21 +0300 Subject: [PATCH 28/43] Feat: video click event --- .../src/comps/comps/meetingComp/videoMeetingStreamComp.tsx | 1 + .../lowcoder/src/comps/controls/eventHandlerControl.tsx | 6 ++++++ client/packages/lowcoder/src/i18n/locales/en.ts | 1 + 3 files changed, 8 insertions(+) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index 7ac21b7b8..d3166145d 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -252,6 +252,7 @@ let VideoCompBuilder = (function (props) { props.onEvent("videoClicked")} ref={videoRef} $style={props.style} id={props.userId.value} diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index 6f0c3e389..e7c216bb6 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -368,6 +368,11 @@ export const videoActiveInactive: EventConfigType = { value: "videoActiveInactive", description: trans("meeting.videoActiveInactive"), }; +export const videoClicked: EventConfigType = { + label: trans("meeting.videoClicked"), + value: "videoClicked", + description: trans("meeting.videoClicked"), +}; export const InputEventHandlerControl = eventHandlerControl([ changeEvent, focusEvent, @@ -400,4 +405,5 @@ export const MeetingEventHandlerControl = eventHandlerControl([ cameraView, audioMuteUnmute, videoActiveInactive, + videoClicked, ] as const); diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 654e4a29b..5e023827c 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1440,6 +1440,7 @@ export const en = { screenShared: "Screen Shared", screenSharedDesc: "Screen Shared", audioMuteUnmute: "Audio Mute", + videoClicked: "Video Clicked", videoActiveInactive: "Video Active Inactive", size: "Size", top: "Top", From 03b21f05fc147a4a5f61f45e9d296d87048a62f4 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Tue, 17 Oct 2023 16:44:16 +0300 Subject: [PATCH 29/43] refactored/cleaned the code --- .../videoMeetingControllerComp.tsx | 31 ++-- .../meetingComp/videoMeetingStreamComp.tsx | 151 +++++++++--------- .../comps/controls/eventHandlerControl.tsx | 40 ++--- .../packages/lowcoder/src/i18n/locales/en.ts | 7 +- 4 files changed, 120 insertions(+), 109 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 6991eb897..2c5809d43 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -190,13 +190,14 @@ export const meetingControllerChildren = { audioControl: booleanExposingStateControl("false"), videoControl: booleanExposingStateControl("true"), endCall: booleanExposingStateControl("false"), - sharingScreen: booleanExposingStateControl("false"), + sharing: booleanExposingStateControl("false"), videoSettings: jsonObjectExposingStateControl(""), videoWidth: numberExposingStateControl("videoWidth", 200), videoHeight: numberExposingStateControl("videoHeight", 200), appId: withDefault(StringControl, trans("meeting.appid")), participants: stateComp([]), - host: stringExposingStateControl("host"), + usersScreenShared: stateComp([]), + localUser: jsonObjectExposingStateControl(""), meetingName: stringExposingStateControl("meetingName"), }; let MTComp = (function () { @@ -231,8 +232,6 @@ let MTComp = (function () { useEffect(() => { if (props.endCall.value) { let newUsers = userIds.filter((item: any) => item.user !== userId); - console.log("newUsers", newUsers, userId); - dispatch( changeChildAction("participants", getData(newUsers).data, false) ); @@ -241,7 +240,11 @@ let MTComp = (function () { useEffect(() => { client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - let userData = { user: user.uid, host: false }; + let userData = { + user: user.uid, + host: false, + audiostatus: user.hasVideo, + }; if (userIds.length == 0) { userData.host = true; } else { @@ -391,9 +394,9 @@ MTComp = withMethodExposing(MTComp, [ params: [], }, execute: async (comp, values) => { - let sharing = !comp.children.sharingScreen.getView().value; - comp.children.sharingScreen.change(sharing); + let sharing = !comp.children.sharing.getView().value; await shareScreen(sharing); + comp.children.sharing.change(sharing); }, }, { @@ -404,6 +407,11 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { let value = !comp.children.audioControl.getView().value; + let localUserData = comp.children.localUser.change({ + user: userId + "", + audiostatus: value, + }); + console.log(localUserData); await turnOnMicrophone(value); comp.children.audioControl.change(value); }, @@ -421,7 +429,7 @@ MTComp = withMethodExposing(MTComp, [ } else { await turnOnCamera(value); } - + comp.children.videoControl.change(value); }, }, @@ -433,7 +441,10 @@ MTComp = withMethodExposing(MTComp, [ }, execute: async (comp, values) => { userId = Math.floor(100000 + Math.random() * 900000); - comp.children.host.change(userId + ""); + comp.children.localUser.change({ + user: userId + "", + audiostatus: false, + }); await publishVideo( comp.children.appId.getView(), comp.children.meetingName.getView().value == "" @@ -470,7 +481,7 @@ MTComp = withMethodExposing(MTComp, [ export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("visible", trans("export.visibleDesc")), new NameConfig("appId", trans("meeting.appid")), - new NameConfig("host", trans("meeting.host")), + new NameConfig("localUser", trans("meeting.host")), new NameConfig("participants", trans("meeting.participants")), new NameConfig("meetingName", trans("meeting.meetingName")), ]); diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index d3166145d..d468b637d 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -25,12 +25,11 @@ import { IForm } from "../formComp/formDataConstants"; import { SimpleNameComp } from "../simpleNameComp"; import { ButtonStyleControl } from "./videobuttonCompConstants"; import { RefControl } from "comps/controls/refControl"; -import { useEffect, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; import { client, - meetingControllerChildren, } from "./videoMeetingControllerComp"; import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; @@ -61,8 +60,7 @@ const Container = styled.div<{ $style: any }>` display: flex; align-items: center; justify-content: center; -`; // ${(props) => props.$style && getStyle(props.$style)} - they should be applyed to VideoContainer only - +`; const VideoContainer = styled.video<{ $style: any }>` height: 100%; width: 100%; @@ -154,13 +152,9 @@ const typeOptions = [ }, ] as const; -export const videoShared = () => { - console.log("data"); -}; export const meetingStreamChildren = { autoHeight: withDefault(AutoHeightControl, "fixed"), type: dropdownControl(typeOptions, ""), - // onEvent: ButtonEventHandlerControl, onEvent: MeetingEventHandlerControl, disabled: BoolCodeControl, loading: BoolCodeControl, @@ -169,27 +163,28 @@ export const meetingStreamChildren = { suffixIcon: IconControl, style: ButtonStyleControl, viewRef: RefControl, - // viewRef: RefControl, - userId: stringExposingStateControl("user id", trans("meeting.userId")), + userId: stringExposingStateControl(""), }; let VideoCompBuilder = (function (props) { - return ( - new UICompBuilder(meetingStreamChildren, (props) => { - const videoRef = useRef(null); - const conRef = useRef(null); + return new UICompBuilder(meetingStreamChildren, (props) => { + const videoRef = useRef(null); + const conRef = useRef(null); + const [userId, setUserId] = useState(); - useEffect(() => { - onResize(); - }, []); + useEffect(() => { + onResize(); + }, []); - const onResize = async () => { - const container = conRef.current; - let videoCo = videoRef.current; - videoCo!.style.height = container?.clientHeight + "px"; - videoCo!.style.width = container?.clientWidth + "px"; - }; - useEffect(() => { + const onResize = async () => { + const container = conRef.current; + let videoCo = videoRef.current; + videoCo!.style.height = container?.clientHeight + "px"; + videoCo!.style.width = container?.clientWidth + "px"; + }; + useEffect(() => { + if (props.userId.value !== "") { + let userData = JSON.parse(props.userId?.value); client.on( "user-published", async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { @@ -198,10 +193,10 @@ let VideoCompBuilder = (function (props) { let userId = user.uid + ""; if ( user.hasVideo && - user.uid + "" != props.userId.value && - props.userId.value != "" + user.uid + "" != userData.user && + userData.user != "" ) { - props.onEvent("videoActiveInactive"); + props.onEvent("videoOn"); } const element = document.getElementById(userId); if (element) { @@ -212,10 +207,12 @@ let VideoCompBuilder = (function (props) { const remoteTrack = await client.subscribe(user, mediaType); if ( user.hasAudio && - user.uid + "" != props.userId.value && - props.userId.value != "" + user.uid + "" != userData.user && + userData.user != "" ) { - props.onEvent("audioMuteUnmute"); + userData.audiostatus = user.hasVideo; + + props.onEvent("audioUnmuted"); } remoteTrack.play(); } @@ -227,67 +224,67 @@ let VideoCompBuilder = (function (props) { if (mediaType === "audio") { if ( !user.hasAudio && - user.uid + "" != props.userId.value && - props.userId.value != "" + user.uid + "" != userData.user && + userData.user != "" ) { - props.onEvent("audioMuteUnmute"); + userData.audiostatus = user.hasVideo; + props.onEvent("audioMuted"); } } if (mediaType === "video") { if ( !user.hasVideo && - user.uid + "" != props.userId.value && - props.userId.value != "" + user.uid + "" != userData.user && + userData.user != "" ) { - props.onEvent("videoActiveInactive"); + props.onEvent("videoOff"); } } } ); - }, [props.userId.value]); + setUserId(userData.user); + } + }, [props.userId.value]); - return ( - - {(editorState) => ( - - - props.onEvent("videoClicked")} - ref={videoRef} - $style={props.style} - id={props.userId.value} - > - - - )} - - ); - }) - .setPropertyViewFn((children) => ( - <> -
- {children.userId.propertyView({ label: trans("meeting.videoId") })} - {children.autoHeight.getPropertyView()} -
-
- {children.onEvent.getPropertyView()} -
-
- {hiddenPropertyView(children)} -
-
- {children.style.getPropertyView()} -
- - )) - // .setExposeMethodConfigs(refMethods([shareMethod])) - .build() - ); + + + return ( + + {(editorState) => ( + + + props.onEvent("videoClicked")} + ref={videoRef} + $style={props.style} + id={userId} + > + + + )} + + ); + }) + .setPropertyViewFn((children) => ( + <> +
+ {children.userId.propertyView({ label: trans("meeting.videoId") })} + {children.autoHeight.getPropertyView()} +
+
+ {children.onEvent.getPropertyView()} +
+
+ {hiddenPropertyView(children)} +
+
+ {children.style.getPropertyView()} +
+ + )) + .build(); })(); -// interface BaseStreamRef { -// shared: () => void; -// } VideoCompBuilder = class extends VideoCompBuilder { override autoHeight(): boolean { return this.children.autoHeight.getView(); diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index e7c216bb6..29b3093de 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -348,25 +348,25 @@ export const mentionEvent: EventConfigType = { value: "mention", description: trans("event.mentionDesc"), }; -export const screenShared: EventConfigType = { - label: trans("meeting.screenShared"), - value: "screenShared", - description: trans("meeting.screenSharedDesc"), +export const audioUnmuted: EventConfigType = { + label: trans("meeting.audioUnmuted"), + value: "audioUnmuted", + description: trans("meeting.audioUnmuted"), }; -export const cameraView: EventConfigType = { - label: trans("meeting.cameraView"), - value: "cameraView", - description: trans("meeting.cameraViewDesc"), +export const audioMuted: EventConfigType = { + label: trans("meeting.audioMuted"), + value: "audioMuted", + description: trans("meeting.audioMuted"), }; -export const audioMuteUnmute: EventConfigType = { - label: trans("meeting.audioMuteUnmute"), - value: "audioMuteUnmute", - description: trans("meeting.audioMuteUnmute"), +export const videoOff: EventConfigType = { + label: trans("meeting.videoOff"), + value: "videoOff", + description: trans("meeting.videoOff"), }; -export const videoActiveInactive: EventConfigType = { - label: trans("meeting.videoActiveInactive"), - value: "videoActiveInactive", - description: trans("meeting.videoActiveInactive"), +export const videoOn: EventConfigType = { + label: trans("meeting.videoOn"), + value: "videoOn", + description: trans("meeting.videoOn"), }; export const videoClicked: EventConfigType = { label: trans("meeting.videoClicked"), @@ -401,9 +401,9 @@ export const ScannerEventHandlerControl = eventHandlerControl([ ] as const); export const MeetingEventHandlerControl = eventHandlerControl([ - screenShared, - cameraView, - audioMuteUnmute, - videoActiveInactive, + audioMuted, + audioUnmuted, + videoOff, + videoOn, videoClicked, ] as const); diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 5e023827c..2869d3183 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1439,9 +1439,11 @@ export const en = { cameraViewDesc: "Camera View", screenShared: "Screen Shared", screenSharedDesc: "Screen Shared", - audioMuteUnmute: "Audio Mute", + audioUnmuted: "Audio Unmuted", + audioMuted: "Audio Muted", videoClicked: "Video Clicked", - videoActiveInactive: "Video Active Inactive", + videoOff: "Video Off", + videoOn: "Video On", size: "Size", top: "Top", host: "Host", @@ -1451,6 +1453,7 @@ export const en = { right: "Right", bottom: "Bottom", videoId: "Video Id", + audioStatus: "audio status", left: "Left", widthTooltip: "Number or percentage, e.g. 520, 60%", heightTooltip: "Number, e.g. 378", From 6964628af9ba5c391244e6ea4cc4cf773b398e3b Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Wed, 18 Oct 2023 00:18:52 +0200 Subject: [PATCH 30/43] new: add keycloak authentication --- .../sdk/auth/Oauth2KeycloakAuthConfig.java | 50 +++++++ .../sdk/auth/Oauth2OryAuthConfig.java | 14 +- .../sdk/auth/Oauth2SimpleAuthConfig.java | 1 + .../sdk/auth/constants/AuthTypeConstants.java | 1 + .../sdk/auth/constants/Oauth2Constants.java | 10 +- .../sdk/constants/AuthSourceConstants.java | 2 + .../java/org/lowcoder/sdk/util/JsonUtils.java | 2 + .../AuthenticationController.java | 22 +-- .../oauth2/Oauth2AuthRequestFactory.java | 6 +- .../request/oauth2/Oauth2DefaultSource.java | 19 +++ .../oauth2/request/KeycloakRequest.java | 125 ++++++++++++++++++ .../factory/AuthConfigFactoryImpl.java | 33 ++++- 12 files changed, 258 insertions(+), 27 deletions(-) create mode 100644 server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2KeycloakAuthConfig.java create mode 100644 server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/KeycloakRequest.java diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2KeycloakAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2KeycloakAuthConfig.java new file mode 100644 index 000000000..a6395f972 --- /dev/null +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2KeycloakAuthConfig.java @@ -0,0 +1,50 @@ +package org.lowcoder.sdk.auth; + +import static org.lowcoder.sdk.auth.constants.Oauth2Constants.INSTANCE_ID_PLACEHOLDER; +import static org.lowcoder.sdk.auth.constants.Oauth2Constants.REALM_PLACEHOLDER; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Getter; + +/** + * + * Keycloak OAuth configuration. + */ +@Getter +public class Oauth2KeycloakAuthConfig extends Oauth2SimpleAuthConfig +{ + protected String instanceId; + protected String realm; + + @JsonCreator + public Oauth2KeycloakAuthConfig( + @JsonProperty("id") String id, + @JsonProperty("enable") Boolean enable, + @JsonProperty("enableRegister") Boolean enableRegister, + @JsonProperty("source") String source, + @JsonProperty("sourceName") String sourceName, + @JsonProperty("clientId") String clientId, + @JsonProperty("clientSecret") String clientSecret, + @JsonProperty("instanceId") String instanceId, + @JsonProperty("realm") String realm, + @JsonProperty("authType") String authType) + { + super(id, enable, enableRegister, source, sourceName, clientId, clientSecret, authType); + this.instanceId = instanceId; + this.realm = realm; + } + + + + @Override + public String replaceAuthUrlClientIdPlaceholder(String url) + { + return super.replaceAuthUrlClientIdPlaceholder(url) + .replace(INSTANCE_ID_PLACEHOLDER, instanceId) + .replace(REALM_PLACEHOLDER, realm); + } + + +} diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2OryAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2OryAuthConfig.java index 8082a62cb..345e05b96 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2OryAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2OryAuthConfig.java @@ -1,18 +1,12 @@ package org.lowcoder.sdk.auth; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonView; -import lombok.Getter; -import org.apache.commons.lang3.StringUtils; -import org.lowcoder.sdk.auth.constants.AuthTypeConstants; -import org.lowcoder.sdk.auth.constants.Oauth2Constants; -import org.lowcoder.sdk.config.SerializeConfig.JsonViews; +import static org.lowcoder.sdk.auth.constants.Oauth2Constants.INSTANCE_ID_PLACEHOLDER; import javax.annotation.Nullable; -import java.util.function.Function; -import static org.lowcoder.sdk.auth.constants.Oauth2Constants.CLIENT_ID_PLACEHOLDER; -import static org.lowcoder.sdk.auth.constants.Oauth2Constants.INSTANCE_ID_PLACEHOLDER; +import com.fasterxml.jackson.annotation.JsonCreator; + +import lombok.Getter; /** * OAuth2 ORY auth config. diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java index 7ab980785..907edbb1c 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/Oauth2SimpleAuthConfig.java @@ -53,6 +53,7 @@ public String getAuthorizeUrl() { case AuthTypeConstants.GOOGLE -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.GOOGLE_AUTHORIZE_URL); case AuthTypeConstants.GITHUB -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.GITHUB_AUTHORIZE_URL); case AuthTypeConstants.ORY -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.ORY_AUTHORIZE_URL); + case AuthTypeConstants.KEYCLOAK -> replaceAuthUrlClientIdPlaceholder(Oauth2Constants.KEYCLOAK_AUTHORIZE_URL); default -> null; }; } diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java index bed41b4f8..f2d4076bd 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/AuthTypeConstants.java @@ -9,4 +9,5 @@ public class AuthTypeConstants { public static final String GOOGLE = "GOOGLE"; public static final String GITHUB = "GITHUB"; public static final String ORY = "ORY"; + public static final String KEYCLOAK = "KEYCLOAK"; } diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/Oauth2Constants.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/Oauth2Constants.java index c6e686322..6313af520 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/Oauth2Constants.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/auth/constants/Oauth2Constants.java @@ -6,8 +6,9 @@ public class Oauth2Constants { public static final String CLIENT_ID_PLACEHOLDER = "$CLIENT_ID"; public static final String REDIRECT_URL_PLACEHOLDER = "$REDIRECT_URL"; public static final String STATE_PLACEHOLDER = "$STATE"; + public static final String REALM_PLACEHOLDER = "$REALM"; - public static final String INSTANCE_ID_PLACEHOLDER = "INSTANCE_ID"; + public static final String INSTANCE_ID_PLACEHOLDER = "$INSTANCE_ID"; // authorize url public static final String GITHUB_AUTHORIZE_URL = "https://github.com/login/oauth/authorize" @@ -32,4 +33,11 @@ public class Oauth2Constants { + "&redirect_uri=" + REDIRECT_URL_PLACEHOLDER + "&state=" + STATE_PLACEHOLDER + "&scope=openid email profile offline_access"; + + public static final String KEYCLOAK_AUTHORIZE_URL = "https://" + INSTANCE_ID_PLACEHOLDER + "/realms/" + REALM_PLACEHOLDER + "/protocol/openid-connect/auth" + + "?response_type=code" + + "&client_id=" + CLIENT_ID_PLACEHOLDER + + "&redirect_uri=" + REDIRECT_URL_PLACEHOLDER + + "&state=" + STATE_PLACEHOLDER + + "&scope=openid email profile"; } diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/constants/AuthSourceConstants.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/constants/AuthSourceConstants.java index 073d333d0..c82d42d21 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/constants/AuthSourceConstants.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/constants/AuthSourceConstants.java @@ -11,11 +11,13 @@ public class AuthSourceConstants { public static final String GOOGLE = "GOOGLE"; public static final String GITHUB = "GITHUB"; public static final String ORY = "ORY"; + public static final String KEYCLOAK = "KEYCLOAK"; // source name public static final String GOOGLE_NAME = "Google"; public static final String GITHUB_NAME = "Github"; public static final String ORY_NAME = "Ory"; + public static final String KEYCLOAK_NAME = "Keycloak"; // default source and source name for common protocol // oauth 2.0 diff --git a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java index eedb3fe42..19e52ed60 100644 --- a/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java +++ b/server/api-service/lowcoder-sdk/src/main/java/org/lowcoder/sdk/util/JsonUtils.java @@ -8,6 +8,7 @@ import javax.annotation.Nullable; import org.lowcoder.sdk.auth.EmailAuthConfig; +import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; import org.lowcoder.sdk.auth.Oauth2OryAuthConfig; import org.lowcoder.sdk.auth.Oauth2SimpleAuthConfig; @@ -46,6 +47,7 @@ public final class JsonUtils { OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2SimpleAuthConfig.class, GITHUB)); OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2SimpleAuthConfig.class, GOOGLE)); OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2OryAuthConfig.class, ORY)); + OBJECT_MAPPER.registerSubtypes(new NamedType(Oauth2KeycloakAuthConfig.class, KEYCLOAK)); } public static final JsonNode EMPTY_JSON_NODE = createObjectNode(); diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java index 0d2829fff..7017da2fc 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java @@ -1,7 +1,7 @@ package org.lowcoder.api.authentication; -import com.fasterxml.jackson.annotation.JsonView; -import lombok.extern.slf4j.Slf4j; +import java.util.List; + import org.lowcoder.api.authentication.dto.AuthConfigRequest; import org.lowcoder.api.authentication.service.AuthenticationApiService; import org.lowcoder.api.framework.view.ResponseView; @@ -9,7 +9,6 @@ import org.lowcoder.api.usermanagement.UserController; import org.lowcoder.api.usermanagement.UserController.UpdatePasswordRequest; import org.lowcoder.api.util.BusinessEventPublisher; -import org.lowcoder.domain.authentication.AuthenticationService; import org.lowcoder.domain.authentication.FindAuthConfig; import org.lowcoder.infra.constant.NewUrl; import org.lowcoder.sdk.auth.AbstractAuthConfig; @@ -17,13 +16,20 @@ import org.lowcoder.sdk.constants.AuthSourceConstants; import org.lowcoder.sdk.util.CookieHelper; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; -import java.util.List; +import com.fasterxml.jackson.annotation.JsonView; + +import reactor.core.publisher.Mono; -@Slf4j @RestController @RequestMapping(value = {NewUrl.CUSTOM_AUTH}) public class AuthenticationController { @@ -36,8 +42,6 @@ public class AuthenticationController { private CookieHelper cookieHelper; @Autowired private BusinessEventPublisher businessEventPublisher; - @Autowired - private AuthenticationService authenticationService; /** * login by email or phone with password; or register by email for now. diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java index 84794e494..c8fdae9b2 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2AuthRequestFactory.java @@ -7,7 +7,9 @@ import org.lowcoder.api.authentication.request.oauth2.request.AbstractOauth2Request; import org.lowcoder.api.authentication.request.oauth2.request.GithubRequest; import org.lowcoder.api.authentication.request.oauth2.request.GoogleRequest; +import org.lowcoder.api.authentication.request.oauth2.request.KeycloakRequest; import org.lowcoder.api.authentication.request.oauth2.request.OryRequest; +import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; import org.lowcoder.sdk.auth.Oauth2OryAuthConfig; import org.lowcoder.sdk.auth.Oauth2SimpleAuthConfig; import org.springframework.stereotype.Component; @@ -29,6 +31,7 @@ private AbstractOauth2Request buildRequest(OAu case GITHUB -> new GithubRequest((Oauth2SimpleAuthConfig) context.getAuthConfig()); case GOOGLE -> new GoogleRequest((Oauth2SimpleAuthConfig) context.getAuthConfig()); case ORY -> new OryRequest((Oauth2OryAuthConfig) context.getAuthConfig()); + case KEYCLOAK -> new KeycloakRequest((Oauth2KeycloakAuthConfig)context.getAuthConfig()); default -> throw new UnsupportedOperationException(context.getAuthConfig().getAuthType()); }; } @@ -38,6 +41,7 @@ public Set supportedAuthTypes() { return Set.of( GITHUB, GOOGLE, - ORY); + ORY, + KEYCLOAK); } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java index c0242d153..a36cc1f5e 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java @@ -55,5 +55,24 @@ public String refresh() { return "https://" + Oauth2Constants.INSTANCE_ID_PLACEHOLDER + "/oauth2/token"; } + }, + + KEYCLOAK { + + @Override + public String accessToken() { + return "http://" + Oauth2Constants.INSTANCE_ID_PLACEHOLDER + "/realms/" + Oauth2Constants.REALM_PLACEHOLDER + "/protocol/openid-connect/token"; + } + + @Override + public String userInfo() { + return "http://" + Oauth2Constants.INSTANCE_ID_PLACEHOLDER + "/realms/" + Oauth2Constants.REALM_PLACEHOLDER + "/protocol/openid-connect/userinfo"; + } + + @Override + public String refresh() { + return "http://" + Oauth2Constants.INSTANCE_ID_PLACEHOLDER + "/realms/" + Oauth2Constants.REALM_PLACEHOLDER + "/protocol/openid-connect/token"; + } + } } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/KeycloakRequest.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/KeycloakRequest.java new file mode 100644 index 000000000..31dcd650d --- /dev/null +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/request/KeycloakRequest.java @@ -0,0 +1,125 @@ +package org.lowcoder.api.authentication.request.oauth2.request; + +import static org.springframework.web.reactive.function.BodyInserters.fromFormData; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; + +import org.apache.commons.collections4.MapUtils; +import org.apache.http.client.utils.URIBuilder; +import org.lowcoder.api.authentication.request.AuthException; +import org.lowcoder.api.authentication.request.oauth2.OAuth2RequestContext; +import org.lowcoder.api.authentication.request.oauth2.Oauth2DefaultSource; +import org.lowcoder.domain.user.model.AuthToken; +import org.lowcoder.domain.user.model.AuthUser; +import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; +import org.lowcoder.sdk.util.JsonUtils; +import org.lowcoder.sdk.webclient.WebClientBuildHelper; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.MediaType; + +import reactor.core.publisher.Mono; + +public class KeycloakRequest extends AbstractOauth2Request +{ + + public KeycloakRequest(Oauth2KeycloakAuthConfig config) + { + super(config, Oauth2DefaultSource.KEYCLOAK); + } + + @Override + protected Mono getAuthToken(OAuth2RequestContext context) { + URI uri; + try { + uri = new URIBuilder(config.replaceAuthUrlClientIdPlaceholder(source.accessToken())).build(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .post() + .uri(uri) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(fromFormData("code", context.getCode()) + .with("client_id", config.getClientId()) + .with("client_secret", config.getClientSecret()) + .with("grant_type", "authorization_code") + .with("redirect_uri", context.getRedirectUrl())) + .exchangeToMono(response -> response.bodyToMono(new ParameterizedTypeReference>() { + })) + .flatMap(map -> { + if (map.containsKey("error") || map.containsKey("error_description")) { + throw new AuthException(JsonUtils.toJson(map)); + } + AuthToken authToken = AuthToken.builder() + .accessToken(MapUtils.getString(map, "access_token")) + .expireIn(MapUtils.getIntValue(map, "expires_in")) + .refreshToken(MapUtils.getString(map, "refresh_token")) + .build(); + return Mono.just(authToken); + }); + } + + @Override + protected Mono refreshAuthToken(String refreshToken) { + + URI uri; + try { + uri = new URIBuilder(config.replaceAuthUrlClientIdPlaceholder(source.refresh())).build(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .post() + .uri(uri) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(fromFormData("refresh_token", refreshToken) + .with("client_id", config.getClientId()) + .with("client_secret", config.getClientSecret()) + .with("grant_type", "refresh_token")) + .exchangeToMono(response -> response.bodyToMono(new ParameterizedTypeReference>() { + })) + .flatMap(map -> { + if (map.containsKey("error") || map.containsKey("error_description")) { + throw new AuthException(JsonUtils.toJson(map)); + } + AuthToken authToken = AuthToken.builder() + .accessToken(MapUtils.getString(map, "access_token")) + .expireIn(MapUtils.getIntValue(map, "expires_in")) + .refreshToken(MapUtils.getString(map, "refresh_token")) + .build(); + return Mono.just(authToken); + }); + + } + + @Override + protected Mono getAuthUser(AuthToken authToken) { + return WebClientBuildHelper.builder() + .systemProxy() + .build() + .post() + .uri(config.replaceAuthUrlClientIdPlaceholder(source.userInfo())) + .header("Authorization", "Bearer " + authToken.getAccessToken()) + .exchangeToMono(response -> response.bodyToMono(new ParameterizedTypeReference>() { + })) + .flatMap(map -> { + if (map.containsKey("error") || map.containsKey("error_description")) { + throw new AuthException(JsonUtils.toJson(map)); + } + AuthUser authUser = AuthUser.builder() + .uid(MapUtils.getString(map, "sub")) + .username(MapUtils.getString(map, "name")) + .rawUserInfo(map) + .build(); + return Mono.just(authUser); + }); + } +} diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java index b5434c8e0..82a8b331a 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/service/factory/AuthConfigFactoryImpl.java @@ -1,19 +1,23 @@ package org.lowcoder.api.authentication.service.factory; +import static java.util.Objects.requireNonNull; +import static org.lowcoder.sdk.constants.AuthSourceConstants.GITHUB; +import static org.lowcoder.sdk.constants.AuthSourceConstants.GITHUB_NAME; +import static org.lowcoder.sdk.constants.AuthSourceConstants.GOOGLE; +import static org.lowcoder.sdk.constants.AuthSourceConstants.GOOGLE_NAME; + +import java.util.Set; + import org.apache.commons.collections4.MapUtils; import org.lowcoder.api.authentication.dto.AuthConfigRequest; import org.lowcoder.sdk.auth.AbstractAuthConfig; import org.lowcoder.sdk.auth.EmailAuthConfig; +import org.lowcoder.sdk.auth.Oauth2KeycloakAuthConfig; import org.lowcoder.sdk.auth.Oauth2OryAuthConfig; import org.lowcoder.sdk.auth.Oauth2SimpleAuthConfig; import org.lowcoder.sdk.auth.constants.AuthTypeConstants; import org.springframework.stereotype.Component; -import java.util.Set; - -import static java.util.Objects.requireNonNull; -import static org.lowcoder.sdk.constants.AuthSourceConstants.*; - @Component public class AuthConfigFactoryImpl implements AuthConfigFactory { @@ -24,6 +28,7 @@ public AbstractAuthConfig build(AuthConfigRequest authConfigRequest, boolean ena case AuthTypeConstants.GITHUB -> buildOauth2SimpleAuthConfig(GITHUB, GITHUB_NAME, authConfigRequest, enable); case AuthTypeConstants.GOOGLE -> buildOauth2SimpleAuthConfig(GOOGLE, GOOGLE_NAME, authConfigRequest, enable); case AuthTypeConstants.ORY -> buildOauth2OryAuthConfig(authConfigRequest, enable); + case AuthTypeConstants.KEYCLOAK -> buildOauth2KeycloakAuthConfig(authConfigRequest, enable); default -> throw new UnsupportedOperationException(authConfigRequest.getAuthType()); }; } @@ -34,7 +39,8 @@ public Set supportAuthTypes() { AuthTypeConstants.FORM, AuthTypeConstants.GITHUB, AuthTypeConstants.GOOGLE, - AuthTypeConstants.ORY + AuthTypeConstants.ORY, + AuthTypeConstants.KEYCLOAK ); } @@ -68,4 +74,19 @@ private Oauth2SimpleAuthConfig buildOauth2OryAuthConfig(AuthConfigRequest authCo authConfigRequest.getInstanceId(), authConfigRequest.getAuthType()); } + + private Oauth2SimpleAuthConfig buildOauth2KeycloakAuthConfig(AuthConfigRequest authConfigRequest, boolean enable) { + return new Oauth2KeycloakAuthConfig( + authConfigRequest.getId(), + enable, + authConfigRequest.isEnableRegister(), + AuthTypeConstants.KEYCLOAK, + org.lowcoder.sdk.constants.AuthSourceConstants.KEYCLOAK_NAME, + requireNonNull(authConfigRequest.getClientId(), "clientId can not be null."), + authConfigRequest.getClientSecret(), + authConfigRequest.getInstanceId(), + authConfigRequest.getString("realm"), + authConfigRequest.getAuthType()); + } + } From 8f85d57a6ad14c5c37fdbd051965c5a5838eb033 Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Wed, 18 Oct 2023 09:18:59 +0200 Subject: [PATCH 31/43] fix: fix github refresh token link --- .../api/authentication/request/oauth2/Oauth2DefaultSource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java index a36cc1f5e..70a7cc776 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/request/oauth2/Oauth2DefaultSource.java @@ -1,6 +1,7 @@ package org.lowcoder.api.authentication.request.oauth2; import org.lowcoder.sdk.auth.constants.Oauth2Constants; +import org.springframework.security.config.oauth2.client.CommonOAuth2Provider; public enum Oauth2DefaultSource implements Oauth2Source { @@ -17,7 +18,7 @@ public String userInfo() { @Override public String refresh() { - return "https://www.googleapis.com/oauth2/v4/token"; + return "https://github.com/login/oauth/access_token"; } }, From 742009597b0bd085a3c837597cd481dae48e6023 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Wed, 18 Oct 2023 14:30:02 +0300 Subject: [PATCH 32/43] Fix: audio echo on the local user --- .../src/comps/comps/meetingComp/videoMeetingControllerComp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 2c5809d43..11dc31d65 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -119,7 +119,7 @@ const turnOnMicrophone = async (flag?: boolean) => { return audioTrack.setEnabled(flag!); } audioTrack = await AgoraRTC.createMicrophoneAudioTrack(); - audioTrack.play(); + // audioTrack.play(); if (!flag) { await client.unpublish(audioTrack); From bcde50c998ac4cc8bb4e25111de5d927a99b8318 Mon Sep 17 00:00:00 2001 From: Ludo Mikula Date: Wed, 18 Oct 2023 16:40:26 +0200 Subject: [PATCH 33/43] fix: update syntax for spring security 6 --- .../framework/security/SecurityConfig.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/security/SecurityConfig.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/security/SecurityConfig.java index f7221862a..6f3f2f211 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/security/SecurityConfig.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/security/SecurityConfig.java @@ -15,6 +15,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.SecurityWebFiltersOrder; @@ -66,27 +67,24 @@ public class SecurityConfig { AuthRequestFactory authRequestFactory; @Bean - public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { + SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { if (!commonConfig.getSecurity().getForbiddenEndpoints().isEmpty()) { - http.authorizeExchange() - .matchers( - commonConfig.getSecurity().getForbiddenEndpoints().stream() + http.authorizeExchange(customizer -> customizer + .matchers(commonConfig.getSecurity().getForbiddenEndpoints().stream() .map(apiEndpoint -> ServerWebExchangeMatchers.pathMatchers(apiEndpoint.getMethod(), apiEndpoint.getUri())) .toArray(size -> new ServerWebExchangeMatcher[size]) - ).denyAll(); + ).denyAll() + ); } - http.cors() - .configurationSource(buildCorsConfigurationSource()) - .and() - .csrf().disable() - .anonymous().principal(createAnonymousUser()) - .and() - .httpBasic() - .and() - .authorizeExchange() + http + .cors(cors -> cors.configurationSource(buildCorsConfigurationSource())) + .csrf(csrf -> csrf.disable()) + .anonymous(anonymous -> anonymous.principal(createAnonymousUser())) + .httpBasic(Customizer.withDefaults()) + .authorizeExchange(customizer -> customizer .matchers( ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, CUSTOM_AUTH + "/otp/send"), // sms verification ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, CUSTOM_AUTH + "/phone/login"), @@ -134,19 +132,21 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, NewUrl.DATASOURCE_URL + "/jsDatasourcePlugins"), ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/api/docs/**") ) - .permitAll() + .permitAll() .pathMatchers("/api/**") - .authenticated() + .authenticated() .pathMatchers("/test/**") - .authenticated() + .authenticated() .pathMatchers("/**") - .permitAll() + .permitAll() .anyExchange() - .authenticated(); + .authenticated() + ); - http.exceptionHandling() + http.exceptionHandling(customizer -> customizer .authenticationEntryPoint(serverAuthenticationEntryPoint) - .accessDeniedHandler(accessDeniedHandler); + .accessDeniedHandler(accessDeniedHandler) + ); http.addFilterBefore(new UserSessionPersistenceFilter(sessionUserService, cookieHelper, authenticationService, authenticationApiService, authRequestFactory), SecurityWebFiltersOrder.AUTHENTICATION); From 8c40725da14fab8273d035fe896c2f163d0f3b90 Mon Sep 17 00:00:00 2001 From: Abdul Qadir Date: Thu, 19 Oct 2023 00:55:06 +0500 Subject: [PATCH 34/43] Fix to allow first user(admin) to sign up --- .../AuthenticationServiceImpl.java | 24 +++++++++++++++---- .../service/OrgMemberService.java | 2 ++ .../service/OrgMemberServiceImpl.java | 7 ++++++ .../birelation/BiRelationRepository.java | 2 ++ .../infra/birelation/BiRelationService.java | 4 ++++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java index 7f7a8b7af..c82054153 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/authentication/AuthenticationServiceImpl.java @@ -1,6 +1,7 @@ package org.lowcoder.domain.authentication; import lombok.extern.slf4j.Slf4j; +import org.lowcoder.domain.organization.service.OrgMemberService; import org.lowcoder.domain.organization.service.OrganizationService; import org.lowcoder.sdk.auth.AbstractAuthConfig; import org.lowcoder.sdk.auth.EmailAuthConfig; @@ -26,6 +27,10 @@ public class AuthenticationServiceImpl implements AuthenticationService { @Autowired private OrganizationService organizationService; + + @Autowired + private OrgMemberService orgMemberService; + @Autowired private CommonConfig commonConfig; @Autowired @@ -51,7 +56,16 @@ private Mono findAuthConfig(String orgId, Function findAllAuthConfigs(String orgId, boolean enableOnly) { - return findAllAuthConfigsByDomain() + + Mono emailAuthConfigMono = orgMemberService.doesAtleastOneAdminExist() + .map(doesAtleastOneAdminExist -> { + boolean shouldEnableRegister = !doesAtleastOneAdminExist && authProperties.getEmail().isEnableRegister(); + return new FindAuthConfig + (new EmailAuthConfig(AuthSourceConstants.EMAIL, authProperties.getEmail().isEnable(), shouldEnableRegister), null); + }); + + + Flux findAuthConfigFlux = findAllAuthConfigsByDomain() .switchIfEmpty(findAllAuthConfigsForEnterpriseMode()) .switchIfEmpty(findAllAuthConfigsForSaasMode(orgId)) .filter(findAuthConfig -> { @@ -59,10 +73,10 @@ public Flux findAllAuthConfigs(String orgId, boolean enableOnly) return findAuthConfig.authConfig().isEnable(); } return true; - }) - .concatWithValues(new FindAuthConfig - (new EmailAuthConfig(AuthSourceConstants.EMAIL, authProperties.getEmail().isEnable(), - authProperties.getEmail().isEnableRegister()), null)); + }); + + return Flux.concat(findAuthConfigFlux, emailAuthConfigMono); + } private Flux findAllAuthConfigsByDomain() { diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberService.java index e027efcf6..bc2627dd8 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberService.java @@ -24,6 +24,8 @@ public interface OrgMemberService { Mono getOrgMemberCount(String orgId); + Mono doesAtleastOneAdminExist(); + Mono countAllActiveOrgs(String userId); Mono getOrgMember(String orgId, String userId); diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java index 5d0b4fd08..9e6fb1b23 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/organization/service/OrgMemberServiceImpl.java @@ -125,6 +125,13 @@ public Mono getOrgMemberCount(String orgId) { return biRelationService.countBySourceId(ORG_MEMBER, orgId); } + @Override + public Mono doesAtleastOneAdminExist() { + return biRelationService.countByRelation(ORG_MEMBER, MemberRole.ADMIN.getValue()) + .single() + .map(count -> count != 0); + } + @Override public Mono addMember(String orgId, String userId, MemberRole memberRole) { return biRelationService.addBiRelation(ORG_MEMBER, orgId, diff --git a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationRepository.java b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationRepository.java index 6a3a7c424..65eb27074 100644 --- a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationRepository.java +++ b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationRepository.java @@ -26,6 +26,8 @@ public interface BiRelationRepository extends ReactiveMongoRepository findByBizTypeAndSourceIdAndRelation(BiRelationBizType bizType, String sourceId, String relation); + Mono countByBizTypeAndRelation(BiRelationBizType bizType, String relation); + Mono countByBizTypeAndSourceId(BiRelationBizType bizType, String sourceId); Mono countByBizTypeAndTargetId(BiRelationBizType bizType, String targetId); diff --git a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationService.java b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationService.java index 43dac65c9..ebb8d9c29 100644 --- a/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationService.java +++ b/server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/birelation/BiRelationService.java @@ -166,6 +166,10 @@ public Flux getBySourceIdAndRelation(BiRelationBizType bizType, Stri return biRelationRepository.findByBizTypeAndSourceIdAndRelation(bizType, sourceId, relation); } + public Mono countByRelation(BiRelationBizType bizType, String relation) { + return biRelationRepository.countByBizTypeAndRelation(bizType, relation); + } + public Mono countBySourceId(BiRelationBizType bizType, String sourceId) { return biRelationRepository.countByBizTypeAndSourceId(bizType, sourceId); } From 7437e9d68263447492ebdfeeb69a9b632a63b7c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 02:41:23 +0000 Subject: [PATCH 35/43] build(deps): bump @babel/traverse in /server/node-service Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.5 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- server/node-service/yarn.lock | 146 ++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 26 deletions(-) diff --git a/server/node-service/yarn.lock b/server/node-service/yarn.lock index b1c3c85ff..31dbbfae0 100644 --- a/server/node-service/yarn.lock +++ b/server/node-service/yarn.lock @@ -1383,6 +1383,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.22.13": + version: 7.22.13 + resolution: "@babel/code-frame@npm:7.22.13" + dependencies: + "@babel/highlight": ^7.22.13 + chalk: ^2.4.2 + checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.21.5": version: 7.21.9 resolution: "@babel/compat-data@npm:7.21.9" @@ -1425,6 +1435,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/generator@npm:7.23.0" + dependencies: + "@babel/types": ^7.23.0 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 8efe24adad34300f1f8ea2add420b28171a646edc70f2a1b3e1683842f23b8b7ffa7e35ef0119294e1901f45bfea5b3dc70abe1f10a1917ccdfb41bed69be5f1 + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.21.5": version: 7.21.5 resolution: "@babel/helper-compilation-targets@npm:7.21.5" @@ -1447,22 +1469,29 @@ __metadata: languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.21.0": - version: 7.21.0 - resolution: "@babel/helper-function-name@npm:7.21.0" +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 + languageName: node + linkType: hard + +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" dependencies: - "@babel/template": ^7.20.7 - "@babel/types": ^7.21.0 - checksum: d63e63c3e0e3e8b3138fa47b0cd321148a300ef12b8ee951196994dcd2a492cc708aeda94c2c53759a5c9177fffaac0fd8778791286746f72a000976968daf4e + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 languageName: node linkType: hard -"@babel/helper-hoist-variables@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-hoist-variables@npm:7.18.6" +"@babel/helper-hoist-variables@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" dependencies: - "@babel/types": ^7.18.6 - checksum: fd9c35bb435fda802bf9ff7b6f2df06308a21277c6dec2120a35b09f9de68f68a33972e2c15505c1a1a04b36ec64c9ace97d4a9e26d6097b76b4396b7c5fa20f + "@babel/types": ^7.22.5 + checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc languageName: node linkType: hard @@ -1516,6 +1545,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" + dependencies: + "@babel/types": ^7.22.5 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.21.5": version: 7.21.5 resolution: "@babel/helper-string-parser@npm:7.21.5" @@ -1523,6 +1561,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-string-parser@npm:7.22.5" + checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-validator-identifier@npm:7.19.1" @@ -1530,6 +1575,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.21.0": version: 7.21.0 resolution: "@babel/helper-validator-option@npm:7.21.0" @@ -1559,7 +1611,18 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.5, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.21.9": +"@babel/highlight@npm:^7.22.13": + version: 7.22.20 + resolution: "@babel/highlight@npm:7.22.20" + dependencies: + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.21.9": version: 7.21.9 resolution: "@babel/parser@npm:7.21.9" bin: @@ -1568,6 +1631,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/parser@npm:7.23.0" + bin: + parser: ./bin/babel-parser.js + checksum: 453fdf8b9e2c2b7d7b02139e0ce003d1af21947bbc03eb350fb248ee335c9b85e4ab41697ddbdd97079698de825a265e45a0846bb2ed47a2c7c1df833f42a354 + languageName: node + linkType: hard + "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -1743,25 +1815,36 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.7.2": - version: 7.21.5 - resolution: "@babel/traverse@npm:7.21.5" +"@babel/template@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" dependencies: - "@babel/code-frame": ^7.21.4 - "@babel/generator": ^7.21.5 - "@babel/helper-environment-visitor": ^7.21.5 - "@babel/helper-function-name": ^7.21.0 - "@babel/helper-hoist-variables": ^7.18.6 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.21.5 - "@babel/types": ^7.21.5 + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.7.2": + version: 7.23.2 + resolution: "@babel/traverse@npm:7.23.2" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-environment-visitor": ^7.22.20 + "@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.23.0 + "@babel/types": ^7.23.0 debug: ^4.1.0 globals: ^11.1.0 - checksum: b403733fa7d858f0c8e224f0434a6ade641bc469a4f92975363391e796629d5bf53e544761dfe85039aab92d5389ebe7721edb309d7a5bb7df2bf74f37bf9f47 + checksum: 26a1eea0dde41ab99dde8b9773a013a0dc50324e5110a049f5d634e721ff08afffd54940b3974a20308d7952085ac769689369e9127dea655f868c0f6e1ab35d languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": version: 7.21.5 resolution: "@babel/types@npm:7.21.5" dependencies: @@ -1772,6 +1855,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/types@npm:7.23.0" + dependencies: + "@babel/helper-string-parser": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 + to-fast-properties: ^2.0.0 + checksum: 215fe04bd7feef79eeb4d33374b39909ce9cad1611c4135a4f7fdf41fe3280594105af6d7094354751514625ea92d0875aba355f53e86a92600f290e77b0e604 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -4103,7 +4197,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0": +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: From 4cf05b0f597a435ff5f03678d62eed58c359908e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Oct 2023 03:45:49 +0000 Subject: [PATCH 36/43] build(deps): bump @babel/traverse from 7.21.5 to 7.23.2 in /client Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.5 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- client/yarn.lock | 141 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 14 deletions(-) diff --git a/client/yarn.lock b/client/yarn.lock index 4748d1eaf..f0585856c 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -264,6 +264,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.22.13": + version: 7.22.13 + resolution: "@babel/code-frame@npm:7.22.13" + dependencies: + "@babel/highlight": ^7.22.13 + chalk: ^2.4.2 + checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.21.5": version: 7.21.9 resolution: "@babel/compat-data@npm:7.21.9" @@ -320,6 +330,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/generator@npm:7.23.0" + dependencies: + "@babel/types": ^7.23.0 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 8efe24adad34300f1f8ea2add420b28171a646edc70f2a1b3e1683842f23b8b7ffa7e35ef0119294e1901f45bfea5b3dc70abe1f10a1917ccdfb41bed69be5f1 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" @@ -408,6 +430,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.18.9, @babel/helper-function-name@npm:^7.19.0, @babel/helper-function-name@npm:^7.21.0": version: 7.21.0 resolution: "@babel/helper-function-name@npm:7.21.0" @@ -418,6 +447,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" + dependencies: + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 + languageName: node + linkType: hard + "@babel/helper-hoist-variables@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-hoist-variables@npm:7.18.6" @@ -427,6 +466,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-hoist-variables@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.21.5": version: 7.21.5 resolution: "@babel/helper-member-expression-to-functions@npm:7.21.5" @@ -532,6 +580,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" + dependencies: + "@babel/types": ^7.22.5 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.21.5": version: 7.21.5 resolution: "@babel/helper-string-parser@npm:7.21.5" @@ -539,6 +596,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-string-parser@npm:7.22.5" + checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-validator-identifier@npm:7.19.1" @@ -546,6 +610,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.18.6, @babel/helper-validator-option@npm:^7.21.0": version: 7.21.0 resolution: "@babel/helper-validator-option@npm:7.21.0" @@ -587,7 +658,18 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.5, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.21.9": +"@babel/highlight@npm:^7.22.13": + version: 7.22.20 + resolution: "@babel/highlight@npm:7.22.20" + dependencies: + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 84bd034dca309a5e680083cd827a766780ca63cef37308404f17653d32366ea76262bd2364b2d38776232f2d01b649f26721417d507e8b4b6da3e4e739f6d134 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.21.9": version: 7.21.9 resolution: "@babel/parser@npm:7.21.9" bin: @@ -596,6 +678,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/parser@npm:7.23.0" + bin: + parser: ./bin/babel-parser.js + checksum: 453fdf8b9e2c2b7d7b02139e0ce003d1af21947bbc03eb350fb248ee335c9b85e4ab41697ddbdd97079698de825a265e45a0846bb2ed47a2c7c1df833f42a354 + languageName: node + linkType: hard + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.18.6" @@ -1726,21 +1817,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.2": - version: 7.21.5 - resolution: "@babel/traverse@npm:7.21.5" +"@babel/template@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" dependencies: - "@babel/code-frame": ^7.21.4 - "@babel/generator": ^7.21.5 - "@babel/helper-environment-visitor": ^7.21.5 - "@babel/helper-function-name": ^7.21.0 - "@babel/helper-hoist-variables": ^7.18.6 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.21.5 - "@babel/types": ^7.21.5 + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.4.5, @babel/traverse@npm:^7.7.2": + version: 7.23.2 + resolution: "@babel/traverse@npm:7.23.2" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-environment-visitor": ^7.22.20 + "@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.23.0 + "@babel/types": ^7.23.0 debug: ^4.1.0 globals: ^11.1.0 - checksum: b403733fa7d858f0c8e224f0434a6ade641bc469a4f92975363391e796629d5bf53e544761dfe85039aab92d5389ebe7721edb309d7a5bb7df2bf74f37bf9f47 + checksum: 26a1eea0dde41ab99dde8b9773a013a0dc50324e5110a049f5d634e721ff08afffd54940b3974a20308d7952085ac769689369e9127dea655f868c0f6e1ab35d languageName: node linkType: hard @@ -1755,6 +1857,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/types@npm:7.23.0" + dependencies: + "@babel/helper-string-parser": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.20 + to-fast-properties: ^2.0.0 + checksum: 215fe04bd7feef79eeb4d33374b39909ce9cad1611c4135a4f7fdf41fe3280594105af6d7094354751514625ea92d0875aba355f53e86a92600f290e77b0e604 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -5896,7 +6009,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0": +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: From ad20fbcdae25540b542ae75a47467df64006e976 Mon Sep 17 00:00:00 2001 From: freddysundowner Date: Fri, 20 Oct 2023 11:51:21 +0300 Subject: [PATCH 37/43] adding broadcast using agora rtm --- .../videoMeetingControllerComp.tsx | 115 +- .../meetingComp/videoMeetingStreamComp.tsx | 14 +- .../packages/lowcoder/src/i18n/locales/en.ts | 2 + node_modules/.package-lock.json | 25 + node_modules/agora-rtm-sdk/index.d.ts | 1960 +++++++++++++++++ node_modules/agora-rtm-sdk/index.js | 8 + node_modules/agora-rtm-sdk/package.json | 10 + package-lock.json | 43 + package.json | 1 + yarn.lock | 13 +- 10 files changed, 2172 insertions(+), 19 deletions(-) create mode 100644 node_modules/.package-lock.json create mode 100644 node_modules/agora-rtm-sdk/index.d.ts create mode 100644 node_modules/agora-rtm-sdk/index.js create mode 100644 node_modules/agora-rtm-sdk/package.json create mode 100644 package-lock.json diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx index 11dc31d65..48e2f63a0 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingControllerComp.tsx @@ -52,6 +52,7 @@ import AgoraRTC, { import { JSONValue } from "@lowcoder-ee/index.sdk"; import { getData } from "../listViewComp/listViewUtils"; +import AgoraRTM, { RtmChannel, RtmClient, RtmMessage } from "agora-rtm-sdk"; const EventOptions = [closeEvent] as const; @@ -105,6 +106,8 @@ let audioTrack: IMicrophoneAudioTrack; let videoTrack: ICameraVideoTrack; let screenShareStream: ILocalVideoTrack; let userId: UID | null | undefined; +let rtmChannelResponse: RtmChannel; +let rtmClient: RtmClient; const turnOnCamera = async (flag?: boolean) => { if (videoTrack) { @@ -119,8 +122,6 @@ const turnOnMicrophone = async (flag?: boolean) => { return audioTrack.setEnabled(flag!); } audioTrack = await AgoraRTC.createMicrophoneAudioTrack(); - // audioTrack.play(); - if (!flag) { await client.unpublish(audioTrack); } else { @@ -141,7 +142,7 @@ const shareScreen = async (sharing: boolean) => { "disable" ); await client.unpublish(videoTrack); - screenShareStream.play(userId + ""); + screenShareStream.play("share-screen"); await client.publish(screenShareStream); } } catch (error) { @@ -158,6 +159,7 @@ const leaveChannel = async () => { await turnOnMicrophone(false); } await client.leave(); + await rtmChannelResponse.leave(); }; const hostChanged = (users: any) => {}; @@ -167,6 +169,8 @@ const publishVideo = async (appId: any, channel: any, height: any) => { await client.join(appId, channel, null, userId); await client.publish(videoTrack); + await rtmInit(appId, userId, channel); + const mediaStreamTrack = videoTrack.getMediaStreamTrack(); if (mediaStreamTrack) { const videoSettings = mediaStreamTrack.getSettings(); @@ -177,6 +181,57 @@ const publishVideo = async (appId: any, channel: any, height: any) => { } }; +const sendMessageRtm = (message: any) => { + rtmChannelResponse + .sendMessage({ text: JSON.stringify(message) }) + .then(() => { + console.log("message sent " + JSON.stringify(message)); + }) + .catch((e: any) => { + console.log("error", e); + }); +}; + +const sendPeerMessageRtm = (message: any, toId: string) => { + rtmClient + .sendMessageToPeer({ text: JSON.stringify(message) }, toId) + .then(() => { + console.log("message sent " + JSON.stringify(message)); + }) + .catch((e: any) => { + console.log("error", e); + }); +}; + +const rtmInit = async (appId: any, uid: any, channel: any) => { + rtmClient = AgoraRTM.createInstance(appId); + let options = { + uid: String(uid), + }; + await rtmClient.login(options); + + rtmClient.on("ConnectionStateChanged", function (state, reason) { + console.log("State changed To: " + state + " Reason: " + reason); + }); + + rtmChannelResponse = rtmClient.createChannel(channel); + + await rtmChannelResponse.join().then(async () => { + console.log( + "You have successfully joined channel " + rtmChannelResponse.channelId + ); + }); + + // Display channel member stats + rtmChannelResponse.on("MemberJoined", function (memberId) { + console.log(memberId + " joined the channel"); + }); + // Display channel member stats + rtmChannelResponse.on("MemberLeft", function (memberId) { + console.log(memberId + " left the channel"); + }); +}; + export const meetingControllerChildren = { visible: booleanExposingStateControl("visible"), onEvent: eventHandlerControl(EventOptions), @@ -199,6 +254,7 @@ export const meetingControllerChildren = { usersScreenShared: stateComp([]), localUser: jsonObjectExposingStateControl(""), meetingName: stringExposingStateControl("meetingName"), + messages: stateComp([]), }; let MTComp = (function () { return new ContainerCompBuilder( @@ -222,6 +278,7 @@ let MTComp = (function () { [dispatch, isTopBom] ); const [userIds, setUserIds] = useState([]); + const [rtmMessages, setRtmMessages] = useState([]); useEffect(() => { dispatch( @@ -238,6 +295,28 @@ let MTComp = (function () { } }, [props.endCall.value]); + useEffect(() => { + if (rtmChannelResponse) { + rtmClient.on("MessageFromPeer", function (message, peerId) { + console.log("Message from: " + peerId + " Message: " + message.text); + setRtmMessages((messages: any) => [...messages, message.text]); + console.log("messages " + rtmMessages); + dispatch( + changeChildAction("messages", getData(rtmMessages).data, false) + ); + }); + rtmChannelResponse.on("ChannelMessage", function (message, memberId) { + console.log("Message received from: " + memberId, message.text); + setRtmMessages((messages: any) => [...messages, message.text]); + dispatch( + changeChildAction("messages", getData(rtmMessages).data, false) + ); + }); + } + }, [rtmChannelResponse]); + + console.log("rtmMessages ", props.messages); + useEffect(() => { client.on("user-joined", (user: IAgoraRTCRemoteUser) => { let userData = { @@ -429,7 +508,6 @@ MTComp = withMethodExposing(MTComp, [ } else { await turnOnCamera(value); } - comp.children.videoControl.change(value); }, }, @@ -454,6 +532,30 @@ MTComp = withMethodExposing(MTComp, [ ); }, }, + { + method: { + name: "broadCast", + description: trans("meeting.broadCast"), + params: [], + }, + execute: async (comp, values) => { + let message = { + time: new Date().getMilliseconds(), + from: comp.children.localUser.getView(), + }; + console.log(values); + + if (values != undefined && values[0] !== undefined) { + let peers = values?.map((u: any) => u.user); + peers.forEach((p) => { + sendPeerMessageRtm(message, String(p)); + }); + } else { + sendMessageRtm(message); + } + comp.children.messages.getView(); + }, + }, { method: { name: "endMeeting", @@ -484,8 +586,5 @@ export const VideoMeetingControllerComp = withExposingConfigs(MTComp, [ new NameConfig("localUser", trans("meeting.host")), new NameConfig("participants", trans("meeting.participants")), new NameConfig("meetingName", trans("meeting.meetingName")), + new NameConfig("messages", trans("meeting.meetingName")), ]); - -export function agoraClient() { - return client; -} diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx index d468b637d..b50cd8f19 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videoMeetingStreamComp.tsx @@ -28,9 +28,7 @@ import { RefControl } from "comps/controls/refControl"; import { useEffect, useRef, useState } from "react"; import { AutoHeightControl } from "comps/controls/autoHeightControl"; -import { - client, -} from "./videoMeetingControllerComp"; +import { client } from "./videoMeetingControllerComp"; import { IAgoraRTCRemoteUser } from "agora-rtc-sdk-ng"; @@ -60,7 +58,7 @@ const Container = styled.div<{ $style: any }>` display: flex; align-items: center; justify-content: center; -`; +`; const VideoContainer = styled.video<{ $style: any }>` height: 100%; width: 100%; @@ -154,6 +152,7 @@ const typeOptions = [ export const meetingStreamChildren = { autoHeight: withDefault(AutoHeightControl, "fixed"), + shareScreen: withDefault(BoolCodeControl, false), type: dropdownControl(typeOptions, ""), onEvent: MeetingEventHandlerControl, disabled: BoolCodeControl, @@ -246,8 +245,6 @@ let VideoCompBuilder = (function (props) { } }, [props.userId.value]); - - return ( {(editorState) => ( @@ -257,7 +254,7 @@ let VideoCompBuilder = (function (props) { onClick={() => props.onEvent("videoClicked")} ref={videoRef} $style={props.style} - id={userId} + id={props.shareScreen ? "share-screen" : userId} >
@@ -270,6 +267,9 @@ let VideoCompBuilder = (function (props) {
{children.userId.propertyView({ label: trans("meeting.videoId") })} {children.autoHeight.getPropertyView()} + {children.shareScreen.propertyView({ + label: trans("meeting.shareScreen"), + })}
{children.onEvent.getPropertyView()} diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 2869d3183..2811ea488 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -1448,6 +1448,7 @@ export const en = { top: "Top", host: "Host", participants: "Participants", + shareScreen: "Share Screen", appid: "Application Id", meetingName: "Meeting Name", right: "Right", @@ -1462,6 +1463,7 @@ export const en = { width: "Drawer width", height: "Drawer height", actionBtnDesc: "Action Button", + broadCast: "BroadCast Messages", title: "Meeting title", meetingCompName: "Meeting Controller", videoCompName: "Video Stream", diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 000000000..bed96b9b8 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,25 @@ +{ + "name": "lowcoder-1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "node_modules/agora-rtm-sdk": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/agora-rtm-sdk/-/agora-rtm-sdk-1.5.1.tgz", + "integrity": "sha512-4zMZVijEOTimIaY4VUS6kJxg7t+nTV3Frtt01Ffs6dvkOrPmpeuCu/1MX88QgAOE04IBiLo0l89ysc+woVn2FA==" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + } + } +} diff --git a/node_modules/agora-rtm-sdk/index.d.ts b/node_modules/agora-rtm-sdk/index.d.ts new file mode 100644 index 000000000..9320f0220 --- /dev/null +++ b/node_modules/agora-rtm-sdk/index.d.ts @@ -0,0 +1,1960 @@ +declare namespace RtmStatusCode { + enum ConnectionChangeReason { + LOGIN = "LOGIN", + LOGIN_SUCCESS = "LOGIN_SUCCESS", + LOGIN_FAILURE = "LOGIN_FAILURE", + LOGIN_TIMEOUT = "LOGIN_TIMEOUT", + INTERRUPTED = "INTERRUPTED", + LOGOUT = "LOGOUT", + BANNED_BY_SERVER = "BANNED_BY_SERVER", + REMOTE_LOGIN = "REMOTE_LOGIN", + TOKEN_EXPIRED = "TOKEN_EXPIRED" + } + enum ConnectionState { + DISCONNECTED = "DISCONNECTED", + CONNECTING = "CONNECTING", + CONNECTED = "CONNECTED", + RECONNECTING = "RECONNECTING", + ABORTED = "ABORTED" + } + enum LocalInvitationState { + IDLE = "IDLE", + SENT_TO_REMOTE = "SENT_TO_REMOTE", + RECEIVED_BY_REMOTE = "RECEIVED_BY_REMOTE", + ACCEPTED_BY_REMOTE = "ACCEPTED_BY_REMOTE", + REFUSED_BY_REMOTE = "REFUSED_BY_REMOTE", + CANCELED = "CANCELED", + FAILURE = "FAILURE" + } + enum RemoteInvitationState { + INVITATION_RECEIVED = "INVITATION_RECEIVED", + ACCEPT_SENT_TO_LOCAL = "ACCEPT_SENT_TO_LOCAL", + REFUSED = "REFUSED", + ACCEPTED = "ACCEPTED", + CANCELED = "CANCELED", + FAILURE = "FAILURE" + } + enum LocalInvitationFailureReason { + UNKNOWN = "UNKNOWN", + PEER_NO_RESPONSE = "PEER_NO_RESPONSE", + INVITATION_EXPIRE = "INVITATION_EXPIRE", + PEER_OFFLINE = "PEER_OFFLINE", + NOT_LOGGEDIN = "NOT_LOGGEDIN" + } + enum RemoteInvitationFailureReason { + UNKNOWN = "UNKNOWN", + PEER_OFFLINE = "PEER_OFFLINE", + ACCEPT_FAILURE = "ACCEPT_FAILURE", + INVITATION_EXPIRE = "INVITATION_EXPIRE" + } + enum PeerOnlineState { + ONLINE = "ONLINE", + UNREACHABLE = "UNREACHABLE", + OFFLINE = "OFFLINE" + } + enum PeerSubscriptionOption { + ONLINE_STATUS = "ONLINE_STATUS" + } + enum MessageType { + TEXT = "TEXT", + RAW = "RAW" + } + enum LegacyAreaCode { + CN = "CN", + NA = "NA", + EU = "EU", + AS = "AS", + JP = "JP", + IN = "IN", + GLOB = "GLOB", + OC = "OC", + SA = "SA", + AF = "AF", + OVS = "OVS" + } + enum AreaCode { + GLOBAL = "GLOBAL", + INDIA = "INDIA", + JAPAN = "JAPAN", + ASIA = "ASIA", + EUROPE = "EUROPE", + CHINA = "CHINA", + NORTH_AMERICA = "NORTH_AMERICA" + } +} + +/** @zh-cn + * 管理频道属性。 + */ +/** + * Manages channel attributes. + */ +interface ChannelAttributeProperties { + /** @zh-cn + * 频道属性的属性值。长度不得超过 8 KB。 + */ + /** + * The value of the channel attribute. Must not exceed 8 KB in length. + */ + value: string; + + /** @zh-cn + * 最近一次更新频道属性用户的 ID。 + */ + /** + * User ID of the user who makes the latest update to the channel attribute. + */ + lastUpdateUserId: string; + + /** @zh-cn + * 频道属性最近一次更新的时间戳(毫秒)。 + */ + /** + * Timestamp of when the channel attribute was last updated in milliseconds. + */ + lastUpdateTs: number; +} + +/** @zh-cn + * 定义属性。 + */ +/** + * Defines attributes. + */ +interface AttributesMap { + + /** @zh-cn + * 属性名和属性值,以键值对形式表示。单个属性值的长度不得超过 8 KB。单个属性名长度不得超过 32 字节。 + */ + /** + * Attribute name and attribute value in the form of a key value pair. The total length of an attribute value must not exceed 8 KB. The length of a single attribute name must not exceed 32 bytes. + */ + [key: string]: string; +} +/** @zh-cn + * 定义频道属性。 + */ +/** + * Defines channel attributes. + */ +interface ChannelAttributes { + /** @zh-cn + * 频道属性名和频道属性健值对。 + */ + [key: string]: ChannelAttributeProperties; +} + +/** @zh-cn + * 维护频道属性操作相关选项。 + */ +/** + * An interface for setting and getting channel attribute options. + */ +interface ChannelAttributeOptions { + /** @zh-cn + * 是否通知所有频道成员本次频道属性变更。该标志位仅对本次 API 调用有效: + * + * - `true`: 通知所有频道成员本次频道属性变更。 + * - `false`: (默认) 不通知所有频道成员本次频道属性变更。 + */ + /** + * Indicates whether or not to notify all channel members of a channel attribute change. This flag is valid only within the current method call: + * + * - `true`: Notify all channel members of a channel attribute change. + * - `false`: (Default) Do not notify all channel members of a channel attribute change. + */ + enableNotificationToChannelMembers?: boolean; +} + +/** @hidden */ +declare type ListenerType = [T] extends [(...args: infer U) => any] + ? U + : [T] extends [void] + ? [] + : [T]; +/** @hidden */ +declare class EventEmitter { + static defaultMaxListeners: number; + on

( + this: T, + event: P, + listener: (...args: ListenerType) => void + ): this; + + once

( + this: T, + event: P, + listener: (...args: ListenerType) => void + ): this; + + off

( + this: T, + event: P, + listener: (...args: any[]) => any + ): this; + + removeAllListeners

(this: T, event?: P): this; + listeners

(this: T, event: P): Function[]; + rawListeners

(this: T, event: P): Function[]; + listenerCount

(this: T, event: P): number; +} + +/** @zh-cn + * 文本消息接口,用于发送和接收文本消息。你可以调用 {@link RtmClient.sendMessageToPeer} 或 {@link RtmChannel.sendMessage} 发送点对点类型或频道类型的文本消息。 + */ +/** + * Interface for text messages. You can use this interface to send and receive text messages. You can call {@link RtmClient.sendMessageToPeer} or {@link RtmChannel.sendMessage} to send a peer-to-peer or channel text message. + */ +interface RtmTextMessage { + /** @zh-cn + * 文本消息的内容。最大长度为 32 KB。 + *

Note

+ * 文本消息和文字描述的总大小不能超过 32 KB。 + */ + /** + * Content of the text message. The maximum length is 32 KB. + *

Note

+ * The maximum total length of the text message and the description is 32 KB. + */ + text: string; + + /** @zh-cn + * 消息类型。`TEXT` 代表文本消息。 + */ + /** + * Message type. `TEXT` stands for text messages. + * + */ + messageType?: 'TEXT'; + /** @hidden */ + rawMessage?: never; + /** @hidden */ + description?: never; +} + +/** @zh-cn + * 二进制消息接口,用于发送和接收二进制消息。你可以调用 {@link RtmClient.sendMessageToPeer} 或 {@link RtmChannel.sendMessage} 发送点对点或频道的二进制消息。 + */ +/** + * Interface for raw messages. You can use this interface to send and receive raw messages. You can call {@link RtmClient.sendMessageToPeer} or {@link RtmChannel.sendMessage} to send a peer-to-peer or channel raw message. + */ +interface RtmRawMessage { + /** @zh-cn + * 二进制消息的内容。最大长度为 32 KB。 + *

Note

+ * 二进制消息和文字描述的总大小不能超过 32 KB。 + */ + /** + * Content of the raw message in binary format. The maximum length is 32 KB. + *

Note

+ * The maximum total length of the raw message and the description is 32 KB. + */ + rawMessage: Uint8Array; + + /** @zh-cn + * 二进制消息的文字描述。最大长度为 32 KB。 + *

Note

+ * 二进制消息和文字描述的总大小不能超过 32 KB。 + */ + /** + * Description of the raw message. The maximum length is 32 KB. + *

Note

+ * The maximum total length of the raw message and the description is 32 KB. + */ + description?: string; + + /** @zh-cn + * 消息类型。`RAW` 代表二进制消息。 + */ + /** + * Message type. `RAW` stands for raw messages. + * + */ + messageType?: 'RAW'; + /** @hidden */ + text?: never; +} + + +/** @zh-cn + * 用于表示 RTM 消息的类型别名。RtmMessage 可以是文本消息 {@link RtmTextMessage} ,自定义二进制消息 {@link RtmRawMessage}。 + */ +/** + * Type alias for RTM messages. RtmMessage can be either {@link RtmTextMessage} , {@link RtmRawMessage}. + */ +type RtmMessage = + | RtmTextMessage + | RtmRawMessage; + +/** @zh-cn + * 用于表示点对点消息发送结果的接口。 + */ +/** + * Interface for the result of delivering the peer-to-peer message. + */ +interface PeerMessageSendResult { + /** @zh-cn + * 该布尔值属性代表消息接收方是否已收到发出的消息。 + * + * - `true`: 点对点消息发送成功,对方已收到; + * - `false`: 对方不在线,未收到该消息。 + * + */ + /** + * This boolean property indicates whether the remote peer user receives the sent message. + * + * - `true`: the peer user receives the message. + * - `false`: the peer user is offline and does not receive the message. + * + */ + hasPeerReceived: boolean; +} + + + +/** @zh-cn + * 用于管理已接收消息属性的接口。 + */ +/** + * Interface for properties of received messages. + */ +interface ReceivedMessageProperties { + /** @zh-cn + * 消息服务器接收到消息的时间戳,单位为毫秒。 + * + *

Note

+ * + *
  • 你不能设置时间戳,但是你可以从该时间戳推断出消息的大致发送时间。
  • + *
  • 时间戳的精度为毫秒。仅用于展示,不建议用于消息的严格排序。
  • + */ + /** + * The timestamp (ms) of when the messaging server receives this message. + * + *

    Note

    + * + *
  • You cannot set this returned timestamp, but you can infer from it the approximate time as to when this message was sent.
  • + *
  • The returned timestamp is on a millisecond time-scale. It is for demonstration purposes only, not for strict ordering of messages.
  • + */ + serverReceivedTs: number; +} + +interface PeersOnlineStatusMap { + [peerId: string]: RtmStatusCode.PeerOnlineState; +} + +declare namespace RtmEvents { + /** @zh-cn + * {@link RtmChannel} 实例上的事件类型。 + * 该接口中,函数属性的名称为事件名称,函数的参数为事件监听回调的传入参数。 + * + * @example **监听频道消息** + * + * ```JavaScript + * channel.on('ChannelMessage', function (message, memberId) { + * // 你的代码:收到频道消息。 + * }); + * ``` + * @example **监听用户加入频道事件** + * + * ```JavaScript + * channel.on('MemberJoined', memberId => { + * // 你的代码:用户已加入频道。 + * }) + * ``` + * @example **监听用户离开频道事件** + * + * ```JavaScript + * channel.on('MemberLeft', memberId => { + * // 你的代码:用户已离开频道。 + * }); + * ``` + */ + /** + * Event types of the {@link RtmChannel} instance. + * In this interface, the function property’s name is the event name; the function property’s parameters is the parameters of the event listener function. + * + * @example **Listening to channel messages.** + * + * ```JavaScript + * channel.on('ChannelMessage', function (message, memberId) { + * // Your code. + * }); + * ``` + * @example **Listening to events, such as a user joining the channel.** + * + * ```JavaScript + * channel.on('MemberJoined', memberId => { + * // Your code. + * }) + * ``` + * @example **Listening to events, such as a member leaving the channel** + * + * ```JavaScript + * channel.on('MemberLeft', memberId => { + * // Your code. + * }); + * ``` + */ + export interface RtmChannelEvents { + /** @zh-cn + * 收到频道消息的事件通知。 + * @event + * @param message 接收到的频道消息对象。 + * @param memberId 该频道消息的发送者 uid。 + */ + /** + * Occurs when the local user receives a channel message. + * @event + * @param message The received channel message object. + * @param memberId The uid of the sender. + */ + ChannelMessage: ( + message: RtmMessage, + memberId: string, + messagePros: ReceivedMessageProperties + ) => void; + + /** @zh-cn + * 收到用户离开频道的通知。 + * + * 用户调用 `leave` 方法离开频道或者由于网络原因与 Agora RTM 系统断开连接达到 30 秒都会触发此回调。 + * + * 当频道成员超过 512 时,该回调失效。 + * @event + * @param memberId 离开频道的远端用户的 uid。 + */ + /** + * Occurs when a user leaves the channel. + * + * This callback is triggered when the user calls `leave` to leave a channel or the user stays disconnected with the Agora RTM system for 30 seconds due to network issues. + * + *

    Note

    + * This callback is disabled when the number of the channel members exceeds 512. + * @event + * @param memberId The uid of the user leaving the channel. + */ + MemberLeft: (memberId: string) => void; + + /** @zh-cn + * 收到用户加入频道的通知。 + *

    Note

    + * 当频道成员超过 512 时,该回调失效。 + * @event + * @param memberId 加入频道的用户的 uid。 + */ + /** + * Occurs when a user joins a channel. + *

    Note

    + * This callback is disabled when the number of the channel members exceeds 512. + * @event + * @param memberId The uid of the user joining the channel. + */ + MemberJoined: (memberId: string) => void; + + /** @zh-cn + * 频道属性更新回调。返回所在频道的所有属性。 + * + *

    Note

    + * 只有当频道属性更新者将 {@link enableNotificationToChannelMembers} 设为 `true` 后,该回调才会被触发。请注意:该标志位仅对当前频道属性操作有效。 + * @event + */ + /** + * Occurs when channel attributes are updated, and returns all attributes of the channel. + * + *

    Note

    + * This callback is enabled only when the user, who updates the attributes of the channel, sets {@link enableNotificationToChannelMembers} as true. Also note that this flag is valid only within the current channel attribute method call. + * @event + */ + AttributesUpdated: (attributes: ChannelAttributes) => void; + /** @zh-cn + * 收到频道人数变化通知。 + * @event + */ + + /** @zh-cn + * 频道成员人数更新回调。返回最新频道成员人数。 + * + *

    Note

    + * + *
  • 频道成员人数 ≤ 512 时,触发频率为每秒 1 次。
  • + *
  • 频道成员人数超过 512 时,触发频率为每 3 秒 1 次。
  • + *
  • 用户在成功加入频道时会收到该回调。你可以通过监听该回调获取加入频道时的频道成员人数和后继人数更新。
  • + * @event + * @param memberCount 最新频道成员人数。 + */ + /** + * Occurs when the number of the channel members changes, and returns the new number. + * + *

    Note

    + * + *
  • When the number of channel members ≤ 512, the SDK returns this callback when the number changes at a frequency of once per second.
  • + *
  • When the number of channel members exceeds 512, the SDK returns this callback when the number changes at a frequency of once every three seconds.
  • + *
  • You will receive this callback when successfully joining an RTM channel, so we recommend implementing this callback to receive timely updates on the number of the channel members.
  • + * @event + * @param memberCount Member count of this channel. + */ + MemberCountUpdated: (memberCount: number) => void; + } + + /** @zh-cn + * {@link RemoteInvitation} 实例上的事件类型。 + */ + /** + * Event types of the {@link RemoteInvitation} instance. + */ + export interface RemoteInvitationEvents { + /** @zh-cn + * 返回给被叫:主叫已取消呼叫邀请。 + */ + /** + * Callback to the callee: occurs when the caller cancels the call invitation. + */ + RemoteInvitationCanceled: (content: string) => void; + + /** @zh-cn + * 返回给被叫:拒绝呼叫邀请成功。 + */ + /** + * Callback for the callee: occurs when the callee successfully declines the incoming call invitation. + */ + RemoteInvitationRefused: () => void; + + /** @zh-cn + * 返回给被叫:接受呼叫邀请成功。 + */ + /** + * Callback to the callee: occurs when the callee accepts a call invitation. + */ + RemoteInvitationAccepted: () => void; + + /** @zh-cn + * 返回给被叫:呼叫邀请进程失败。 + * @param reason 呼叫邀请失败原因。详见: {@link RemoteInvitationFailureReason} 。 + */ + /** + * Callback to the callee: occurs when the life cycle of the incoming call invitation ends in failure. + * + * @param reason See: {@link RemoteInvitationFailureReason}. + */ + RemoteInvitationFailure: ( + reason: RtmStatusCode.RemoteInvitationFailureReason + ) => void; + } + + /** @zh-cn + * {@link LocalInvitation} 实例上的事件类型。 + */ + /** + * Event types of the {@link LocalInvitation} instance. + */ + export interface LocalInvitationEvents { + /** @zh-cn + * 返回给主叫:被叫已接受呼叫邀请。 + * + * @param response 被叫设置的响应内容。 + */ + /** + * Callback to the caller: occurs when the callee accepts the call invitation. + * + * @param response The response from the callee. + */ + LocalInvitationAccepted: (response: string) => void; + /** @zh-cn + * 返回给主叫:被叫已拒绝呼叫邀请。 + * @param response 被叫设置的响应内容。 + */ + /** + * Callback to the caller: occurs when the callee refuses the call invitation. + * @param response The response from the callee. + */ + LocalInvitationRefused: (response: string) => void; + /** @zh-cn + * 返回给主叫:被叫已收到呼叫邀请。 + */ + /** + * Callback to the caller: occurs when the callee receives the call invitation. + * + * This callback notifies the caller that the callee receives the call invitation. + */ + LocalInvitationReceivedByPeer: () => void; + /** @zh-cn + * 返回给主叫:呼叫邀请已被成功取消。 + */ + /** + * Callback to the caller: occurs when the caller cancels a call invitation. + * This callback notifies the caller that he/she has canceled a call invitation. + */ + LocalInvitationCanceled: () => void; + /** @zh-cn + * 返回给主叫:呼叫邀请进程失败。 + * + * @param reason 呼叫邀请的失败原因。详见: {@link LocalInvitationFailureReason} 。 + */ + /** + * Callback to the caller: occurs when the outgoing call invitation ends in failure. + * + * @param reason See: {@link LocalInvitationFailureReason}. + */ + LocalInvitationFailure: ( + reason: RtmStatusCode.LocalInvitationFailureReason + ) => void; + } + + /** @zh-cn + * {@link RtmClient} 实例上的事件类型。 + * 该接口中,函数属性的名称为事件名称,函数的参数为事件监听回调的传入参数。 + * + * @example **监听点对点消息** + * + * ```JavaScript + * client.on('MessageFromPeer', function (message, peerId) { + * // Your code. + * }); + * ``` + */ + /** + * Event listener type of the {@link RtmClient} instance. + * In this interface, the function property’s name is the event name; the function property’s parameters is the parameters of the event listener function. + * + * @example **Listening to peer-to-peer messages.** + * + * ```JavaScript + * client.on('MessageFromPeer', function (message, peerId) { + * // Your code. + * }); + * ``` + */ + export interface RtmClientEvents { + /** @zh-cn + * 收到来自对端的点对点消息。 + * @event + * @param message 远端用户发送的消息对象。 + * @param peerId 发送该消息的远端用户 uid。 + * @param messageProps 接收到的消息的属性。 + */ + /** + * Occurs when the local user receives a peer-to-peer message from a remote user. + * @event + * @param message The received peer-to-peer message object. + * @param peerId The uid of the sender. + * @param messageProps The properties of the received message. + */ + MessageFromPeer: ( + message: RtmMessage, + peerId: string, + messageProps: ReceivedMessageProperties + ) => void; + /** @zh-cn + * 通知 SDK 与 Agora RTM 系统的连接状态发生了改变。 + * @event + * @param newState 新的连接状态 + * @param reason 状态改变的原因 + */ + /** + * Occurs when the connection state changes between the SDK and the Agora RTM system. + * @event + * @param newState The new connection state. + * @param reason Reasons for the connection state change. + */ + ConnectionStateChanged: ( + newState: RtmStatusCode.ConnectionState, + reason: RtmStatusCode.ConnectionChangeReason + ) => void; + /** @zh-cn + * 收到来自主叫的呼叫邀请。 + * @event + * @param remoteInvitation 一个 {@link RemoteInvitation} 对象。 + */ + /** + * Occurs when the callee receives a call invitation from a remote user (caller). + * @event + * @param remoteInvitation A {@link RemoteInvitation} object. + */ + RemoteInvitationReceived: (remoteInvitation: RemoteInvitation) => void; + + /** @zh-cn + * (SDK 断线重连时触发)当前使用的 RTM Token 已超过 24 小时的签发有效期。 + * + * - 该回调仅会在 SDK 处于 `RECONNECTING` 状态时因 RTM 后台监测到 Token 签发有效期过期而触发。SDK 处于 `CONNECTED` 状态时该回调不会被触发。 + * - 收到该回调时,请尽快在你的业务服务端生成新的 Token 并调用 {@link renewToken} 方法把新的 Token 传给 Token 验证服务器。 + */ + /** + * Occurs when the RTM server detects that the RTM token has exceeded the 24-hour validity period and when the SDK is in the `RECONNECTING` state. + * + * - This callback occurs only when the SDK is reconnecting to the server. You will not receive this callback when the SDK is in the `CONNECTED` state. + * - When receiving this callback, generate a new RTM Token on the server and call the {@link renewToken} method to pass the new Token on to the server. + */ + TokenExpired: () => void; + + /** @zh-cn + * 当前使用的 RTM Token 登录权限还有 30 秒就会超过签发有效期。 + * + * - 收到该回调时,请尽快在你的业务服务端生成新的 Token 并调用 {@link renewToken} 方法把新的 Token 传给 Token 验证服务器。 + */ + /** + * The currently used RTM Token login permission will expire after 30 seconds. + * + * - When receiving this callback, generate a new RTM Token on the server and call the {@link renewToken} method to pass the new Token on to the server. + */ + TokenPrivilegeWillExpire: () => void; + + /** @zh-cn + * 被订阅用户在线状态改变回调。 + * + * - 首次订阅在线状态成功时,SDK 也会返回本回调,显示所有被订阅用户的在线状态。 + * - 每当被订阅用户的在线状态发生改变,SDK 都会通过该回调通知订阅方。 + * - 如果 SDK 在断线重连过程中有被订阅用户的在线状态发生改变,SDK 会在重连成功时通过该回调通知订阅方。 + */ + /** + * Occurs when the online status of the peers, to whom you subscribe, changes. + * + * - When the subscription to the online status of specified peer(s) succeeds, the SDK returns this callback to report the online status of peers, to whom you subscribe. + * - When the online status of the peers, to whom you subscribe, changes, the SDK returns this callback to report whose online status has changed. + * - If the online status of the peers, to whom you subscribe, changes when the SDK is reconnecting to the server, the SDK returns this callback to report whose online status has changed when successfully reconnecting to the server. + */ + PeersOnlineStatusChanged: (status: PeersOnlineStatusMap) => void; + + /** + * Occurs when the SDK automatically switches to proxy WebSocket of 443 port. + */ + FallbackProxyConnected: () => void; + } +} + +/** @zh-cn + * 由主叫通过 {@link createLocalInvitation} 方法创建,仅供主叫调用的呼叫邀请对象。 + * @noInheritDoc + */ +/** + * The call invitation object created by calling the {@link createLocalInvitation} method, and called only by the caller. + * @noInheritDoc + */ +declare class LocalInvitation extends EventEmitter< + RtmEvents.LocalInvitationEvents +> { + /** @zh-cn + * 被叫设置的响应内容。 + * @readonly + */ + /** + * The callee's response to the call invitation. + * @readonly + */ + readonly response: string; + + /** + * 供主叫查看的呼叫邀请状态。 + * + * 详见: {@link LocalInvitationState} 。 + * @readonly + */ + /** + * State of the outgoing call invitation. + * + * See: {@link LocalInvitationState}. + * @readonly + */ + readonly state: RtmStatusCode.LocalInvitationState; + + /** @zh-cn + * 主叫设置的呼叫邀请内容。 + * @note 最大长度为 8 KB。 + */ + /** + * Call invitation content set by the caller. + * @note The maximum length is 8 KB. + */ + content: string; + + /** @zh-cn + * 被叫的 uid。 + */ + /** + * uid of the callee. + */ + readonly calleeId: string; + + /** @zh-cn + * 主叫设置的频道 ID。 + * @note 与老信令 SDK 互通时你必须设置频道 ID。不过即使在被叫成功接受呼叫邀请后,Agora RTM SDK 也不会把主叫加入指定频道。 + */ + /** + * The channel ID set by the caller. + * @note To intercommunicate with the legacy Agora Signaling SDK, you MUST set the channel ID. However, even if the callee successfully accepts the call invitation, the Agora RTM SDK does not join the channel of the specified channel ID. + */ + channelId: string; + + /** @zh-cn + * 向指定用户(被叫)发送呼叫邀请。该方法无异步回调。如需监听 {@link LocalInvitationState} 变化,请通过 {@link on} 方法注册 {@link LocalInvitationEvents} 中的事件回调。 + */ + /** + * Send a call invitation to a specified remote user (callee). This method has no asynchronous callbacks. To listen for {@link LocalInvitationState} changes, register the event handler in {@link LocalInvitationEvents} via the {@link on} method. + */ + send(): void; + + /** @zh-cn + * 取消已发送的呼叫邀请。该方法无异步回调。如需监听 {@link LocalInvitationState} 变化,请通过 {@link on} 方法注册 {@link LocalInvitationEvents} 中的事件回调。 + */ + /** + * Allows the caller to cancel a sent call invitation. This method has no asynchronous callbacks. To listen for {@link LocalInvitationState} changes, register the event handler in {@link LocalInvitationEvents} via the {@link on} method. + */ + cancel(): void; + /** @zh-cn + * 在该频道实例上添加 `listener` 函数到名为 `eventName` 的事件。其他 `RtmChannel` 实例上的事件方法请参考 [`EventEmitter` API 文档](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter)。 + * @param eventName 频道事件的名称。事件列表请参考 {@link RtmChannelEvents} 中的属性名。 + * @param listener 事件的回调函数。 + */ + /** + * Adds the `listener` function to the channel for the event named `eventName`. See [the `EventEmitter` API documentation](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter) for other event methods on the `RtmChannel` instance. + * @param eventName The name of the channel event. See the property names in the {@link RtmChannelEvents} for the list of events. + * @param listener The callback function of the channel event. + */ + on( + eventName: EventName, + listener: ( + ...args: ListenerType + ) => any + ): this; +} + +/** @zh-cn + * 由 SDK 创建供被叫调用的呼叫邀请对象。 + * @noInheritDoc + */ +/** + * The call invitation object created by the SDK and called by the callee. + * @noInheritDoc + */ +declare class RemoteInvitation extends EventEmitter< + RtmEvents.RemoteInvitationEvents +> { + /** @zh-cn + * 供被叫获取主叫的用户 ID。 + * @readonly + */ + /** + * Allows the callee to get the channel ID. + * @readonly + */ + readonly channelId: string; + + /** @zh-cn + * 主叫的 uid。 + * @readonly + */ + /** + * uid of the caller. + * @readonly + */ + readonly callerId: string; + + /** @zh-cn + * 主叫设置的呼叫邀请内容。 + * @readonly + * @note 最大长度为 8 KB。 + */ + /** + * The call invitation content set by the caller. + * @readonly + * @note The maximum length is 8 KB. + */ + readonly content: string; + + /** @zh-cn + * 呼叫邀请的状态。详见: {@link RemoteInvitationState} 。 + * @readonly + */ + /** + * States of the incoming call invitation. See: {@link RemoteInvitationState} . + * @readonly + */ + readonly state: RtmStatusCode.RemoteInvitationState; + + /** @zh-cn + * 被叫设置的响应内容。 + * @note 最大长度为 8 KB。 + */ + /** + * Response to the incoming call invitation. + * @note The maximum length is 8 KB. + */ + response: string; + + /** @zh-cn + * 接受来自主叫的呼叫邀请。该方法无异步回调。如需监听 {@link RemoteInvitationState} 变化,请通过 {@link on} 方法注册 {@link RemoteInvitationEvents} 中的事件回调。 + */ + /** + * Allows the callee to accept an incoming call invitation. This method has no asynchronous callbacks. To listen for {@link RemoteInvitationState} changes, register the event handler in {@link RemoteInvitationEvents} via the {@link on} method. + */ + accept(): void; + + /** @zh-cn + * 拒绝来自主叫的呼叫邀请。该方法无异步回调。如需监听 {@link RemoteInvitationState} 变化,请通过 {@link on} 方法注册 {@link RemoteInvitationEvents} 中的事件回调。 + */ + /** + * Allows the callee to decline an incoming call invitation. This method has no asynchronous callbacks. To listen for {@link RemoteInvitationState} changes, register the event handler in {@link RemoteInvitationEvents} via the {@link on} method. + */ + refuse(): void; + + /** @zh-cn + * 在该频道实例上添加 `listener` 函数到名为 `eventName` 的事件。其他 `RtmChannel` 实例上的事件方法请参考 [`EventEmitter` API 文档](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter)。 + * @param eventName 频道事件的名称。事件列表请参考 {@link RtmChannelEvents} 中的属性名。 + * @param listener 事件的回调函数。 + */ + /** + * Adds the `listener` function to the channel for the event named `eventName`. See [the `EventEmitter` API documentation](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter) for other event methods on the `RtmChannel` instance. + * @param eventName The name of the channel event. See the property names in the {@link RtmChannelEvents} for the list of events. + * @param listener The callback function of the channel event. + */ + on( + eventName: EventName, + listener: ( + ...args: ListenerType + ) => any + ): this; +} + +/** @zh-cn + * RTM 频道类。你可以调用 {@link createChannel} 方法创建 RTM 频道实例。 + * @noInheritDoc + */ +/** + * Class to represent an RTM channel. You can call the {@link createChannel} method to create an RtmClient instance. + * @noInheritDoc + */ +declare class RtmChannel extends EventEmitter< + RtmEvents.RtmChannelEvents +> { + /** @zh-cn + * @readonly + * 频道实例的 ID。 + */ + /** + * @readonly + * ID of the RTM channel instance. + */ + readonly channelId: string; + + /** @zh-cn + * 发送频道消息,所有加入频道的用户都会收到该频道消息。 + * + * 发送消息(包括点对点消息和频道消息)的频率上限为 180 次每 3 秒。 + * @example **发送频道消息。** + * + * ```JavaScript + * channel.sendMessage({ text: 'test channel message' }).then(() => { + * // 你的代码:频道消息发送成功处理逻辑。 + * }).catch(error => { + * // 你的代码:频道消息发送失败处理逻辑。 + * }); + * ``` + * @note 在实际开发中,你可以将已发送的频道消息作为应用界面上的用户已发送消息。这样可以在界面中显示用户频道消息的发送状态。发送频道消息的用户本身不会收到频道消息。 + * @param message 要发送的消息实例。 + * @return 该 Promise 会在发送频道消息成功后 resolve。 + */ + /** + * Allows a user to send a message to all users in a channel. + * + * You can send messages, including peer-to-peer and channel messages at a maximum frequency of 180 calls every three seconds. + * @example **Sending a channel message.** + * + * ```JavaScript + * channel.sendMessage({ text: 'test channel message' }).then(() => { + * // Your code for handling the event when the channel message is successfully sent. + * }).catch(error => { + * // Your code for handling the event when the channel message fails to be sent. + * }); + * ``` + * @note In development, you can set the sent channel message as the sent message in the UI of your application. Thus, you can display the message status in the UI. The user who sends the channel message does not receive the same channel message. + * @param message The message instance to be sent. + * @return The Promise resolves after the user successfully sends a channel message. + */ + sendMessage( + message: RtmMessage, + ): Promise; + + /** @zh-cn + * 调用该方法加入该频道,加入频道成功后可收到该频道消息和频道用户进退通知。 + * + * 你最多可以加入 20 个频道。 + * @return 该 Promise 会在加入频道成功后 resolve。 + */ + /** + * Joins a channel. After joining the channel, the user can receive channel messages and notifications of other users joining or leaving the channel. + * + * You can join a maximum of 20 channels. + * @return The Promise resolves after the user successfully joins the channel. + */ + join(): Promise; + + /** @zh-cn + * 调用该方法离开该频道,不再接收频道消息和频道用户进退通知。 + * @return 该 Promise 会在离开频道成功后 resolve。 + */ + /** + * Leaves a channel. After leaving the channel, the user does not receive channel messages or notifications of users joining or leaving the channel. + * @return The Promise resolves after the user successfully leaves the channel. + */ + leave(): Promise; + + /** @zh-cn + * 获取频道用户列表 + * + * @return 该 Promise 会在成功获取频道用户列表后 resolve。Promise 返回的值为该频道所有用户 ID 的数组。 + */ + /** + * Gets the member list of the channel. + * + * @return The Promise resolves after the user gets the member list of the channel in an array with the channel's uids. + */ + getMembers(): Promise; + + /** @zh-cn + * 在该频道实例上添加 `listener` 函数到名为 `eventName` 的事件。其他 `RtmChannel` 实例上的事件方法请参考 [`EventEmitter` API 文档](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter)。 + * + * @param eventName 频道事件的名称。事件列表请参考 {@link RtmChannelEvents} 中的属性名。 + * @param listener 事件的回调函数。 + */ + /** + * Adds the `listener` function to the channel for the event named `eventName`. See [the `EventEmitter` API documentation](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter) for other event methods on the `RtmChannel` instance. + * + * @param eventName The name of the channel event. See the property names in the {@link RtmChannelEvents} for the list of events. + * @param listener The callback function of the channel event. + */ + on( + eventName: EventName, + listener: ( + ...args: ListenerType + ) => any + ): this; +} + +/** @zh-cn + * @hidden + */ +/** + * @hidden + */ +type LogFilterType = { + error: boolean; + warn: boolean; + info: boolean; + track: boolean; + debug: boolean; +}; + +/** @zh-cn + * {@link RtmClient} 对象的配置参数。 + * + * 可在初始化时通过 {@link createInstance} 的第 2 个参数或实例上的 {@link updateConfig} 方法进行设置。 + */ +/** + * Interface holding the configuration of an `RtmClient` instance. + * + * You can pass it as the second argument when calling the {@link createInstance} method, or use it when calling the {@link updateConfig} method. + */ +interface RtmConfig { + /** @zh-cn + * 是否上传日志。默认关闭。 + * - `true`: 启用日志上传; + * - `false`: (默认)关闭日志上传。 + */ + /** + * Whether to enable log upload. It is set to `false` by default. + * - `true`: Enable log upload, + * - `false`: (Default) Disable log upload. + */ + enableLogUpload?: boolean; + + /** @zh-cn + * 日志输出等级。 + * + * 设置 SDK 的输出日志输出等级。不同的输出等级可以单独或组合使用。日志级别顺序依次为 OFF、ERROR、WARNING 和 INFO。选择一个级别,你就可以看到在该级别之前所有级别的日志信息。例如,你选择 WARNING 级别,就可以看到在 ERROR 和 WARNING 级别上的所有日志信息。 + * + * - {@link AgoraRTM.LOG_FILTER_OFF} + * - {@link AgoraRTM.LOG_FILTER_ERROR} + * - {@link AgoraRTM.LOG_FILTER_INFO} (默认) + * - {@link AgoraRTM.LOG_FILTER_WARNING} + */ + /** + * Output log level of the SDK. + * + * You can use one or a combination of the filters. The log level follows the sequence of OFF, ERROR, WARNING, and INFO. Choose a level to see the logs preceding that level. If, for example, you set the log level to WARNING, you see the logs within levels ERROR and WARNING. + * + * - {@link AgoraRTM.LOG_FILTER_OFF} + * - {@link AgoraRTM.LOG_FILTER_ERROR} + * - {@link AgoraRTM.LOG_FILTER_INFO} (Default) + * - {@link AgoraRTM.LOG_FILTER_WARNING} + */ + logFilter?: LogFilterType; + + /** + * Whether to enable cloud proxy. + */ + enableCloudProxy?: boolean; +} + +/** @zh-cn + * 表示用户 ID/在线状态键值对的接口。 + *
      + *
    • `true`: 用户已登录到 Agora RTM 系统。
    • + *
    • `false`: 用户已登出 Agora RTM 系统或因其他原因与 Agora RTM 系统断开连接。
    • + *
    + */ +/** + * Interface for the peerId / online status key-value pair. + *
      + *
    • `true`: The user has logged in the Agora RTM system.
    • + *
    • `false`: The user has logged out of the Agora RTM system.
    • + *
    + */ +interface PeersOnlineStatusResult { + [peerId: string]: boolean; +} +/** @zh-cn + * 表示频道名/频道人数键值对的接口。 + */ +/** + * Interface for the channelId / channel member count key-value pair. + */ +interface ChannelMemberCountResult { + [channelId: string]: number; +} + +/** @zh-cn + * RTM 客户端类。你可以通过 {@link AgoraRTM} 上的 {@link createInstance} 方法创建 RTM 客户端实例。Agora RTM SDK 的入口。 + * @noInheritDoc + */ +/** + * Class that represents the RTM client. You can call the {@link createInstance} method of {@link AgoraRTM} to create an `RtmClient` instance. This class is the entry point of the Agora RTM SDK. + * @noInheritDoc + */ +declare class RtmClient extends EventEmitter { + /** @zh-cn + * 用户登录 Agora RTM 系统。 + * @note 在 RTM 和 RTC 结合使用的场景下,Agora 推荐你错时进行登录 RTM 系统和加入 RTC 频道的操作。 + * @note 如果用户在不同的 RtmClient 实例中以相同用户 ID 登录,之前的登录将会失效,用户会被踢出之前加入的频道。 + * @param options.uid 登录 Agora RTM 系统的用户 ID。该字符串不可超过 64 字节。以下为支持的字符集范围:
      + *
    • 26 个小写英文字母 a-z
    • + *
    • 26 个大写英文字母 A-Z
    • + *
    • 10 个数字 0-9
    • + *
    • 空格
    • + *
    • "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ","
    • + *
    + *

    Note

      + *
    • 请不要将 uid 设为空、null,或字符串 "null"。
    • + *
    • uid 不支持 number 类型。建议调用 toString() 方法转化非 string 型 uid。
    • + *
    + * @param options.token 可选的动态密钥,一般由客户的服务端获取。 + * @return 该 Promise 会在登录成功后 resolve。 + */ + /** + * Logs in to the Agora RTM system. + * + * @note If you use the Agora RTM SDK together with the Agora RTC SDK, Agora recommends that you avoid logging in to the RTM system and joining the RTC channel at the same time. + * @note If the user logs in with the same uid from a different instance, the user will be kicked out of your previous login and removed from previously joined channels. + * @param options.uid The uid of the user logging in the Agora RTM system. The string length must be less than 64 bytes with the following character scope:
      + *
    • All lowercase English letters: a to z
    • + *
    • All uppercase English letters: A to Z
    • + *
    • All numeric characters: 0 to 9
    • + *
    • The space character.
    • + *
    • Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ","
    • + *
    + *

    Note

      + *
    • The uid cannot be empty, or set as null or "null".
    • + *
    • We do not support uids of the number type and recommend using the toString() method to convert your non-string uid.
    • + *
    + * @param options.token An optional token generated by the app server. + * @return The Promise resolves after the user logs in to the Agora RTM system successfully. + */ + login(options: { uid: string; token?: string }): Promise; + + /** @zh-cn + * 退出登录,退出后自动断开连接和销毁回调监听。 + * @return 该 Promise 会在登出成功并断开 WebSocket 连接后 resolve。 + */ + /** + * Allows a user to log out of the Agora RTM system. + * + * After the user logs out of the Agora RTM system, the SDK disconnects from the Agora RTM system and destroys the corresponding event listener. + * @return The Promises resolves after the user logs out of the Agora RTM system and disconnects from WebSocket. + */ + logout(): Promise; + + /** @zh-cn + * 本地用户(发送者)向指定用户(接收者)发送点对点消息或点对点的离线消息。 + *

    发送消息(包括点对点消息和频道消息)的频率上限为 180 次每 3 秒。

    + * @example + * ```TypeScript + * client.sendMessageToPeer( + * { text: 'test peer message' }, // 一个 RtmMessage 实例。 + * 'PeerId', // 对端用户的 uid。 + * ).then(sendResult => { + * if (sendResult.hasPeerReceived) { + * // 你的代码:远端用户收到消息事件。 + * } else { + * // 你的代码:服务器已收到消息,对端未收到消息。 + * } + * }).catch(error => { + * // 你的代码:点对点消息发送失败。 + * }); + * ``` + * @param message 要发送的文字消息。 + * @param peerId 远端用户的 uid。 + *

    Note

    + * uid 不支持 number 类型。建议调用 toString() 方法转化非 string 型 uid。 + * @return 该 Promise 会在发送成功后 resolve。Promise 的值代表对方是否在线并接收成功。 + */ + /** + * Allows a user to send an (offline) peer-to-peer message to a specified remote user. + *

    You can send messages, including peer-to-peer and channel messages at a maximum frequency of 180 calls every three second.

    + * @example + * ```TypeScript + * client.sendMessageToPeer( + * { text: 'test peer message' }, // An RtmMessage object. + * 'demoPeerId', // The uid of the remote user. + * ).then(sendResult => { + * if (sendResult.hasPeerReceived) { + * // Your code for handling the event when the remote user receives the message. + * } else { + * // Your code for handling the event when the message is received by the server but the remote user cannot be reached. + * } + * }).catch(error => { + * // Your code for handling the event when the message fails to be sent. + * }); + * ``` + * @param message The message to be sent. + * @param peerId The uid of the peer user. + *

    Note

    + * We do not support uids of the number type. We recommend using the toString() method to convert a non-string uid. + * @return The Promise resolves after the message is successfully sent. The value of the Promise indicates whether the peer user is online and receives the message. + */ + sendMessageToPeer( + message: RtmMessage, + peerId: string, + ): Promise; + + /** @zh-cn + * 该方法创建一个 {@link RtmChannel} 实例。 + * @param channelId 频道名称。该字符串不可超过 64 字节。以下为支持的字符集范围:
      + *
    • 26 个小写英文字母 a-z
    • + *
    • 26 个大写英文字母 A-Z
    • + *
    • 10 个数字 0-9
    • + *
    • 空格
    • + *
    • "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ","
    • + *
    + *

    Note:

      + *
    • 请不要将 channelId 设为空、null,或字符串 "null"。
    + * @return 一个 {@link RtmChannel} 实例。 + */ + /** + * Creates an {@link RtmChannel} instance. + * @param channelId The unique channel name of the Agora RTM channel. The string length must be less than 64 bytes with the following character scope:
      + *
    • All lowercase English letters: a to z
    • + *
    • All uppercase English letters: A to Z
    • + *
    • All numeric characters: 0 to 9
    • + *
    • The space character.
    • + *
    • Punctuation characters and other symbols, including: "!", "#", "$", "%", "&", "(", ")", "+", "-", ":", ";", "<", "=", ".", ">", "?", "@", "[", "]", "^", "_", " {", "}", "|", "~", ","
    • + *
    + *

    Note:

      + *
    • The channelId cannot be empty, null, or "null".
    + * @return An {@link RtmChannel} instance. + */ + createChannel(channelId: string): RtmChannel; + /** @zh-cn + * 该方法创建一个 {@link LocalInvitation} 实例。 + * @param calleeId 被叫的 uid。 + * @return 一个 {@link LocalInvitation} 实例。 + */ + /** + * Creates a {@link LocalInvitation} instance. + * @param calleeId The uid of the callee. + * @return A {@link LocalInvitation} instance. + */ + createLocalInvitation(calleeId: string): LocalInvitation; + + /** @zh-cn + * 全量设置本地用户的属性。 + * + * @param attributes 新的属性。 + * @return 该 Promise 会在设置本地用户属性成功后 resolve。 + */ + /** + * Substitutes the local user's attributes with new ones. + * + * @param attributes The new attributes. + * @return The Promise resolves after successfully setting the local user's attributes. + */ + setLocalUserAttributes(attributes: AttributesMap): Promise; + + /** @zh-cn + * 添加或更新本地用户的属性。 + *
      + *
    • 如果属性已存在,该方法更新本地用户的已有属性;
    • + *
    • 如果属性不存在,该方法增加本地用户的属性。
    • + *
    + * + * @param attributes 待增加或更新的属性列表。 + * @return 该 Promise 会在添加或更新本地用户属性成功后 resolve。 + */ + /** + * Adds or updates the local user's attributes. + * + *

    This method updates the local user's attributes if it finds that the attributes has/have the same keys, or adds attributes to the local user if it does not. + * + * @param attributes The attributes to be added or updated. + * @return The Promise resolves after successfully adding or updating the local user's attributes. + */ + addOrUpdateLocalUserAttributes(attributes: AttributesMap): Promise; + + /** @zh-cn + * 删除本地用户的指定属性。 + * + * @param attributeKeys 属性名列表。 + * @return 该 Promise 会在删除指定属性成功后 resolve。 + */ + /** + * Deletes the local user's attributes using attribute keys. + * + * @param attributeKeys A list of the attribute keys to be deleted. + * @return The Promise resolves after successfully deleting the local user's attributes. + */ + deleteLocalUserAttributesByKeys(attributeKeys: string[]): Promise; + + /** @zh-cn + * 清空本地用户的所有属性。 + * @return 该 Promise 会在清空本地用户属性成功后 resolve。 + */ + /** + * Clears all attributes of the local user. + * @return The Promise resolves after successfully clearing the local user's attributes. + */ + clearLocalUserAttributes(): Promise; + + /** @zh-cn + * 获取指定用户的全部属性。 + * + * @param userId 指定用户的用户 ID。 + */ + /** + * Gets all attributes of a specified user. + * + * @param userId The user ID of the specified user. + */ + getUserAttributes(userId: string): Promise; + + /** @zh-cn + * 获取指定用户指定属性名的属性。 + * + * @param userId 指定用户的用户 ID。 + * @param attributeKeys 属性名列表。 + */ + /** + * Gets the attributes of a specified user by attribute keys. + * + * @param userId The user ID of the specified user. + * @param attributeKeys An array of the attribute keys. + */ + getUserAttributesByKeys( + userId: string, + attributeKeys: string[] + ): Promise; + + /** @zh-cn + * 查询指定用户的在线状态。 + * + * @param peerIds 用户 ID 列表。用户 ID 的数量不能超过 256。 + */ + /** + * Queries the online status of the specified users. + * + * @param peerIds A list of the user IDs. The number of user IDs must not exceed 256. + */ + queryPeersOnlineStatus(peerIds: string[]): Promise; + + /** @zh-cn + * 更新当前 Token。 + * + * @param token 新的 Token。 + */ + /** + * Renews the token. + * + * @param token Your new Token. + */ + renewToken(token: string): Promise; + + /** @zh-cn + * 修改 `RtmClient` 实例配置。修改实时生效。 + * + * @param config 设置 SDK 是否上传日志以及日志的输出等级。详见 {@link RtmConfig}。 + */ + /** + * Modifies the `RtmClient` instance configuration. The changes take effect immediately. + * + * @param config Sets whether the SDK uploads logs, and sets the output level of logs. See {@link RtmConfig}. + */ + updateConfig(config: RtmConfig): void; + + /** @zh-cn + * + * 修改 `RtmClient` 实例配置。修改实时生效。 + * + * @deprecated 该方法自 v1.4.2 起已废弃,请使用 {@link updateConfig}。 + * + * + * @param config 设置 SDK 是否上传日志以及日志的输出等级。详见 {@link RtmConfig}。 + */ + /** + * Modifies the `RtmClient` instance configuration. The changes take effect immediately. + * + * @deprecated This method is deprecated as of v1.4.2. Please use {@link updateConfig} instead. + * + * @param config Sets whether the SDK uploads logs, and sets the output level of logs. See {@link RtmConfig}. + */ + setParameters(config: RtmConfig): void; + + /** @zh-cn + * 查询单个或多个频道的成员人数。 + * + *

    Note

    + *
      + *
    • 该方法的调用频率上限为每秒 1 次。
    • + *
    • 不支持一次查询超过 32 个频道的成员人数。
    • + *
    + * @param channelIds 指定频道名列表。 + */ + /** + * Gets the member count of specified channels. + * + *

    Note

    + *
      + *
    • The call frequency limit for this method is one call per second.
    • + *
    • We do not support getting the member counts of more than 32 channels in one method call.
    • + *
    + * @param channelIds An array of the specified channel IDs. + */ + getChannelMemberCount( + channelIds: string[] + ): Promise; + + /** @zh-cn + * 查询某指定频道的全部属性。 + * + *

    Note

    + *
      + *
    • 你无需加入指定频道即可查询该频道的属性。
    • + *
    • {@link getChannelAttributes} 和 {@link getChannelAttributesByKeys} 一并计算在内:调用频率限制为每 5 秒 10 次。
    • + *
    + * @param channelId 该指定频道的 ID。 + */ + /** + * Gets all attributes of a specified channel. + * + *

    Note

    + *
      + *
    • You do not have to join the specified channel to delete its attributes.
    • + *
    • For {@link getChannelAttributes} and {@link getChannelAttributesByKeys} taken together: the call frequency limit is 10 calls every five seconds.
    • + *
    + * @param channelId The ID of the specified channel. + */ + getChannelAttributes(channelId: string): Promise; + + /** @zh-cn + * 查询某指定频道指定属性名的属性。 + * + *

    Note

    + *
      + *
    • 你无需加入指定频道即可查询该频道的属性。
    • + *
    • {@link getChannelAttributes} 和 {@link getChannelAttributesByKeys} 一并计算在内:调用频率限制为每 5 秒 10 次。
    • + *
    + * @param channelId 该指定频道的频道 ID。 + * @param keys 频道属性名列表。 + */ + /** + * Gets the attributes of a specified channel by attribute keys. + * + *

    Note

    + *
      + *
    • You do not have to join the specified channel to get its attributes.
    • + *
    • For {@link getChannelAttributes} and {@link getChannelAttributesByKeys} taken together: the call frequency limit is 10 calls every five seconds.
    • + *
    + * @param channelId The ID of the specified channel. + * @param keys An array of attribute keys. + */ + getChannelAttributesByKeys( + channelId: string, + keys: string[] + ): Promise; + + /** @zh-cn + * 清空某指定频道的属性。 + * + *

    Note

    + *
      + *
    • 你无需加入指定频道即可清空该频道的属性。
    • + *
    • [RtmClient.setChannelAttributes()]{@link setLocalUserAttributes}、 {@link addOrUpdateChannelAttributes}、 {@link deleteChannelAttributesByKeys} 和 {@link clearChannelAttributes} 一并计算在内:调用频率限制为每 5 秒 10 次。
    • + *
    + * @param channelId 该指定频道的频道 ID。 + * @param options 频道属性操作选项。详见 {@link ChannelAttributeOptions}。 + */ + /** + * Clears all attributes of a specified channel. + * + *

    Note

    + * + * - You do not have to join the specified channel to clear its attributes. + * - For {@link RtmClient.setChannelAttributes}, {@link addOrUpdateChannelAttributes}, {@link deleteChannelAttributesByKeys}, and {@link clearChannelAttributes} taken together: the call frequency limit is 10 calls every five seconds. + * @param channelId The channel ID of the specified channel. + * @param options Options for this attribute operation. See {@link ChannelAttributeOptions}. + */ + clearChannelAttributes( + channelId: string, + options?: ChannelAttributeOptions + ): Promise; + + /** @zh-cn + * 删除某指定频道的指定属性。 + * + *

    Note

    + *
      + *
    • 你无需加入指定频道即可删除该频道的属性。
    • + *
    • 当某频道处于空频道状态(无人状态)数分钟后,该频道的频道属性将被清空。
    • + *
    • {@link setLocalUserAttributes}、 {@link addOrUpdateChannelAttributes}、 {@link deleteChannelAttributesByKeys} 和 {@link clearChannelAttributes} 一并计算在内:调用频率限制为每 5 秒 10 次。
    • + *
    + * @param channelId 该指定频道的 ID。 + * @param attributeKeys 属性名列表。 + * @param options 频道属性操作选项。详见 {@link ChannelAttributeOptions}。 + */ + /** + * Deletes the local user's attributes using attribute keys. + * + *

    Note

    + *
      + *
    • You do not have to join the specified channel to delete its attributes.
    • + *
    • The attributes of a channel will be cleared if the channel remains empty (has no members) for a couple of minutes.
    • + *
    • For {@link setLocalUserAttributes}, {@link addOrUpdateChannelAttributes}, {@link deleteChannelAttributesByKeys}, and {@link clearChannelAttributes} taken together: the call frequency limit is 10 calls every five seconds.
    • + *
    + * @param channelId The channel ID of the specified channel. + * @param attributeKeys A list of channel attribute keys. + * @param options Options for this attribute operation. See {@link ChannelAttributeOptions}. + */ + deleteChannelAttributesByKeys( + channelId: string, + attributeKeys: string[], + options?: ChannelAttributeOptions + ): Promise; + + /** @zh-cn + * 添加或更新某指定频道的属性。 + *
      + *
    • 如果属性已存在,该方法更新该频道的已有属性;
    • + *
    • 如果属性不存在,该方法增加该频道的属性。
    • + *
    + *

    Note

    + *
      + *
    • 你无需加入指定频道即可为该频道更新频道属性。
    • + *
    • 当某频道处于空频道状态(无人状态)数分钟后,该频道的频道属性将被清空。
    • + *
    • {@link setLocalUserAttributes}、 {@link addOrUpdateChannelAttributes}、 {@link deleteChannelAttributesByKeys} ,和 {@link clearChannelAttributes} 一并计算在内:调用频率限制为每 5 秒 10 次。
    • + *
    + * @param channelId 该指定频道的 ID。 + * @param attributes 待增加或更新的属性列表。 + * @param options 频道属性操作选项。详见 {@link ChannelAttributeOptions}。 + */ + /** + * Adds or updates the attributes of a specified channel. + * + * This method updates the specified channel's attributes if it finds that the attributes has/have the same keys, or adds attributes to the channel if it does not. + * + *

    Note

    + *
      + *
    • You do not have to join the specified channel to update its attributes.
    • + *
    • The attributes of a channel will be cleared if the channel remains empty (has no members) for a couple of minutes.
    • + *
    • For {@link setLocalUserAttributes}, {@link addOrUpdateChannelAttributes}, {@link deleteChannelAttributesByKeys}, and {@link clearChannelAttributes} taken together: the call frequency limit is 10 calls every five seconds.
    • + *
    + * @param channelId The channel ID of the specified channel. + * @param attributes An array of channel attributes. + * @param options Options for this attribute operation. See {@link ChannelAttributeOptions}. + */ + addOrUpdateChannelAttributes( + channelId: string, + attributes: AttributesMap, + options?: ChannelAttributeOptions + ): Promise; + + /** @zh-cn + * 全量设置某指定频道的属性。 + * + *

    Note

    + *
      + *
    • 你无需加入指定频道即可为该频道设置频道属性。
    • + *
    • 当某频道处于空频道状态(无人状态)数分钟后,该频道的频道属性将被清空。
    • + *
    • {@link setLocalUserAttributes}、 {@link addOrUpdateChannelAttributes}、 {@link deleteChannelAttributesByKeys} ,和 {@link clearChannelAttributes} 一并计算在内:调用频率限制为每 5 秒 10 次。
    • + *
    + * @param channelId 该指定频道的频道 ID。 + * @param attributes 频道属性列表实例。 + * @param options 频道属性操作选项。详见 {@link ChannelAttributeOptions}。 + */ + /** + * Sets the attributes of a specified channel with new ones. + * + *

    Note

    + *
      + *
    • You do not have to join the specified channel to reset its attributes.
    • + *
    • The attributes of a channel will be cleared if the channel remains empty (has no members) for a couple of minutes.
    • + *
    • For {@link setLocalUserAttributes}, {@link addOrUpdateChannelAttributes}, {@link deleteChannelAttributesByKeys}, and {@link clearChannelAttributes} taken together: the call frequency limit is 10 calls every five seconds.
    • + *
    + * @param channelId The channel ID of the specified channel. + * @param attributes An array of channel attributes. + * @param options Options for this attribute operation. See {@link ChannelAttributeOptions}. + */ + setChannelAttributes( + channelId: string, + attributes: AttributesMap, + options?: ChannelAttributeOptions + ): Promise; + + /** @zh-cn + * 订阅指定单个或多个用户的在线状态。 + *
      + *
    • 首次订阅成功后,SDK 会通过 {@link RtmClientEvents.PeersOnlineStatusChanged} 回调返回被订阅用户在线状态。
    • + *
    • 每当被订阅用户在线状态发生变化时,SDK 都会通过 {@link RtmClientEvents.PeersOnlineStatusChanged} 回调通知订阅方。
    • + *
    • 如果 SDK 在断线重连过程中有被订阅用户的在线状态发生改变,SDK 会在重连成功时通过 {@link RtmClientEvents.PeersOnlineStatusChanged} 回调通知订阅方。
    • + *
    + *

    Note

    + *
      + *
    • 用户登出 Agora RTM 系统后,所有之前的订阅内容都会被清空;重新登录后,如需保留之前订阅内容则需重新订阅。
    • + *
    • SDK 会在网络连接中断时进入断线重连状态。重连成功时 SDK 会自动重新订阅之前订阅用户,无需人为干预。
    • + *
    + * @param peerIds + */ + /** + * Subscribes to the online status of the specified users. + *
      + *
    • When the method call succeeds, the SDK returns the {@link RtmClientEvents.PeersOnlineStatusChanged} callback to report the online status of peers, to whom you subscribe.
    • + *
    • When the online status of the peers, to whom you subscribe, changes, the SDK returns the {@link RtmClientEvents.PeersOnlineStatusChanged} callback to report whose online status has changed.
    • + *
    • If the online status of the peers, to whom you subscribe, changes when the SDK is reconnecting to the server, the SDK returns the {@link RtmClientEvents.PeersOnlineStatusChanged} callback to report whose online status has changed when successfully reconnecting to the server.
    • + *
    + *

    Note

    + *
      + *
    • When you log out of the Agora RTM system, all the status that you subscribe to will be cleared. To keep the original subscription after you re-log in the system, you need to redo the whole subscription process.
    • + *
    • When the SDK reconnects to the server from the state of being interrupted, the SDK automatically subscribes to the peers and states before the interruption without human intervention.
    • + *
    + * @param peerIds An array of the specified user IDs. + */ + subscribePeersOnlineStatus(peerIds: string[]): Promise; + + /** @zh-cn + * 退订指定单个或多个用户的在线状态。 + * + * @param peerIds 被退订用户的用户 ID 阵列。 + */ + /** + * Unsubscribes from the online status of the specified users. + * + * @param peerIds An array of the specified user IDs. + */ + unsubscribePeersOnlineStatus(peerIds: string[]): Promise; + + /** @zh-cn + * 获取某特定内容被订阅的用户列表。 + * + * @param option 被订阅的类型。详见 {@link RtmStatusCode.PeerSubscriptionOption}。 + */ + /** + * Gets a list of the peers, to whose specific status you have subscribed. + * + * @param option The status type, to which you have subscribed. See {@link RtmStatusCode.PeerSubscriptionOption}. + */ + queryPeersBySubscriptionOption( + option: RtmStatusCode.PeerSubscriptionOption + ): Promise; + + + + /** @zh-cn + * 创建一个消息实例,可用于发送点对点消息或频道消息。 + * + * @typeParam T {@link RtmMessage} 类型别名。 + * + * @param message 一个包含 {@link RtmMessage} 中任意属性的对象。 + * + * @return 一个 {@link RtmMessage} 实例。你可以用这个实例发送点对点消息或频道消息。 + * + */ + /** + * + * @typeParam T A {@link RtmMessage} type. + * + * @param message An object that includes any property of {@link RtmMessage}. + * + * @return A message instance to send. You can use the message instance to send peer-to-peer or channel messages. + * + */ + createMessage(message: Partial): T; + + /** @zh-cn + * 在该频道实例上添加 `listener` 函数到名为 `eventName` 的事件。其他 `RtmClient` 实例上的事件方法请参考 [`EventEmitter` API 文档](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter)。 + * @param eventName RTM 客户端事件的名称。事件列表请参考 {@link RtmClientEvents} 中的属性名。 + * @param listener 事件的回调函数。 + */ + /** + * Adds the `listener` function to the channel for the event named `eventName`. See [the `EventEmitter` API documentation](https://nodejs.org/docs/latest/api/events.html#events_class_eventemitter) for other event methods on the `RtmClient` instance. + * @param eventName The name of the RTM client event. See the property names in the {@link RtmClientEvents} for the list of events. + * @param listener The callback function of the RTM client event. + */ + on( + eventName: EventName, + listener: ( + ...args: ListenerType + ) => any + ): this; +} + +/** @zh-cn + * AgoraRTM 是 Agora RTM SDK 的导出模块。 + * + * 使用 ``。 + * + * **Note:** + * + * 此处文件名 `agora-rtm-sdk-0.9.1.js` 中的版本号 `0.9.1` 仅供参考,安装时请使用最新版的 SDK 和链接地址。 + */ +/** + * AgoraRTM is the exported module of the Agora RTM SDK. + * + * If you import the Agora RTM Web SDK using the `` in your HTML. + *

    Note:

    + *

    The version `0.9.1` in the file name `agora-rtm-sdk-0.9.1.js` is for reference only, please use the latest version of the SDK. + */ +declare namespace AgoraRTM { + /** @zh-cn + * 不输出日志信息。 + */ + /** + * Do not output any log information. + */ + const LOG_FILTER_OFF: LogFilterType; + /** @zh-cn + * 输出 ERROR 级别的日志信息。 + */ + /** + * Output ERROR level log information. + */ + const LOG_FILTER_ERROR: LogFilterType; + /** @zh-cn + * 输出 ERROR、WARNING 和 INFO 级别的日志信息。 我们推荐你将日志级别设为该等级。 + */ + /** + * Output ERROR, WARNING, and INFO level log information. + */ + const LOG_FILTER_INFO: LogFilterType; + /** @zh-cn + * 输出 ERROR 和 WARNING 级别的日志信息。 + */ + /** + * Output WARNING and INFO level log information. + */ + const LOG_FILTER_WARNING: LogFilterType; + // const LOG_FILTER_DEBUG: LogFilterType; + + /** @zh-cn + * Agora RTM SDK 的版本号。 + */ + /** + * Version of the Agora RTM SDK. + * @example `AgoraRTM.VERSION` + */ + const VERSION: string; + + /** @zh-cn + * Agora RTM SDK 的编译信息。 + */ + /** + * Compilation information of the Agora RTM SDK. + * @example `AgoraRTM.BUILD` + */ + const BUILD: string; + + const END_CALL_PREFIX: string; + + /** @zh-cn + * 该方法创建并返回一个 {@link RtmClient} 实例。 + *

    Agora RTM SDK 支持多个 {@link RtmClient} 实例。

    + *

    {@link RtmClient} 类的所有接口函数都是异步调用。

    + * @example **创建 RtmClient 对象** + * + * ```JavaScript + * import AgoraRTM from 'agora-rtm-sdk'; + * const client = AgoraRTM.createInstance('demoAppId', { enableLogUpload: false }); // Pass your App ID here. + * ``` + * @param appId 传入项目的 App ID。必须是 ASCII 编码,长度为 32 个字符。 + * @param config {@link RtmClient} 对象的配置参数。详见 {@link RtmConfig}。 + * @return 一个 {@link RtmClient} 实例。 + */ + /** + * Creates and returns an {@link RtmClient} instance. + *

    The Agora RTM SDK supports creating multiple {@link RtmClient} instances.

    + *

    All methods in the {@link RtmClient} class are executed asynchronously.

    + * @example **Create an RtmClient instance** + * + * ```JavaScript + * import AgoraRTM from 'agora-rtm-sdk'; + * const client = AgoraRTM.createInstance('demoAppId', { enableLogUpload: false }); // Pass your App ID here. + * ``` + * @param appId App ID of your project that must be a string containing 32 ASCII characters. + * @param config The configuration of an {@link RtmClient} instance. See {@link RtmConfig}. + * @return An {@link RtmClient} instance. + */ + function createInstance(appId: string, config?: RtmConfig): RtmClient; + + /** @zh-cn + * @deprecated 从 v1.4.3 起废弃,声网不建议你使用。请改用 {@link createInstance} 方法。 + * 该方法创建并返回一个 {@link RtmClient} 实例。 + *

    Agora RTM SDK 支持多个 {@link RtmClient} 实例。

    + *

    {@link RtmClient} 类的所有接口函数都是异步调用。

    + * @example **创建 RtmClient 对象** + * + * ```JavaScript + * import AgoraRTM from 'agora-rtm-sdk'; + * const client = AgoraRTM.createInstance('demoAppId', { enableLogUpload: false }); // Pass your App ID here. + * ``` + * @param appId 传入项目的 App ID。必须是 ASCII 编码,长度为 32 个字符。 + * @param config {@link RtmClient} 对象的配置参数。详见 {@link RtmConfig}。 + * @param areaCodes Agora RTM 服务的限定区域。详见 {@link AreaCode}。 + * @return 一个 {@link RtmClient} 实例。 + */ + /** + * @deprecated From v2.3.2. Use {@link createInstance} instead. + * + * Creates and returns an {@link RtmClient} instance. + *

    The Agora RTM SDK supports creating multiple {@link RtmClient} instances.

    + *

    All methods in the {@link RtmClient} class are executed asynchronously.

    + * @example **Create an RtmClient instance** + * + * ```JavaScript + * import AgoraRTM from 'agora-rtm-sdk'; + * const client = AgoraRTM.createInstance('demoAppId', { enableLogUpload: false }); // Pass your App ID here. + * ``` + * @param appId App ID of your project that must be a string containing 32 ASCII characters. + * @param config The configuration of an {@link RtmClient} instance. See {@link RtmConfig}. + * @param areaCodes Region for the Agora RTM service. See {@link AreaCode}. + * @return An {@link RtmClient} instance. + */ + function createInstance( + appId: string, + config?: RtmConfig, + areaCodes?: RtmStatusCode.AreaCode[] + ): RtmClient; + + /** @zh-cn + * @since 1.4.3 + * + * 设置 Agora RTM SDK 的访问区域。支持设置多个访问区域。 + * + * 注意: + * - 该功能为高级设置,适用于有访问安全限制的场景。 + * - 默认情况下,SDK 会就近选择 Agora 服务器进行连接。设置访问区域之后,SDK 只会连接到指定区域内的 Agora 服务器。 + * - 该方法支持去除访问区域中的个别区域。 + * @param areaConfig 访问区域设置。 + * - areaCodes 访问区域,详见 {@link AreaCode}。 + * - excludedArea 排除区域,支持设置为`CHINA`,`JAPAN` 和 `ASIA`。该参数仅对于 `GLOBAL` 的访问区域有效。 + * @param areaCodes 访问区域,详见 {@link AreaCode}。 + * @param excludedArea 排除区域,支持设置为`CHINA`,`JAPAN` 和 `ASIA`。该参数仅对于 `GLOBAL` 的访问区域有效。 + */ + /** + * @since 1.4.3 + * + * Sets the regions for connection. + * + * **Note:** + * - This advanced feature applies to scenarios that have regional restrictions. + * - By default, the SDK connects to nearby Agora servers. After specifying the regions, the SDK connects to the Agora servers within those regions. + * - You can remove some areas from the region for connection. + * @param areaConfig The configration of regions for connection. + * - areaCodes: The region for connection. For details, see {@link AreaCode}. + * - excludedArea: Exclude areas, which can be set to `CHINA`, `JAPAN` and `ASIA`. This parameter is only valid when the region for connection is `GLOBAL`. + */ + function setArea(areaConfig: { + areaCodes: RtmStatusCode.AreaCode[]; + excludedArea?: RtmStatusCode.AreaCode; + }): void; + + /**@zh-cn + * 连接状态改变原因。 + */ + /** + * The reason of the connection state change. + */ + const ConnectionChangeReason: typeof RtmStatusCode.ConnectionChangeReason; + /**@zh-cn + * 连接状态。 + */ + /** + * The connection state. + */ + const ConnectionState: typeof RtmStatusCode.ConnectionState; + /**@zh-cn + * (返回给主叫)呼叫邀请失败原因。 + */ + /** + * (Return to the caller) The reason of the local invitation failure. + */ + const LocalInvitationFailureReason: typeof RtmStatusCode.LocalInvitationFailureReason; + /**@zh-cn + * 返回给主叫的呼叫邀请状态。 + */ + /** + * Call invitation state returned to the caller. + */ + const LocalInvitationState: typeof RtmStatusCode.LocalInvitationState; + /**@zh-cn + * 返回给被叫的呼叫邀请状态。 + */ + /** + * Call invitation state returned to the callee. + */ + const RemoteInvitationState: typeof RtmStatusCode.RemoteInvitationState; + /**@zh-cn + * (返回给被叫)呼叫邀请失败原因。 + */ + /** + * (Return to the callee) The reason of the local invitation failure. + */ + const RemoteInvitationFailureReason: typeof RtmStatusCode.RemoteInvitationFailureReason; + /**@zh-cn + * 消息类型。 + */ + /** + * Message type. + */ + const MessageType: typeof RtmStatusCode.MessageType; + /**@zh-cn + * 用户的在线状态。 + */ + /** + * Online state of the user. + */ + const PeerOnlineState: typeof RtmStatusCode.PeerOnlineState; + /**@zh-cn + * 订阅类型。 + */ + /** + * Subscription type. + */ + const PeerSubscriptionOption: typeof RtmStatusCode.PeerSubscriptionOption; + /**@zh-cn + * Agora RTM 服务的限定区域。默认为 AgoraAreaGLOB,即限定区域为全球。详见 {@link AreaCode}。 + */ + /** + * Region for the Agora RTM service. The default is `GLOBAL`. See {@link AreaCode}. + */ + const AreaCode: typeof RtmStatusCode.AreaCode; +} + +export default AgoraRTM; +export type { LocalInvitation, RemoteInvitation, RtmChannel, RtmClient, RtmEvents, RtmMessage, RtmRawMessage, RtmStatusCode, RtmTextMessage }; diff --git a/node_modules/agora-rtm-sdk/index.js b/node_modules/agora-rtm-sdk/index.js new file mode 100644 index 000000000..43a2b4461 --- /dev/null +++ b/node_modules/agora-rtm-sdk/index.js @@ -0,0 +1,8 @@ +/* + @preserve + AgoraRTM Web SDK 1.5.1 - commit: v1.5.1-0-g5bbbcd72 + Copyright (C) 2018-2022 Agora Lab. + This file is licensed under the AGORA, INC. SDK LICENSE AGREEMENT + A copy of this license may be found at https://www.agora.io/en/sdk-license-agreement/ +*/ +"use strict";!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).AgoraRTM=t()}(this,(function(){function Be(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Wa(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);narguments.length?e:arguments[2];return Ia(e)===r?e[t]:(n=dc.f(e,t))?ka(n,"value")?n.value:void 0===n.get?void 0:n.get.call(r):xa(n=uc(e))?Am(n,t,r):void 0}function bu(e){var t=e.charCodeAt(0)<<24,n=0|cu(~t),r=0,o=0|e.length,i="";if(5>n&&o>=n){for(t=t<>>24+n,r=1;r=t?i+=Ud(t):1114111>=t?i+=Ud(55296+((t=t-65536|0)>>10)|0,56320+(1023&t)|0):r=0}for(;r=t){var n=0|e.charCodeAt(1);if(!(n==n&&56320<=n&&57343>=n))return Ud(239,191,189);if(65535<(t=(t-55296<<10)+n-56320+65536|0))return Ud(240|t>>>18,128|t>>>12&63,128|t>>>6&63,128|63&t)}return 127>=t?e:2047>=t?Ud(192|t>>>6,128|63&t):Ud(224|t>>>12,128|t>>>6&63,128|63&t)}function Cm(){}function Ba(){Ba.init.call(this)}function Wg(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+qa(e))}function Dm(e,t,n,r){Wg(n);var o=e._events;if(void 0===o)o=e._events=Object.create(null),e._eventsCount=0;else{void 0!==o.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),o=e._events);var i=o[t]}return void 0===i?(o[t]=n,++e._eventsCount):("function"==typeof i?i=o[t]=r?[n,i]:[i,n]:r?i.unshift(n):i.push(n),0<(n=void 0===e._maxListeners?Ba.defaultMaxListeners:e._maxListeners)&&i.length>n&&!i.warned&&(i.warned=!0,(n=Error("Possible EventEmitter memory leak detected. "+i.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit")).name="MaxListenersExceededWarning",n.emitter=e,n.type=t,n.count=i.length,console&&console.warn&&console.warn(n))),e}function eu(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function Em(e,t,n){return e={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},(t=eu.bind(e)).listener=n,e.wrapFn=t}function Fm(e,t,n){if(void 0===(e=e._events))return[];if(void 0===(t=e[t]))return[];if("function"==typeof t)return n?[t.listener||t]:[t];if(n)for(n=Array(t.length),e=0;e>>=0)&&256>e)&&(n=Vm[e]))return n;n=Qa(e,0>(0|e)?-1:0,!0),t&&(Vm[e]=n)}else{if((t=-128<=(e|=0)&&128>e)&&(n=Wm[e]))return n;n=Qa(e,0>e?-1:0,!1),t&&(Wm[e]=n)}return n}function ec(e,t){if(isNaN(e))return t?Yd:fc;if(t){if(0>e)return Yd;if(e>=Xm)return Ym}else{if(e<=-Zm)return Ib;if(e+1>=Zm)return $m}return 0>e?ec(-e,t).neg():Qa(e%Me|0,e/Me|0,t)}function Qa(e,t,n){return new Pa(e,t,n)}function Vi(e,t,n){if(0===e.length)throw Error("empty string");if("NaN"===e||"Infinity"===e||"+Infinity"===e||"-Infinity"===e)return fc;if("number"==typeof t?(n=t,t=!1):t=!!t,2>(n=n||10)||36s?(s=ec(ah(n,s)),o=o.mul(s).add(ec(a))):o=(o=o.mul(r)).add(ec(a))}return o.unsigned=t,o}function vc(e,t){return"number"==typeof e?ec(e,t):"string"==typeof e?Vi(e,t):Qa(e.low,e.high,"boolean"==typeof t?t:e.unsigned)}function ha(e,t){function n(){this.constructor=e}Wi(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}function Ne(e){return"function"==typeof e}function Oe(e){setTimeout((function(){throw e}),0)}function Xi(e){return null!==e&&"object"===qa(e)}function an(e){return e.reduce((function(e,t){return e.concat(t instanceof Pf?t.errors:t)}),[])}function Yi(e){for(;e;){var t=e.destination,n=e.isStopped;if(e.closed||n)return!1;e=t&&t instanceof za?t:null}return!0}function wd(e){return e}function Zi(){for(var e=[],t=0;t=e.length?e[0]:e),o.complete()}]))}catch(e){Yi(o)?o.error(e):console.warn(e)}}return o.subscribe(r)}))}}function Du(e){var t=this,n=e.args,r=e.subscriber,o=e.params;e=o.callbackFunc;var i=o.context,s=o.scheduler,a=o.subject;if(!a){a=o.subject=new Sf,o=function(){for(var e=[],n=0;n=e.length?e[0]:e,subject:a}))};try{e.apply(i,n.concat([o]))}catch(e){a.error(e)}}this.add(a.subscribe(r))}function Eu(e){var t=e.subject;t.next(e.value),t.complete()}function hn(e,t,n){if(t){if(!ad(t))return function(){for(var r=[],o=0;o=e.length?e[0]:e),s.complete())}]))}catch(e){Yi(s)?s.error(e):console.warn(e)}}return s.subscribe(r)}))}}function Fu(e){var t=this,n=e.params,r=e.subscriber;e=e.context;var o=n.callbackFunc,i=n.args,s=n.scheduler,a=n.subject;if(!a){a=n.subject=new Sf,n=function(){for(var e=[],n=0;n=e.length?e[0]:e,subject:a}))};try{o.apply(e,i.concat([n]))}catch(e){this.add(s.schedule(jn,0,{err:e,subject:a}))}}this.add(a.subscribe(r))}function Gu(e){var t=e.subject;t.next(e.value),t.complete()}function jn(e){e.subject.error(e.err)}function kn(e){return!!e&&"function"!=typeof e.subscribe&&"function"==typeof e.then}function bj(e,t,n,r,o){if(void 0===o&&(o=new Hu(e,n,r)),!o.closed)return t instanceof ua?t.subscribe(o):Tf(t)(o)}function Iu(e,t){return new ua((function(n){var r=new nb;return r.add(t.schedule((function(){var o=e[Pe]();r.add(o.subscribe({next:function(e){r.add(t.schedule((function(){return n.next(e)})))},error:function(e){r.add(t.schedule((function(){return n.error(e)})))},complete:function(){r.add(t.schedule((function(){return n.complete()})))}}))}))),r}))}function Ju(e,t){return new ua((function(n){var r=new nb;return r.add(t.schedule((function(){return e.then((function(e){r.add(t.schedule((function(){n.next(e),r.add(t.schedule((function(){return n.complete()})))})))}),(function(e){r.add(t.schedule((function(){return n.error(e)})))}))}))),r}))}function Ku(e,t){if(!e)throw Error("Iterable cannot be null");return new ua((function(n){var r,o=new nb;return o.add((function(){r&&"function"==typeof r.return&&r.return()})),o.add(t.schedule((function(){r=e[xd](),o.add(t.schedule((function(){if(!n.closed){try{var e=r.next(),t=e.value,o=e.done}catch(e){return void n.error(e)}o?n.complete():(n.next(t),this.schedule())}})))}))),o}))}function ln(e,t){if(null!=e){if(e&&"function"==typeof e[Pe])return Iu(e,t);if(kn(e))return Ju(e,t);if(mn(e))return $i(e,t);if(e&&"function"==typeof e[xd]||"string"==typeof e)return Ku(e,t)}throw new TypeError((null!==e&&qa(e)||e)+" is not observable")}function Jc(e,t){return t?ln(e,t):e instanceof ua?e:new ua(Tf(e))}function bd(e,t){if(!t.closed){if(e instanceof ua)return e.subscribe(t);try{var n=Tf(e)(t)}catch(e){t.error(e)}return n}}function Cb(e,t,n){return void 0===n&&(n=Number.POSITIVE_INFINITY),"function"==typeof t?function(r){return r.pipe(Cb((function(n,r){return Jc(e(n,r)).pipe(Ea((function(e,o){return t(n,e,r,o)})))}),n))}:("number"==typeof t&&(n=t),function(t){return t.lift(new Lu(e,n))})}function bh(e){return void 0===e&&(e=Number.POSITIVE_INFINITY),Cb(wd,e)}function nn(){for(var e=[],t=0;te)&&(e=0),t&&"function"==typeof t.schedule||(t=cd),new ua((function(n){return n.add(t.schedule(Nu,e,{subscriber:n,counter:0,period:e})),n}))}function Nu(e){var t=e.subscriber,n=e.counter;e=e.period,t.next(n),this.schedule({subscriber:t,counter:n+1,period:e},e)}function Jb(){for(var e=[],t=0;t=e.count?r.complete():(r.next(t),r.closed||(e.index=n+1,e.start=t+1,this.schedule(e)))}function dd(e,t,n){void 0===e&&(e=0);var r=-1;return cj(t)?r=1>Number(t)?1:Number(t):ad(t)&&(n=t),ad(n)||(n=cd),new ua((function(t){var o=cj(e)?e:+e-n.now();return n.schedule(Tu,o,{index:0,period:r,subscriber:t})}))}function Tu(e){var t=e.index,n=e.period,r=e.subscriber;if(r.next(t),!r.closed){if(-1===n)return r.complete();e.index=t+1,this.schedule(e,n)}}function ej(){for(var e=[],t=0;t=arguments.length?0:arguments.length-1)?"number"==typeof(1>=arguments.length?void 0:arguments[1])?t=1>=arguments.length?void 0:arguments[1]:n=1>=arguments.length?void 0:arguments[1]:2==(1>=arguments.length?0:arguments.length-1)&&(t=1>=arguments.length?void 0:arguments[1],n=2>=arguments.length?void 0:arguments[2]);var r=t||1;return function(t){return t.pipe(gh((function(t,o){var i=n.now(),s=i-e;if((t=t.filter((function(e){return e.until>s}))).length>=r){var a=t[t.length-1],c=t[0].until+e*Math.floor(t.length/r);t.push({delay:a.untilt?1:0;if(o&&(t=-t),0===t)e(0<1/t?0:2147483648,n,r);else if(isNaN(t))e(2143289344,n,r);else if(34028234663852886e22>>0,n,r);else if(11754943508222875e-54>t)e((o<<31|Math.round(t/1401298464324817e-60))>>>0,n,r);else{var i=Math.floor(Math.log(t)/Math.LN2);e((o<<31|i+127<<23|8388607&Math.round(t*Math.pow(2,-i)*8388608))>>>0,n,r)}}function n(e,t,n){return n=e(t,n),e=2*(n>>31)+1,t=n>>>23&255,n&=8388607,255===t?n?NaN:1/0*e:0===t?1401298464324817e-60*e*n:e*Math.pow(2,t-150)*(n+8388608)}e.writeFloatLE=t.bind(null,Gn),e.writeFloatBE=t.bind(null,Hn),e.readFloatLE=n.bind(null,In),e.readFloatBE=n.bind(null,Jn)}(),"undefined"!=typeof Float64Array?function(){function t(e,t,n){i[0]=e,t[n]=s[0],t[n+1]=s[1],t[n+2]=s[2],t[n+3]=s[3],t[n+4]=s[4],t[n+5]=s[5],t[n+6]=s[6],t[n+7]=s[7]}function n(e,t,n){i[0]=e,t[n]=s[7],t[n+1]=s[6],t[n+2]=s[5],t[n+3]=s[4],t[n+4]=s[3],t[n+5]=s[2],t[n+6]=s[1],t[n+7]=s[0]}function r(e,t){return s[0]=e[t],s[1]=e[t+1],s[2]=e[t+2],s[3]=e[t+3],s[4]=e[t+4],s[5]=e[t+5],s[6]=e[t+6],s[7]=e[t+7],i[0]}function o(e,t){return s[7]=e[t],s[6]=e[t+1],s[5]=e[t+2],s[4]=e[t+3],s[3]=e[t+4],s[2]=e[t+5],s[1]=e[t+6],s[0]=e[t+7],i[0]}var i=new Float64Array([-0]),s=new Uint8Array(i.buffer),a=128===s[7];e.writeDoubleLE=a?t:n,e.writeDoubleBE=a?n:t,e.readDoubleLE=a?r:o,e.readDoubleBE=a?o:r}():function(){function t(e,t,n,r,o,i){var s=0>r?1:0;if(s&&(r=-r),0===r)e(0,o,i+t),e(0<1/r?0:2147483648,o,i+n);else if(isNaN(r))e(0,o,i+t),e(2146959360,o,i+n);else if(17976931348623157e292>>0,o,i+n);else if(22250738585072014e-324>r)e((r/=5e-324)>>>0,o,i+t),e((s<<31|r/4294967296)>>>0,o,i+n);else{var a=Math.floor(Math.log(r)/Math.LN2);1024===a&&(a=1023),e(4503599627370496*(r*=Math.pow(2,-a))>>>0,o,i+t),e((s<<31|a+1023<<20|1048576*r&1048575)>>>0,o,i+n)}}function n(e,t,n,r,o){return t=e(r,o+t),r=e(r,o+n),e=2*(r>>31)+1,t=4294967296*(1048575&r)+t,2047===(n=r>>>20&2047)?t?NaN:1/0*e:0===n?5e-324*e*t:e*Math.pow(2,n-1075)*(t+4503599627370496)}e.writeDoubleLE=t.bind(null,Gn,0,4),e.writeDoubleBE=t.bind(null,Hn,4,0),e.readDoubleLE=n.bind(null,In,0,4),e.readDoubleBE=n.bind(null,Jn,4,0)}(),e}function Gn(e,t,n){t[n]=255&e,t[n+1]=e>>>8&255,t[n+2]=e>>>16&255,t[n+3]=e>>>24}function Hn(e,t,n){t[n]=e>>>24,t[n+1]=e>>>16&255,t[n+2]=e>>>8&255,t[n+3]=255&e}function In(e,t){return(e[t]|e[t+1]<<8|e[t+2]<<16|e[t+3]<<24)>>>0}function Jn(e,t){return(e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3])>>>0}function vb(e,t){this.lo=e>>>0,this.hi=t>>>0}function Wf(e,t,n){this.fn=e,this.len=t,this.next=void 0,this.val=n}function lj(){}function Cv(e){this.head=e.head,this.tail=e.tail,this.len=e.len,this.next=e.states}function Aa(){this.len=0,this.tail=this.head=new Wf(lj,0,0),this.states=null}function mj(e,t,n){t[n]=255&e}function nj(e,t){this.len=e,this.next=void 0,this.val=t}function oj(e,t,n){for(;e.hi;)t[n++]=127&e.lo|128,e.lo=(e.lo>>>7|e.hi<<25)>>>0,e.hi>>>=7;for(;127>>=7;t[n++]=e.lo}function pj(e,t,n){t[n]=255&e,t[n+1]=e>>>8&255,t[n+2]=e>>>16&255,t[n+3]=e>>>24}function Lc(){qj.call(this)}function Dv(e,t,n){40>e.length?pa.utf8.write(e,t,n):t.utf8Write?t.utf8Write(e,n):t.write(e,n)}function wc(e,t){return RangeError("index out of range: "+e.pos+" + "+(t||1)+" > "+e.len)}function ib(e){this.buf=e,this.pos=0,this.len=e.length}function rj(){var e=new Kn(0,0),t=0;if(!(4t;++t){if(this.pos>=this.len)throw wc(this);if(e.lo=(e.lo|(127&this.buf[this.pos])<<7*t)>>>0,128>this.buf[this.pos++])return e}return e.lo=(e.lo|(127&this.buf[this.pos++])<<7*t)>>>0,e}for(;4>t;++t)if(e.lo=(e.lo|(127&this.buf[this.pos])<<7*t)>>>0,128>this.buf[this.pos++])return e;if(e.lo=(e.lo|(127&this.buf[this.pos])<<28)>>>0,e.hi=(e.hi|(127&this.buf[this.pos])>>4)>>>0,128>this.buf[this.pos++])return e;if(t=0,4t;++t)if(e.hi=(e.hi|(127&this.buf[this.pos])<<7*t+3)>>>0,128>this.buf[this.pos++])return e}else for(;5>t;++t){if(this.pos>=this.len)throw wc(this);if(e.hi=(e.hi|(127&this.buf[this.pos])<<7*t+3)>>>0,128>this.buf[this.pos++])return e}throw Error("invalid varint encoding")}function ih(e,t){return(e[t-4]|e[t-3]<<8|e[t-2]<<16|e[t-1]<<24)>>>0}function Ln(){if(this.pos+8>this.len)throw wc(this,8);return new Kn(ih(this.buf,this.pos+=4),ih(this.buf,this.pos+=4))}function be(e){sj.call(this,e)}function Xf(e,t,n){if("function"!=typeof e)throw TypeError("rpcImpl must be a function");pa.EventEmitter.call(this),this.rpcImpl=e,this.requestDelimited=!!t,this.responseDelimited=!!n}function Mn(e){var t=[];return function e(n){if(null===n||"object"!==qa(n))return n;if(-1!==t.indexOf(n))return"[Circular]";if(t.push(n),"function"==typeof n.toJSON)try{var r=e(n.toJSON());return t.pop(),r}catch(e){return"[Throws: "+(e?e.message:"?")+"]"}return Array.isArray(n)?(r=n.map(e),t.pop(),r):(r=Object.keys(n).reduce((function(t,r){e:{if(Ev.call(n,r))try{var o=n[r];break e}catch(e){o="[Throws: "+(e?e.message:"?")+"]";break e}o=n[r]}return t[r]=e(o),t}),{}),t.pop(),r)}(e)}function Fv(e){if(!(100<(e=String(e)).length)&&(e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e))){var t=parseFloat(e[1]);switch((e[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*t;case"weeks":case"week":case"w":return 6048e5*t;case"days":case"day":case"d":return 864e5*t;case"hours":case"hour":case"hrs":case"hr":case"h":return 36e5*t;case"minutes":case"minute":case"mins":case"min":case"m":return 6e4*t;case"seconds":case"second":case"secs":case"sec":case"s":return 1e3*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return t}}}function jh(e,t,n,r){return Math.round(e/n)+" "+r+(t>=1.5*n?"s":"")}function Gv(e){var t=e.areas,n=e.excludedArea;if(1===t.length&&t[0]===S.GLOBAL&&n===S.CHINA)return Ve([S.OVERSEA]);if(t.includes(S.GLOBAL)){if(e=Yf(kh).filter((function(e){return e!==S.GLOBAL&&e!==S.OVERSEA})),n in Zf){t=Zf[n];var r=[].concat(Z(null!=t?t:[]),[n]);return Ve(e.filter((function(e){return!r.includes(e)})))}if(Nn(n)){var o=Hv(n);return Ve(e.filter((function(e){return e!==n&&e!==o})))}}if(Nn(n)||n in Zf)return Ve(t);throw new ca("Invalid excludedArea area config")}function jb(e,t,n){void 0===n&&(n=Object.getOwnPropertyDescriptor(e,t));var r=n.value;return n.value=function(){for(var e=this,n=arguments.length,o=Array(n),i=0;i?@[\]^{|}~-]{1,64}$/.test(e)&&"null"!==e}function Pn(e){try{var t=e.split(".").map((function(e){return Number(e)}))}catch(e){return!1}if(4!==t.length||0===t[0])return!1;for(e=0;en||255r)throw new ic("Exceed the limit of ".concat(r," attributes"),Ye);if(0===Object.keys(t).length)throw new ca("The attributes is an empty object",gb);var i=0,s=0;for(t=Object.entries(t);so)throw new ic("Invalid attribute value, over the limit of ".concat(o," bytes"),Ye);if("string"!=typeof c||0===c.length)throw new ca("Invalid attribute value",gb);i+=a,i+=u}if(i>e)throw new ic("The attributes size overflow",Ye);if(void 0!==n){if(Object.keys(n).length>r)throw new ic("Exceed the limit of ".concat(r," attributes"),Ye);for(i=r=0,n=Object.entries(n);io)throw new ic("Invalid attribute value, over the limit of ".concat(o," bytes"),Ye);r+=t,r+=s}if(r>e)throw new ic("The attributes size overflow",Ye)}}function mh(e,t){return Math.floor(Math.random()*(Math.floor(t)-Math.ceil(e)+1))+e}function nh(){var e=mh(0,4294967295),t=mh(1,4294967295);return new P(e,t,!0)}function sb(e){return e.toString().padEnd(32,"0")}function Rn(e,t){return new TypeError("Unexpected ".concat(e,": ").concat(t))}function Sn(e,t){return e=e.split(".").map((function(e){return Number(e)})),t=t.split(".").map((function(e){return Number(e)})),Math.sqrt(1e3*Math.pow(e[0]-t[0],2)+100*Math.pow(e[1]-t[1],2)+10*Math.pow(e[2]-t[2],2)+1*Math.pow(e[3]-t[3],2))}function Tn(e){return e.lessThanOrEqual(Number.MAX_SAFE_INTEGER)?e.toNumber():e.toString()}function uj(e,t){t="".concat(e).concat(t||"");var n=Un.get(t)||1;return Un.set(t,n+1),"".concat(e).concat(n)}function Vn(e,t){var n="number"==typeof t?t:void 0!==t&&"string"!=typeof t?t.code:void 0;return t="number"!=typeof t&&"string"!=typeof t&&void 0!==t&&void 0!==t.serverCode?t.serverCode:void 0,n="".concat(void 0!==n?" Error Code ".concat(n):"").concat(void 0!==t?", server Code ".concat(t):""),e="string"==typeof e&&e?oh(e):Array.isArray(e)&&"string"==typeof e[0]&&e[0]?oh(Wn.apply(void 0,[e[0]].concat(Z(e.slice(1))))):"","".concat(""===n?"":"".concat(n," - ")).concat(e)}function Kv(e,t){return vj.apply(this,arguments)}function vj(){return(vj=ma(N.mark((function e(t,n){return N.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!n||!n.aborted){e.next=2;break}return e.abrupt("return");case 2:return e.abrupt("return",new Promise((function(e){setTimeout(e,t),null==n||n.addEventListener("abort",e)})));case 3:case"end":return e.stop()}}),e)})))).apply(this,arguments)}function lh(e,t,n){return wj.apply(this,arguments)}function wj(){return(wj=ma(N.mark((function e(t,n,r){var o,i,s,a,c,u,l,f,h,p,d,b,g,v,y,m,E,w,O,_,k,I,A,R,S,T;return N.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(o=n.body,i=n.headers,s=void 0===i?{}:i,a=n.timeout,c=void 0===a?1e4:a,u=n.signal,l=n.withCredentials,f=void 0!==l&&l,h=(r||{}).useBinaryResponse,p=void 0!==h&&h,(d=new XMLHttpRequest).open("POST",t,!0),d.responseType=p?"arraybuffer":"text",d.withCredentials=f,d.timeout=c,b=o instanceof FormData,g=o instanceof Uint8Array,!(1<(v=Object.keys(s).filter((function(e){return"content-type"===e.toLowerCase()}))).length)){e.next=14;break}throw new RangeError("multiple content-type");case 14:0===v.length&&(g?s["Content-Type"]="application/octet-stream":b||(s["Content-Type"]="application/json"));case 15:if("setRequestHeader"in d){e.next=46;break}return d.abort(),e.next=19,fetch(t,{body:b||g?o:JSON.stringify(o),cache:"no-cache",credentials:f?"include":"same-origin",headers:s,method:"POST",mode:"cors",referrer:"no-referrer",signal:u});case 19:if(y=e.sent,!(200<=(m=y.status)&&300>m||304===m)){e.next=31;break}if(!p){e.next=27;break}return e.next=25,y.arrayBuffer();case 25:return E=e.sent,e.abrupt("return",{status:m,responseData:E});case 27:return e.next=29,y.text();case 29:return w=e.sent,e.abrupt("return",{status:m,responseText:w});case 31:return O=new Ja(["Post XHR failure, status %d",m]),e.prev=32,e.next=35,y.text();case 35:throw _=e.sent,O.statusCode=m,O.message=_||"Request failed, status ".concat(m),O;case 41:throw e.prev=41,e.t0=e.catch(32),O.statusCode=m,O.message="Request failed, status ".concat(m),O;case 46:if(0!==Object.keys(s).length)for(k=0,I=Object.entries(s);kn||304===n)e(p?{status:n,responseData:d.response}:{status:n,responseText:d.responseText});else{var r=new Ja(["Post XHR failure, status %d",n]);r.statusCode=n,r.message=d.response||"Request failed, status ".concat(d.status),t(r)}},d.ontimeout=function(e){t(new Ub(["XHR request timed out after %d ms",c],{originalError:e}))},d.onerror=function(){var e=new Ja(["Post XHR failure, status %d",d.status]);e.statusCode=d.status,e.message=d.response||"Request failed, status ".concat(d.status),t(e)},d.onabort=function(){try{t(new DOMException("The request aborted.","AbortError"))}catch(n){var e=Error("The request aborted.");e.name="AbortError",t(e)}}})));case 50:case"end":return e.stop()}}),e,null,[[32,41]])})))).apply(this,arguments)}function Xn(e,t){if(!De(e))throw new ca("message object is not a plain object",t);if(void 0===e.messageType)if(e.rawMessage instanceof Uint8Array){if(e.messageType="RAW",void 0!==e.text)throw new ca("Raw messages cannot have text property. Use description instead",t)}else{if("string"!=typeof e.text)throw new ca("messageType is undefined",t);if(e.messageType="TEXT",void 0!==e.rawMessage)throw new ca("Text messages cannot have rawMessage property",t)}}function ph(e){return xj.apply(this,arguments)}function xj(){return(xj=ma(N.mark((function e(t){var n,r,o,i,s,a,c,u,l,f,h,p,d,b,g,v,y,m,E,w,O;return N.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(n=t.message,r=t.peerId,o=t.toPeer,i=t.session,s=t.errorCodes,a=t.diff,c=t.logger,void 0!==i){e.next=3;break}throw new da("The client is not logged in. Cannot do the operation",s.NOT_LOGGED_IN);case 3:if(u=!1,l=o?"TEXT"===n.messageType?Ka.P2pSMsgNoOfflineFlag:Ka.P2pRMsgNoOfflineFlag:"TEXT"===n.messageType?Ka.ChannelSMsg:Ka.ChannelRMsg,"TEXT"!==n.messageType||!n.text.startsWith("AgoraRTMLegacyEndcallCompatibleMessagePrefix")||!o){e.next=14;break}if(f=n.text.split("_"),h=$a(f,3),p=h[0],d=h[1],void 0!==h[2]&&Ta(d)&&"AgoraRTMLegacyEndcallCompatibleMessagePrefix"===p){e.next=13;break}throw i.emit("messageCount",{messageCategory:l,type:"common",key:"sentcount"}),i.emit("messageCount",{messageCategory:l,type:"common",key:"invalidmessagecount"}),new ca("Message is not valid",bg);case 13:u=!0;case 14:if(b=Date.now(),g=i.messageSentTimes.length-1,!((v=i.messageSentTimes[g])&&v+3e3arguments.length?oo(R[e])||oo(R[e]):R[e]&&R[e][t]||R[e]&&R[e][t]},aw=Math.ceil,bw=Math.floor,yc=function(e){return isNaN(e=+e)?0:(0(e=yc(e))?dw(e+t,0):ew(e,t)},po=function(e){return function(t,n,r){t=Mb(t);var o=Ma(t.length);if(r=Vb(r,o),e&&n!=n){for(;o>r;)if((n=t[r++])!=n)return!0}else for(;o>r;r++)if((e||r in t)&&t[r]===n)return e||r||0;return!e&&-1}},qo=po(!0),Fj=po(!1),ro=function(e,t){e=Mb(e);var n,r=0,o=[];for(n in e)!ka(bf,n)&&ka(e,n)&&o.push(n);for(;t.length>r;)ka(e,n=t[r++])&&(~Fj(o,n)||o.push(n));return o},zh="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),fw=zh.concat("length","prototype"),de={f:Object.getOwnPropertyNames||function(e){return ro(e,fw)}},gg={f:Object.getOwnPropertySymbols},so=Pc("Reflect","ownKeys")||function(e){var t=de.f(Ia(e)),n=gg.f;return n?t.concat(n(e)):t},to=function(e,t){for(var n=so(t),r=qb.f,o=dc.f,i=0;iBd[0]?1:Bd[0]+Bd[1];else df&&(Bd=df.match(/Edge\/(\d+)/),(!Bd||74<=Bd[1])&&(Bd=df.match(/Chrome\/(\d+)/))&&(Jj=Bd[1]));var Cd=Jj&&+Jj,Sc=!!Object.getOwnPropertySymbols&&!la((function(){return!String(Symbol())||!Symbol.sham&&Cd&&41>Cd})),zo=Sc&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,ig=Ad("wks"),jg=R.Symbol,ow=zo?jg:jg&&jg.withoutSetter||af,Fa=function(e){return ka(ig,e)&&(Sc||"string"==typeof ig[e])||(Sc&&ka(jg,e)?ig[e]=jg[e]:ig[e]=ow("Symbol."+e)),ig[e]},pw=Fa("species"),Kj=RegExp.prototype,qw=!la((function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")})),Ao="$0"==="a".replace(/./,"$0"),Bo=Fa("replace"),Co=!!/./[Bo]&&""===/./[Bo]("a","$0"),rw=!la((function(){var e=/(?:)/,t=e.exec;return e.exec=function(){return t.apply(this,arguments)},2!==(e="ab".split(e)).length||"a"!==e[0]||"b"!==e[1]})),Bh=function(e,t,n,r){var o=Fa(e),i=!la((function(){var t={};return t[o]=function(){return 7},7!=""[e](t)})),s=i&&!la((function(){var t=!1,n=/a/;return"split"===e&&((n={constructor:{}}).constructor[pw]=function(){return n},n.flags="",n[o]=/./[o]),n.exec=function(){return t=!0,null},n[o](""),!t}));if(!i||!s||"replace"===e&&(!qw||!Ao||Co)||"split"===e&&!rw){var a=/./[o],c=(n=n(o,""[e],(function(e,t,n,r,o){var s=t.exec;return s===hg||s===Kj.exec?i&&!o?{done:!0,value:a.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),{REPLACE_KEEPS_$0:Ao,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:Co}))[1];Za(String.prototype,e,n[0]),Za(Kj,o,2==t?function(e,t){return c.call(e,this,t)}:function(e){return c.call(e,this)})}r&&kb(Kj[o],"sham",!0)},sw=Fa("match"),Lj=function(e){var t;return xa(e)&&(void 0!==(t=e[sw])?!!t:"RegExp"==xc(e))},Wb=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e},tw=Fa("species"),ee=function(e,t){var n;return void 0===(e=Ia(e).constructor)||null==(n=Ia(e)[tw])?t:Wb(n)},Do=function(e){return function(t,n){t=String(Eb(t)),n=yc(n);var r,o=t.length;if(0>n||n>=o)return e?"":void 0;var i=t.charCodeAt(n);return 55296>i||56319(r=t.charCodeAt(n+1))||57343>>0))return[];if(void 0===e)return[r];if(!Lj(e))return t.call(r,e,n);var o,i,s,a=[],c=0;for(e=new RegExp(e.source,(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":"")+"g");(o=hg.call(e,r))&&!((i=e.lastIndex)>c&&(a.push(r.slice(c,o.index)),1=n));)e.lastIndex===o.index&&e.lastIndex++;return c===r.length?(s||!e.test(""))&&a.push(""):a.push(r.slice(c)),a.length>n?a.slice(0,n):a}:"0".split(void 0,0).length?function(e,n){return void 0===e&&0===n?[]:t.call(this,e,n)}:t;return[function(t,n){var o=Eb(this),i=null==t?void 0:t[e];return void 0!==i?i.call(t,o,n):r.call(String(o),t,n)},function(e,o){var i=n(r,e,this,o,r!==t);if(i.done)return i.value;var s=Ia(e);e=String(this);var a=ee(s,RegExp);if(i=s.unicode,s=new a(Rc?"^(?:"+s.source+")":s,(s.ignoreCase?"i":"")+(s.multiline?"m":"")+(s.unicode?"u":"")+(Rc?"g":"y")),0===(o=void 0===o?4294967295:o>>>0))return[];if(0===e.length)return null===ef(s,e)?[e]:[];var c=0,u=0;for(a=[];u>>0||(zw.test(e)?16:10))}:Ch;ea({global:!0,forced:parseInt!=Fo},{parseInt:Fo});var Dd=function(e,t,n){if(Wb(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,o){return e.call(t,n,r,o)}}return function(){return e.apply(t,arguments)}},Ed=Array.isArray||function(e){return"Array"==xc(e)},Aw=Fa("species"),Dh=function(e,t){if(Ed(e)){var n=e.constructor;"function"!=typeof n||n!==Array&&!Ed(n.prototype)?xa(n)&&(null===(n=n[Aw])&&(n=void 0)):n=void 0}return new(void 0===n?Array:n)(0===t?0:t)},Go=[].push,Fd=function(e){var t=1==e,n=2==e,r=3==e,o=4==e,i=6==e,s=7==e,a=5==e||i;return function(c,u,l,f){var h=pb(c),p=fg(h);u=Dd(u,l,3),l=Ma(p.length);var d,b=0;for(f=f||Dh,c=t?f(c,l):n||s?f(c,0):void 0;l>b;b++)if((a||b in p)&&(d=u(f=p[b],b,h),e))if(t)c[b]=d;else if(d)switch(e){case 3:return!0;case 5:return f;case 6:return b;case 2:Go.call(c,f)}else switch(e){case 4:return!1;case 7:Go.call(c,f)}return i?-1:r||o?o:c}},fe=Fd(0),Ho=Fd(1),Io=Fd(2),Bw=Fd(3),Cw=Fd(4),Jo=Fd(5),Dw=Fd(6);Fd(7);var Ew=Fa("species"),kg=function(e){return 51<=Cd||!la((function(){var t=[];return(t.constructor={})[Ew]=function(){return{foo:1}},1!==t[e](Boolean).foo}))},Fw=kg("filter");ea({target:"Array",proto:!0,forced:!Fw},{filter:function(e){return Io(this,e,1c;c++)a=s?i(n[c],c):n[c],hf(r,c,a)}else for(o=(n=a.call(n)).next,r=new r;!(t=o.call(n)).done;c++){if(s){a=n;var l=i;t=[t.value,c];try{u=l(Ia(t)[0],t[1])}catch(e){throw Pj(a),e}}else u=t.value;hf(r,c,a=u)}return r.length=c,r},Lo=Fa("iterator"),Mo=!1;try{var Rw=0,No={next:function(){return{done:!!Rw++}},return:function(){Mo=!0}};No[Lo]=function(){return this},Array.from(No,(function(){throw 2}))}catch(c){}var Eh=function(e,t){if(!t&&!Mo)return!1;var n=!1;try{(t={})[Lo]=function(){return{next:function(){return{done:n=!0}}}},e(t)}catch(e){}return n},Sw=!Eh((function(e){Array.from(e)}));ea({target:"Array",stat:!0,forced:Sw},{from:ge});var Oo=!la((function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype})),Po=xh("IE_PROTO"),Tw=Object.prototype,uc=Oo?Object.getPrototypeOf:function(e){return e=pb(e),ka(e,Po)?e[Po]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?Tw:null},Sj=Fa("iterator"),Qo=!1,Uw=function(){return this},he;if([].keys){var Ro=[].keys();if("next"in Ro){var So=uc(uc(Ro));So!==Object.prototype&&(he=So)}else Qo=!0}(null==he||la((function(){var e={};return he[Sj].call(e)!==e})))&&(he={}),ka(he,Sj)||kb(he,Sj,Uw);var Fh=he,Gh=Qo,To=wa?Object.defineProperties:function(e,t){Ia(e);for(var n,r=ed(t),o=r.length,i=0;o>i;)qb.f(e,n=r[i++],t[n]);return e},Tj=Pc("document","documentElement"),Uo=xh("IE_PROTO"),Uj=function(){},Vj,Hh=function(){try{Vj=document.domain&&new ActiveXObject("htmlfile")}catch(e){}if(Vj){var e=Vj;e.write("