Start consolidating shared types in the monorepo (#34062)
* Start consolidating shared types in the monorepo * Iterate * Simplify api-extractor * Iterate * Fix lockfile
This commit is contained in:
@@ -217,6 +217,7 @@
|
||||
"postcss-simple-vars": "7.0.1",
|
||||
"process": "^0.11.10",
|
||||
"semver": "^7.5.2",
|
||||
"shared-types": "workspace:*",
|
||||
"source-map-loader": "^5.0.0",
|
||||
"stylelint": "^17.0.0",
|
||||
"stylelint-config-standard": "^40.0.0",
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
type ToMatchScreenshotOptions,
|
||||
} from "@element-hq/element-web-playwright-common";
|
||||
|
||||
import type { IConfigOptions } from "../src/IConfigOptions";
|
||||
import { type Credentials } from "./plugins/homeserver";
|
||||
import { ElementAppPage } from "./pages/ElementAppPage";
|
||||
import { Crypto } from "./pages/crypto";
|
||||
@@ -32,11 +31,6 @@ import { type WorkerOptions, type Services, test as base } from "./services";
|
||||
// See https://playwright.dev/docs/service-workers-experimental#how-to-enable
|
||||
process.env["PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS"] = "1";
|
||||
|
||||
declare module "@element-hq/element-web-playwright-common" {
|
||||
// Improve the type for the config fixture based on the real type
|
||||
export interface Config extends Omit<IConfigOptions, "default_server_config"> {}
|
||||
}
|
||||
|
||||
export interface CredentialsWithDisplayName extends Credentials {
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
@@ -10,55 +10,8 @@ import { type JSX, type JSXElementConstructor } from "react";
|
||||
|
||||
export type { NonEmptyArray, XOR, Writeable } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
export type * from "shared-types/lib/utils";
|
||||
|
||||
export type ComponentClass = keyof JSX.IntrinsicElements | JSXElementConstructor<any>;
|
||||
|
||||
export type { Leaves } from "matrix-web-i18n";
|
||||
|
||||
export type KeysStartingWith<Input extends object, Str extends string> = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
[P in keyof Input]: P extends `${Str}${infer _X}` ? P : never; // we don't use _X
|
||||
}[keyof Input];
|
||||
|
||||
export type Defaultize<P, D> = P extends any
|
||||
? string extends keyof P
|
||||
? P
|
||||
: Pick<P, Exclude<keyof P, keyof D>> &
|
||||
Partial<Pick<P, Extract<keyof P, keyof D>>> &
|
||||
Partial<Pick<D, Exclude<keyof D, keyof P>>>
|
||||
: never;
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
||||
export type DeepReadonly<T> = T extends (infer R)[]
|
||||
? DeepReadonlyArray<R>
|
||||
: T extends Function
|
||||
? T
|
||||
: T extends object
|
||||
? DeepReadonlyObject<T>
|
||||
: T;
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-function-type */
|
||||
|
||||
interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}
|
||||
|
||||
type DeepReadonlyObject<T> = {
|
||||
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
||||
};
|
||||
|
||||
export type AtLeastOne<T, U = { [K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U];
|
||||
|
||||
/**
|
||||
* Returns a union type of the keys of the input Object type whose values are assignable to the given Item type.
|
||||
* Based on https://stackoverflow.com/a/57862073
|
||||
*/
|
||||
export type Assignable<Object, Item> = {
|
||||
[Key in keyof Object]: Object[Key] extends Item ? Key : never;
|
||||
}[keyof Object];
|
||||
|
||||
/**
|
||||
* Like `Partial` but for applied to all nested objects.
|
||||
* Based on https://dev.to/perennialautodidact/adventures-in-typescript-deeppartial-2f2a
|
||||
*/
|
||||
export type DeepPartial<T> = T extends object
|
||||
? {
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
}
|
||||
: T;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
export type JsonValue = null | string | number | boolean;
|
||||
export type JsonArray = Array<JsonValue | JsonObject | JsonArray>;
|
||||
export interface JsonObject {
|
||||
[key: string]: JsonObject | JsonArray | JsonValue;
|
||||
}
|
||||
export type Json = JsonArray | JsonObject;
|
||||
+10
-203
@@ -7,15 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { type IClientWellKnown } from "matrix-js-sdk/src/matrix";
|
||||
import { type ResolveDefaults, type WebConfigJson } from "shared-types";
|
||||
|
||||
import { type ValidatedServerConfig } from "./utils/ValidatedServerConfig";
|
||||
|
||||
// Convention decision: All config options are lower_snake_case
|
||||
// We use an isolated file for the interface so we can mess around with the eslint options.
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
/* eslint @typescript-eslint/naming-convention: ["error", { "selector": "property", "format": ["snake_case"] } ] */
|
||||
import { type DEFAULTS } from "./SdkConfig.ts";
|
||||
|
||||
/**
|
||||
* Bug reports are enabled but must only be locally
|
||||
@@ -23,202 +18,14 @@ import { type ValidatedServerConfig } from "./utils/ValidatedServerConfig";
|
||||
*/
|
||||
export const BugReportEndpointURLLocal = "local";
|
||||
|
||||
// see element-web config.md for non-developer docs
|
||||
export interface IConfigOptions {
|
||||
// dev note: while true that this is arbitrary JSON, it's valuable to enforce that all
|
||||
// config options are documented for "find all usages" sort of searching.
|
||||
// [key: string]: any;
|
||||
|
||||
// Properties of this interface are roughly grouped by their subject matter, such as
|
||||
// "instance customisation", "login stuff", "branding", etc. Use blank lines to denote
|
||||
// a logical separation of properties, but keep similar ones near each other.
|
||||
|
||||
// Exactly one of the following must be supplied
|
||||
default_server_config?: IClientWellKnown; // copy/paste of client well-known
|
||||
default_server_name?: string; // domain to do well-known lookup on
|
||||
default_hs_url?: string; // http url
|
||||
|
||||
default_is_url?: string; // used in combination with default_hs_url, but for the identity server
|
||||
|
||||
// This is intended to be overridden by app startup and not specified by the user
|
||||
// This is also why it's allowed to have an interface that isn't snake_case
|
||||
export interface ConfigOptions extends WebConfigJson {
|
||||
/**
|
||||
* This is not a real config field, we're just abusing the config structure to pass around a validated server config
|
||||
*/
|
||||
validated_server_config?: ValidatedServerConfig;
|
||||
|
||||
fallback_hs_url?: string;
|
||||
|
||||
disable_custom_urls?: boolean;
|
||||
disable_guests?: boolean;
|
||||
disable_login_language_selector?: boolean;
|
||||
disable_3pid_login?: boolean;
|
||||
|
||||
brand: string;
|
||||
branding: {
|
||||
welcome_background_url: string | string[]; // chosen at random if array
|
||||
logo_link_url: string;
|
||||
auth_header_logo_url?: string;
|
||||
auth_footer_links?: { text: string; url: string }[];
|
||||
};
|
||||
|
||||
force_verification?: boolean; // if true, users must verify new logins
|
||||
|
||||
map_style_url?: string; // for location-shared maps
|
||||
|
||||
embedded_pages?: {
|
||||
welcome_url?: string;
|
||||
home_url?: string;
|
||||
login_for_welcome?: boolean;
|
||||
};
|
||||
|
||||
permalink_prefix?: string;
|
||||
|
||||
update_base_url?: string;
|
||||
desktop_builds: {
|
||||
available: boolean;
|
||||
logo: string; // url
|
||||
url: string; // download url
|
||||
url_macos?: string;
|
||||
url_win64?: string;
|
||||
url_win64arm?: string;
|
||||
url_linux?: string;
|
||||
};
|
||||
mobile_builds: {
|
||||
ios: string | null; // download url
|
||||
android: string | null; // download url
|
||||
fdroid: string | null; // download url
|
||||
};
|
||||
|
||||
mobile_guide_toast?: boolean;
|
||||
mobile_guide_app_variant?: "element" | "element-classic" | "element-pro";
|
||||
|
||||
default_theme?: "light" | "dark" | string; // custom themes are strings
|
||||
default_country_code?: string; // ISO 3166 alpha2 country code
|
||||
default_federate?: boolean;
|
||||
default_device_display_name?: string; // for device naming on login+registration
|
||||
|
||||
setting_defaults?: Record<string, any>; // <SettingName, Value>
|
||||
|
||||
integrations_ui_url?: string;
|
||||
integrations_rest_url?: string;
|
||||
integrations_widgets_urls?: string[];
|
||||
default_widget_container_height?: number; // height in pixels
|
||||
|
||||
show_labs_settings: boolean;
|
||||
features?: Record<string, boolean>; // <FeatureName, EnabledBool>
|
||||
|
||||
/**
|
||||
* Bug report endpoint URL. "local" means the logs should not be uploaded.
|
||||
*/
|
||||
bug_report_endpoint_url?: typeof BugReportEndpointURLLocal | string; // omission disables bug reporting
|
||||
sentry?: {
|
||||
dsn: string;
|
||||
environment?: string; // "production", etc
|
||||
};
|
||||
|
||||
widget_build_url?: string; // url called to replace jitsi/call widget creation
|
||||
widget_build_url_ignore_dm?: boolean;
|
||||
audio_stream_url?: string;
|
||||
jitsi?: {
|
||||
preferred_domain: string;
|
||||
};
|
||||
jitsi_widget?: {
|
||||
skip_built_in_welcome_screen?: boolean;
|
||||
};
|
||||
voip?: {
|
||||
obey_asserted_identity?: boolean; // MSC3086
|
||||
};
|
||||
element_call: {
|
||||
guest_spa_url?: string;
|
||||
use_exclusively?: boolean;
|
||||
brand?: string;
|
||||
};
|
||||
|
||||
logout_redirect_url?: string;
|
||||
|
||||
sso_redirect_options?: ISsoRedirectOptions;
|
||||
|
||||
custom_translations_url?: string;
|
||||
|
||||
report_event?: {
|
||||
admin_message_md: string; // message for how to contact the server owner when reporting an event
|
||||
};
|
||||
|
||||
room_directory?: {
|
||||
servers: string[];
|
||||
};
|
||||
|
||||
posthog?: {
|
||||
project_api_key: string;
|
||||
api_host: string; // hostname
|
||||
};
|
||||
analytics_owner?: string; // defaults to `brand`
|
||||
privacy_policy_url?: string; // location for cookie policy
|
||||
|
||||
enable_presence_by_hs_url?: Record<string, boolean>; // <HomeserverName, Enabled>
|
||||
|
||||
terms_and_conditions_links?: { url: string; text: string }[];
|
||||
help_url: string;
|
||||
help_encryption_url: string;
|
||||
help_key_storage_url: string;
|
||||
|
||||
latex_maths_delims?: {
|
||||
inline?: {
|
||||
left?: string;
|
||||
right?: string;
|
||||
pattern?: {
|
||||
tex?: string;
|
||||
latex?: string;
|
||||
};
|
||||
};
|
||||
display?: {
|
||||
left?: string;
|
||||
right?: string;
|
||||
pattern?: {
|
||||
tex?: string;
|
||||
latex?: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sync_timeline_limit?: number;
|
||||
dangerously_allow_unsafe_and_insecure_passwords?: boolean; // developer option
|
||||
|
||||
user_notice?: {
|
||||
title: string;
|
||||
description: string;
|
||||
show_once?: boolean;
|
||||
};
|
||||
|
||||
feedback: {
|
||||
existing_issues_url: string;
|
||||
new_issue_url: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration for OIDC issuers where a static client_id has been issued for the app.
|
||||
* Otherwise dynamic client registration is attempted.
|
||||
* The issuer URL must have a trailing `/`.
|
||||
* OPTIONAL
|
||||
*/
|
||||
oidc_static_clients?: {
|
||||
[issuer: string]: { client_id: string };
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration for OIDC dynamic registration where a static OIDC client is not configured.
|
||||
*/
|
||||
oidc_metadata?: {
|
||||
client_uri?: string;
|
||||
logo_uri?: string;
|
||||
tos_uri?: string;
|
||||
policy_uri?: string;
|
||||
contacts?: string[];
|
||||
};
|
||||
|
||||
modules?: string[];
|
||||
}
|
||||
|
||||
export interface ISsoRedirectOptions {
|
||||
immediate?: boolean;
|
||||
on_welcome_page?: boolean;
|
||||
on_login_page?: boolean;
|
||||
}
|
||||
/**
|
||||
* Type representing the effective config.json structure after DEFAULTS has been merged in
|
||||
*/
|
||||
export type IConfigOptions = ResolveDefaults<ConfigOptions, typeof DEFAULTS>;
|
||||
|
||||
@@ -139,10 +139,10 @@ export class PosthogAnalytics {
|
||||
}
|
||||
|
||||
public constructor(private readonly posthog: PostHog) {
|
||||
const posthogConfig = SdkConfig.getObject("posthog");
|
||||
if (posthogConfig) {
|
||||
this.posthog.init(posthogConfig.get("project_api_key"), {
|
||||
api_host: posthogConfig.get("api_host"),
|
||||
const posthogConfig = SdkConfig.get("posthog");
|
||||
if (posthogConfig?.project_api_key && posthogConfig?.api_host) {
|
||||
this.posthog.init(posthogConfig.project_api_key, {
|
||||
api_host: posthogConfig.api_host,
|
||||
autocapture: false,
|
||||
mask_all_text: true,
|
||||
mask_all_element_attributes: true,
|
||||
|
||||
@@ -8,15 +8,15 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { mergeWith } from "lodash";
|
||||
import { type DeepReadonly } from "shared-types";
|
||||
|
||||
import { SnakedObject } from "./utils/SnakedObject";
|
||||
import { type IConfigOptions } from "./IConfigOptions";
|
||||
import { type IConfigOptions, type ConfigOptions } from "./IConfigOptions";
|
||||
import { isObject, objectClone } from "./utils/objects";
|
||||
import { type DeepPartial, type DeepReadonly, type Defaultize } from "./@types/common";
|
||||
import ElementDesktopLogoSvg from "../res/img/element-desktop-logo.svg";
|
||||
|
||||
// see element-web config.md for docs, or the IConfigOptions interface for dev docs
|
||||
export const DEFAULTS: DeepReadonly<IConfigOptions> = {
|
||||
export const DEFAULTS = {
|
||||
brand: "Element",
|
||||
branding: {
|
||||
logo_link_url: "https://element.io",
|
||||
@@ -69,13 +69,13 @@ export const DEFAULTS: DeepReadonly<IConfigOptions> = {
|
||||
android: "https://play.google.com/store/apps/details?id=im.vector.app",
|
||||
fdroid: "https://f-droid.org/repository/browse/?fdid=im.vector.app",
|
||||
},
|
||||
};
|
||||
} satisfies ConfigOptions;
|
||||
|
||||
export type ConfigOptions = Defaultize<IConfigOptions, typeof DEFAULTS>;
|
||||
export type { ConfigOptions };
|
||||
|
||||
function mergeConfig(
|
||||
config: DeepReadonly<IConfigOptions>,
|
||||
changes: DeepReadonly<DeepPartial<IConfigOptions>>,
|
||||
changes: DeepReadonly<ConfigOptions>,
|
||||
): DeepReadonly<IConfigOptions> {
|
||||
// return { ...config, ...changes };
|
||||
return mergeWith(objectClone(config), changes, (objValue, srcValue) => {
|
||||
@@ -141,7 +141,7 @@ export default class SdkConfig {
|
||||
SdkConfig.setInstance(mergeConfig(DEFAULTS, {})); // safe to cast - defaults will be applied
|
||||
}
|
||||
|
||||
public static add(cfg: DeepPartial<ConfigOptions>): void {
|
||||
public static add(cfg: DeepReadonly<ConfigOptions>): void {
|
||||
SdkConfig.put(mergeConfig(SdkConfig.get(), cfg));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,7 +707,11 @@ export class ElementCall extends Call {
|
||||
*/
|
||||
private static appendAnalyticsParams(params: URLSearchParams, client: MatrixClient): void {
|
||||
const posthogConfig = SdkConfig.get("posthog");
|
||||
if (!posthogConfig || PosthogAnalytics.instance.getAnonymity() === Anonymity.Disabled) {
|
||||
if (
|
||||
!posthogConfig?.project_api_key ||
|
||||
!posthogConfig?.api_host ||
|
||||
PosthogAnalytics.instance.getAnonymity() === Anonymity.Disabled
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -725,7 +729,7 @@ export class ElementCall extends Call {
|
||||
// We gate passing sentry behind analytics consent as EC shares data automatically without user-consent,
|
||||
// unlike EW where data is shared upon an intentional user action (rageshake).
|
||||
const sentryConfig = SdkConfig.get("sentry");
|
||||
if (sentryConfig) {
|
||||
if (sentryConfig?.dsn) {
|
||||
params.append("sentryDsn", sentryConfig.dsn);
|
||||
params.append("sentryEnvironment", sentryConfig.environment ?? "");
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React, { type ReactNode } from "react";
|
||||
import { STABLE_MSC4133_EXTENDED_PROFILES, UNSTABLE_MSC4133_EXTENDED_PROFILES } from "matrix-js-sdk/src/matrix";
|
||||
import { type JsonDocument, type JsonValue } from "shared-types";
|
||||
// Import these directly from shared-components to avoid circular deps
|
||||
import { _t, _td } from "@element-hq/web-shared-components";
|
||||
|
||||
@@ -44,7 +45,6 @@ import FallbackIceServerController from "./controllers/FallbackIceServerControll
|
||||
import { type IRightPanelForRoomStored } from "../stores/right-panel/RightPanelStoreIPanelState.ts";
|
||||
import { type ILayoutSettings } from "../stores/widgets/WidgetLayoutStore.ts";
|
||||
import { type ReleaseAnnouncementData } from "../stores/ReleaseAnnouncementStore.ts";
|
||||
import { type Json, type JsonValue } from "../@types/json.ts";
|
||||
import { type RecentEmojiData } from "../emojipicker/recent.ts";
|
||||
import { type Assignable } from "../@types/common.ts";
|
||||
import { SortingAlgorithm } from "../stores/room-list-v3/skip-list/sorters/index.ts";
|
||||
@@ -121,7 +121,7 @@ export const labGroupNames: Record<LabGroup, TranslationKey> = {
|
||||
[LabGroup.Ui]: _td("labs|group_ui"),
|
||||
};
|
||||
|
||||
export type SettingValueType = Json | JsonValue | Record<string, unknown> | Record<string, unknown>[];
|
||||
export type SettingValueType = JsonDocument | JsonValue | Record<string, unknown> | Record<string, unknown>[];
|
||||
|
||||
export interface IBaseSetting<T extends SettingValueType = SettingValueType> {
|
||||
isFeature?: false | undefined;
|
||||
|
||||
Reference in New Issue
Block a user