forked from mystiq/hydrogen-web
Merge branch 'master' into kegan/syncv3
This commit is contained in:
commit
f193418ed1
68 changed files with 533 additions and 394 deletions
|
@ -1,7 +1,9 @@
|
|||
# Typescript migration
|
||||
|
||||
## Introduce `abstract` & `override`
|
||||
# Typescript style guide
|
||||
|
||||
- find all methods and getters that throw or are empty in base classes and turn into abstract method or if all methods are abstract, into an interface.
|
||||
- change child impls to not call super.method and to add override
|
||||
- don't allow implicit override in ts config
|
||||
## Use `type` rather than `interface` for named parameters and POJO return values.
|
||||
|
||||
`type` and `interface` can be used somewhat interchangebly used, but let's use `type` to describe data and `interface` to describe (polymorphic) behaviour.
|
||||
|
||||
Good examples of data are option objects to have named parameters, and POJO (plain old javascript objects) without any methods, just fields.
|
||||
|
||||
Also see [this playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBACghgJwgO2AeTMAlge2QZygF4oBvAKCiqmTgFsIAuKfYBLZAcwG5LqATCABs4IAPzNkAVzoAjCAl4BfcuVCQoAYQAWWIfwzY8hEvCSpDuAlABkZPlQDGOITgTNW7LstWOR+QjMUYHtqKGcCNilHYDcAChxMK3xmIIsk4wBKewcoFRVyPzgArV19KAgAD2AUfkDEYNDqCM9o2IQEjIJmHT0DLvxsijCw-ClIDsSjAkzeEebjEIYAuE5oEgADABJSKeSAOloGJSgsQh29433nVwQlDbnqfKA)
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
"eslint": "^7.32.0",
|
||||
"fake-indexeddb": "^3.1.2",
|
||||
"finalhandler": "^1.1.1",
|
||||
"impunity": "^1.0.8",
|
||||
"impunity": "^1.0.9",
|
||||
"mdn-polyfills": "^5.20.0",
|
||||
"postcss": "^8.1.1",
|
||||
"postcss-css-variables": "^0.17.0",
|
||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
|||
// we do need to return a disposable from EventEmitter.on, or at least have a method here to easily track a subscription to an EventEmitter
|
||||
|
||||
import {EventEmitter} from "../utils/EventEmitter";
|
||||
import {Disposables} from "../utils/Disposables.js";
|
||||
import {Disposables} from "../utils/Disposables";
|
||||
|
||||
export class ViewModel extends EventEmitter {
|
||||
constructor(options = {}) {
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {ViewModel} from "../ViewModel.js";
|
||||
import {createEnum} from "../../utils/enum.js";
|
||||
import {createEnum} from "../../utils/enum";
|
||||
import {ConnectionStatus} from "../../matrix/net/Reconnector.js";
|
||||
import {SyncStatus} from "../../matrix/Sync.js";
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ import {NullLogItem, NullLogger} from "../../../../logging/NullLogger";
|
|||
import {HomeServer as MockHomeServer} from "../../../../mocks/HomeServer.js";
|
||||
// other imports
|
||||
import {BaseMessageTile} from "./tiles/BaseMessageTile.js";
|
||||
import {MappedList} from "../../../../observable/list/MappedList.js";
|
||||
import {MappedList} from "../../../../observable/list/MappedList";
|
||||
import {ObservableValue} from "../../../../observable/ObservableValue";
|
||||
import {PowerLevels} from "../../../../matrix/room/PowerLevels.js";
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {BaseObservableList} from "../../../../observable/list/BaseObservableList";
|
||||
import {sortedIndex} from "../../../../utils/sortedIndex.js";
|
||||
import {sortedIndex} from "../../../../utils/sortedIndex";
|
||||
|
||||
// maps 1..n entries to 0..1 tile. Entries are what is stored in the timeline, either an event or fragmentboundary
|
||||
// for now, tileCreator should be stable in whether it returns a tile or not.
|
||||
|
@ -253,7 +253,7 @@ export class TilesCollection extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
import {ObservableArray} from "../../../../observable/list/ObservableArray.js";
|
||||
import {ObservableArray} from "../../../../observable/list/ObservableArray";
|
||||
import {UpdateAction} from "./UpdateAction.js";
|
||||
|
||||
export function tests() {
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import {BaseMessageTile} from "./BaseMessageTile.js";
|
||||
import {stringAsBody} from "../MessageBody.js";
|
||||
import {createEnum} from "../../../../../utils/enum.js";
|
||||
import {createEnum} from "../../../../../utils/enum";
|
||||
|
||||
export const BodyFormat = createEnum("Plain", "Html");
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {BaseMessageTile} from "./BaseMessageTile.js";
|
||||
import {formatSize} from "../../../../../utils/formatSize.js";
|
||||
import {formatSize} from "../../../../../utils/formatSize";
|
||||
import {SendStatus} from "../../../../../matrix/room/sending/PendingEvent.js";
|
||||
|
||||
export class FileTile extends BaseMessageTile {
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import {ViewModel} from "../../ViewModel.js";
|
||||
import {KeyType} from "../../../matrix/ssss/index.js";
|
||||
import {createEnum} from "../../../utils/enum.js";
|
||||
import {createEnum} from "../../../utils/enum";
|
||||
|
||||
export const Status = createEnum("Enabled", "SetupKey", "SetupPhrase", "Pending");
|
||||
|
||||
|
|
|
@ -17,15 +17,17 @@ limitations under the License.
|
|||
|
||||
import {LogItem} from "./LogItem";
|
||||
import {LogLevel, LogFilter} from "./LogFilter";
|
||||
import type {ILogger, ILogExport, FilterCreator, LabelOrValues, LogCallback, ILogItem} from "./types";
|
||||
import type {ILogger, ILogExport, FilterCreator, LabelOrValues, LogCallback, ILogItem, ISerializedItem} from "./types";
|
||||
import type {Platform} from "../platform/web/Platform.js";
|
||||
|
||||
export abstract class BaseLogger implements ILogger {
|
||||
protected _openItems: Set<LogItem> = new Set();
|
||||
protected _platform: Platform;
|
||||
protected _serializedTransformer: (item: ISerializedItem) => ISerializedItem;
|
||||
|
||||
constructor({platform}) {
|
||||
constructor({platform, serializedTransformer = (item: ISerializedItem) => item}) {
|
||||
this._platform = platform;
|
||||
this._serializedTransformer = serializedTransformer;
|
||||
}
|
||||
|
||||
log(labelOrValues: LabelOrValues, logLevel: LogLevel = LogLevel.Info): void {
|
||||
|
|
|
@ -26,7 +26,7 @@ import {BaseLogger} from "./BaseLogger";
|
|||
import type {Interval} from "../platform/web/dom/Clock";
|
||||
import type {Platform} from "../platform/web/Platform.js";
|
||||
import type {BlobHandle} from "../platform/web/dom/BlobHandle.js";
|
||||
import type {ILogItem, ILogExport} from "./types";
|
||||
import type {ILogItem, ILogExport, ISerializedItem} from "./types";
|
||||
import type {LogFilter} from "./LogFilter";
|
||||
|
||||
type QueuedItem = {
|
||||
|
@ -40,7 +40,7 @@ export class IDBLogger extends BaseLogger {
|
|||
private readonly _flushInterval: Interval;
|
||||
private _queuedItems: QueuedItem[];
|
||||
|
||||
constructor(options: {name: string, flushInterval?: number, limit?: number, platform: Platform}) {
|
||||
constructor(options: {name: string, flushInterval?: number, limit?: number, platform: Platform, serializedTransformer?: (item: ISerializedItem) => ISerializedItem}) {
|
||||
super(options);
|
||||
const {name, flushInterval = 60 * 1000, limit = 3000} = options;
|
||||
this._name = name;
|
||||
|
@ -119,9 +119,12 @@ export class IDBLogger extends BaseLogger {
|
|||
|
||||
_persistItem(logItem: ILogItem, filter: LogFilter, forced: boolean): void {
|
||||
const serializedItem = logItem.serialize(filter, undefined, forced);
|
||||
this._queuedItems.push({
|
||||
json: JSON.stringify(serializedItem)
|
||||
});
|
||||
if (serializedItem) {
|
||||
const transformedSerializedItem = this._serializedTransformer(serializedItem);
|
||||
this._queuedItems.push({
|
||||
json: JSON.stringify(transformedSerializedItem)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_persistQueuedItems(items: QueuedItem[]): void {
|
||||
|
|
|
@ -19,7 +19,7 @@ import {Room} from "./room/Room.js";
|
|||
import {ArchivedRoom} from "./room/ArchivedRoom.js";
|
||||
import {RoomStatus} from "./room/RoomStatus.js";
|
||||
import {Invite} from "./room/Invite.js";
|
||||
import {Pusher} from "./push/Pusher.js";
|
||||
import {Pusher} from "./push/Pusher";
|
||||
import { ObservableMap } from "../observable/index.js";
|
||||
import {User} from "./User.js";
|
||||
import {DeviceMessageHandler} from "./DeviceMessageHandler.js";
|
||||
|
@ -34,7 +34,7 @@ import {Encryption as MegOlmEncryption} from "./e2ee/megolm/Encryption.js";
|
|||
import {MEGOLM_ALGORITHM} from "./e2ee/common.js";
|
||||
import {RoomEncryption} from "./e2ee/RoomEncryption.js";
|
||||
import {DeviceTracker} from "./e2ee/DeviceTracker.js";
|
||||
import {LockMap} from "../utils/LockMap.js";
|
||||
import {LockMap} from "../utils/LockMap";
|
||||
import {groupBy} from "../utils/groupBy";
|
||||
import {
|
||||
keyFromCredential as ssssKeyFromCredential,
|
||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {createEnum} from "../utils/enum.js";
|
||||
import {createEnum} from "../utils/enum";
|
||||
import {lookupHomeserver} from "./well-known.js";
|
||||
import {AbortableOperation} from "../utils/AbortableOperation";
|
||||
import {ObservableValue} from "../observable/ObservableValue";
|
||||
|
@ -27,9 +27,9 @@ import {RequestScheduler} from "./net/RequestScheduler.js";
|
|||
// import {Sync, SyncStatus} from "./Sync.js";
|
||||
import {Sync3, SyncStatus} from "./Sync3";
|
||||
import {Session} from "./Session.js";
|
||||
import {PasswordLoginMethod} from "./login/PasswordLoginMethod.js";
|
||||
import {TokenLoginMethod} from "./login/TokenLoginMethod.js";
|
||||
import {SSOLoginHelper} from "./login/SSOLoginHelper.js";
|
||||
import {PasswordLoginMethod} from "./login/PasswordLoginMethod";
|
||||
import {TokenLoginMethod} from "./login/TokenLoginMethod";
|
||||
import {SSOLoginHelper} from "./login/SSOLoginHelper";
|
||||
import {getDehydratedDevice} from "./e2ee/Dehydration.js";
|
||||
|
||||
export const LoadStatus = createEnum(
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {ObservableValue} from "../observable/ObservableValue";
|
||||
import {createEnum} from "../utils/enum.js";
|
||||
import {createEnum} from "../utils/enum";
|
||||
|
||||
const INCREMENTAL_TIMEOUT = 30000;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import {MEGOLM_ALGORITHM, DecryptionSource} from "./common.js";
|
||||
import {groupEventsBySession} from "./megolm/decryption/utils";
|
||||
import {mergeMap} from "../../utils/mergeMap.js";
|
||||
import {mergeMap} from "../../utils/mergeMap";
|
||||
import {groupBy} from "../../utils/groupBy";
|
||||
import {makeTxnId} from "../common.js";
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import anotherjson from "../../../lib/another-json/index.js";
|
||||
import {createEnum} from "../../utils/enum.js";
|
||||
import {createEnum} from "../../utils/enum";
|
||||
|
||||
export const DecryptionSource = createEnum("Sync", "Timeline", "Retry");
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {DecryptionChanges} from "./DecryptionChanges.js";
|
||||
import {mergeMap} from "../../../../utils/mergeMap.js";
|
||||
import {mergeMap} from "../../../../utils/mergeMap";
|
||||
|
||||
/**
|
||||
* Class that contains all the state loaded from storage to decrypt the given events
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import {DecryptionError} from "../common.js";
|
||||
import {groupBy} from "../../../utils/groupBy";
|
||||
import {MultiLock} from "../../../utils/Lock.js";
|
||||
import {MultiLock} from "../../../utils/Lock";
|
||||
import {Session} from "./Session.js";
|
||||
import {DecryptionResult} from "../DecryptionResult.js";
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ export class HomeServerError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
export {AbortError} from "../utils/error.js";
|
||||
export {AbortError} from "../utils/error";
|
||||
|
||||
export class ConnectionError extends Error {
|
||||
constructor(message, isTimeout) {
|
||||
|
|
|
@ -14,17 +14,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
export class LoginMethod {
|
||||
constructor({homeserver}) {
|
||||
this.homeserver = homeserver;
|
||||
}
|
||||
import type {ILogItem} from "../../logging/types";
|
||||
import type {HomeServerApi} from "../net/HomeServerApi.js";
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async login(hsApi, deviceName, log) {
|
||||
/*
|
||||
Regardless of the login method, SessionContainer.startWithLogin()
|
||||
can do SomeLoginMethod.login()
|
||||
*/
|
||||
throw("Not Implemented");
|
||||
}
|
||||
export interface ILoginMethod {
|
||||
homeserver: string;
|
||||
login(hsApi: HomeServerApi, deviceName: string, log: ILogItem): Promise<Record<string, any>>;
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {LoginMethod} from "./LoginMethod.js";
|
||||
|
||||
export class PasswordLoginMethod extends LoginMethod {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this.username = options.username;
|
||||
this.password = options.password;
|
||||
}
|
||||
|
||||
async login(hsApi, deviceName, log) {
|
||||
return await hsApi.passwordLogin(this.username, this.password, deviceName, {log}).response();
|
||||
}
|
||||
}
|
35
src/matrix/login/PasswordLoginMethod.ts
Normal file
35
src/matrix/login/PasswordLoginMethod.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {ILogItem} from "../../logging/types";
|
||||
import {ILoginMethod} from "./LoginMethod";
|
||||
import {HomeServerApi} from "../net/HomeServerApi.js";
|
||||
|
||||
export class PasswordLoginMethod implements ILoginMethod {
|
||||
private readonly _username: string;
|
||||
private readonly _password: string;
|
||||
public readonly homeserver: string;
|
||||
|
||||
constructor({username, password, homeserver}: {username: string, password: string, homeserver: string}) {
|
||||
this._username = username;
|
||||
this._password = password;
|
||||
this.homeserver = homeserver;
|
||||
}
|
||||
|
||||
async login(hsApi: HomeServerApi, deviceName: string, log: ILogItem): Promise<Record<string, any>> {
|
||||
return await hsApi.passwordLogin(this._username, this._password, deviceName, {log}).response();
|
||||
}
|
||||
}
|
|
@ -15,13 +15,15 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
export class SSOLoginHelper{
|
||||
constructor(homeserver) {
|
||||
private _homeserver: string;
|
||||
|
||||
constructor(homeserver: string) {
|
||||
this._homeserver = homeserver;
|
||||
}
|
||||
|
||||
get homeserver() { return this._homeserver; }
|
||||
get homeserver(): string { return this._homeserver; }
|
||||
|
||||
createSSORedirectURL(returnURL) {
|
||||
createSSORedirectURL(returnURL: string): string {
|
||||
return `${this._homeserver}/_matrix/client/r0/login/sso/redirect?redirectUrl=${returnURL}`;
|
||||
}
|
||||
}
|
|
@ -14,16 +14,21 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {LoginMethod} from "./LoginMethod.js";
|
||||
import {makeTxnId} from "../common.js";
|
||||
import {ILogItem} from "../../logging/types";
|
||||
import {ILoginMethod} from "./LoginMethod";
|
||||
import {HomeServerApi} from "../net/HomeServerApi.js";
|
||||
|
||||
export class TokenLoginMethod extends LoginMethod {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this._loginToken = options.loginToken;
|
||||
export class TokenLoginMethod implements ILoginMethod {
|
||||
private readonly _loginToken: string;
|
||||
public readonly homeserver: string;
|
||||
|
||||
constructor({ homeserver, loginToken }: { homeserver: string, loginToken: string}) {
|
||||
this.homeserver = homeserver;
|
||||
this._loginToken = loginToken;
|
||||
}
|
||||
|
||||
async login(hsApi, deviceName, log) {
|
||||
async login(hsApi: HomeServerApi, deviceName: string, log: ILogItem): Promise<Record<string, any>> {
|
||||
return await hsApi.tokenLogin(this._loginToken, makeTxnId(), deviceName, {log}).response();
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {AbortError} from "../../utils/error.js";
|
||||
import {AbortError} from "../../utils/error";
|
||||
|
||||
export class ExponentialRetryDelay {
|
||||
constructor(createTimeout) {
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {createEnum} from "../../utils/enum.js";
|
||||
import {createEnum} from "../../utils/enum";
|
||||
import {ObservableValue} from "../../observable/ObservableValue";
|
||||
|
||||
export const ConnectionStatus = createEnum(
|
||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {AbortError} from "../../utils/error.js";
|
||||
import {AbortError} from "../../utils/error";
|
||||
import {HomeServerError} from "../error.js";
|
||||
import {HomeServerApi} from "./HomeServerApi.js";
|
||||
import {ExponentialRetryDelay} from "./ExponentialRetryDelay.js";
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
export class Pusher {
|
||||
constructor(description) {
|
||||
this._description = description;
|
||||
}
|
||||
|
||||
static httpPusher(host, appId, pushkey, data) {
|
||||
return new Pusher({
|
||||
kind: "http",
|
||||
append: true, // as pushkeys are shared between multiple users on one origin
|
||||
data: Object.assign({}, data, {url: host + "/_matrix/push/v1/notify"}),
|
||||
pushkey,
|
||||
app_id: appId,
|
||||
app_display_name: "Hydrogen",
|
||||
device_display_name: "Hydrogen",
|
||||
lang: "en"
|
||||
});
|
||||
}
|
||||
|
||||
static createDefaultPayload(sessionId) {
|
||||
return {session_id: sessionId};
|
||||
}
|
||||
|
||||
async enable(hsApi, log) {
|
||||
try {
|
||||
log.set("endpoint", new URL(this._description.data.endpoint).host);
|
||||
} catch {
|
||||
log.set("endpoint", null);
|
||||
}
|
||||
await hsApi.setPusher(this._description, {log}).response();
|
||||
}
|
||||
|
||||
async disable(hsApi, log) {
|
||||
const deleteDescription = Object.assign({}, this._description, {kind: null});
|
||||
await hsApi.setPusher(deleteDescription, {log}).response();
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return this._description;
|
||||
}
|
||||
|
||||
equals(pusher) {
|
||||
if (this._description.app_id !== pusher._description.app_id) {
|
||||
return false;
|
||||
}
|
||||
if (this._description.pushkey !== pusher._description.pushkey) {
|
||||
return false;
|
||||
}
|
||||
return JSON.stringify(this._description.data) === JSON.stringify(pusher._description.data);
|
||||
}
|
||||
}
|
90
src/matrix/push/Pusher.ts
Normal file
90
src/matrix/push/Pusher.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import type {HomeServerApi} from "../net/HomeServerApi.js";
|
||||
import type {ILogItem} from "../../logging/types";
|
||||
|
||||
export interface IPusherDescription {
|
||||
kind: "http" | "email" | "null";
|
||||
lang: string;
|
||||
device_display_name: string;
|
||||
app_display_name: string;
|
||||
app_id: string;
|
||||
pushkey: string;
|
||||
data: IPusherData;
|
||||
append?: boolean;
|
||||
profile_tag?: string;
|
||||
}
|
||||
|
||||
interface IPusherData {
|
||||
format?: string;
|
||||
url?: string;
|
||||
endpoint?: PushSubscriptionJSON["endpoint"];
|
||||
keys?: PushSubscriptionJSON["keys"];
|
||||
}
|
||||
|
||||
export class Pusher {
|
||||
private readonly _description: IPusherDescription;
|
||||
|
||||
constructor(description: IPusherDescription) {
|
||||
this._description = description;
|
||||
}
|
||||
|
||||
static httpPusher(host: string, appId: string, pushkey: string, data: IPusherData): Pusher {
|
||||
return new Pusher({
|
||||
kind: "http",
|
||||
append: true, // as pushkeys are shared between multiple users on one origin
|
||||
data: Object.assign({}, data, {url: host + "/_matrix/push/v1/notify"}),
|
||||
pushkey,
|
||||
app_id: appId,
|
||||
app_display_name: "Hydrogen",
|
||||
device_display_name: "Hydrogen",
|
||||
lang: "en"
|
||||
});
|
||||
}
|
||||
|
||||
static createDefaultPayload(sessionId: string): {session_id: string} {
|
||||
return {session_id: sessionId};
|
||||
}
|
||||
|
||||
async enable(hsApi: HomeServerApi, log: ILogItem): Promise<void> {
|
||||
try {
|
||||
log.set("endpoint", new URL(this._description.data.endpoint!).host);
|
||||
} catch {
|
||||
log.set("endpoint", null);
|
||||
}
|
||||
await hsApi.setPusher(this._description, {log}).response();
|
||||
}
|
||||
|
||||
async disable(hsApi: HomeServerApi, log: ILogItem): Promise<void> {
|
||||
const deleteDescription = Object.assign({}, this._description, {kind: null});
|
||||
await hsApi.setPusher(deleteDescription, {log}).response();
|
||||
}
|
||||
|
||||
serialize(): IPusherDescription {
|
||||
return this._description;
|
||||
}
|
||||
|
||||
equals(pusher): boolean {
|
||||
if (this._description.app_id !== pusher._description.app_id) {
|
||||
return false;
|
||||
}
|
||||
if (this._description.pushkey !== pusher._description.pushkey) {
|
||||
return false;
|
||||
}
|
||||
return JSON.stringify(this._description.data) === JSON.stringify(pusher._description.data);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {ObservableMap} from "../../../observable/map/ObservableMap.js";
|
||||
import {RetainedValue} from "../../../utils/RetainedValue.js";
|
||||
import {RetainedValue} from "../../../utils/RetainedValue";
|
||||
|
||||
export class MemberList extends RetainedValue {
|
||||
constructor({members, closeCallback}) {
|
||||
|
|
|
@ -13,8 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import {createEnum} from "../../../utils/enum.js";
|
||||
import {AbortError} from "../../../utils/error.js";
|
||||
import {createEnum} from "../../../utils/enum";
|
||||
import {AbortError} from "../../../utils/error";
|
||||
import {REDACTION_TYPE} from "../common.js";
|
||||
import {getRelationFromContent, getRelationTarget, setRelationTarget} from "../timeline/relations.js";
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {SortedArray} from "../../../observable/list/SortedArray.js";
|
||||
import {SortedArray} from "../../../observable/list/SortedArray";
|
||||
import {ConnectionError} from "../../error.js";
|
||||
import {PendingEvent, SendStatus} from "./PendingEvent.js";
|
||||
import {makeTxnId, isTxnId} from "../../common.js";
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {SortedArray, AsyncMappedList, ConcatList, ObservableArray} from "../../../observable/index.js";
|
||||
import {Disposables} from "../../../utils/Disposables.js";
|
||||
import {Disposables} from "../../../utils/Disposables";
|
||||
import {Direction} from "./Direction";
|
||||
import {TimelineReader} from "./persistence/TimelineReader.js";
|
||||
import {PendingEventEntry} from "./entries/PendingEventEntry.js";
|
||||
|
|
|
@ -14,12 +14,33 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
export class SessionInfoStorage {
|
||||
constructor(name) {
|
||||
interface ISessionInfo {
|
||||
id: string;
|
||||
deviceId: string;
|
||||
userId: string;
|
||||
homeserver: string;
|
||||
homeServer: string; // deprecate this over time
|
||||
accessToken: string;
|
||||
lastUsed: number;
|
||||
}
|
||||
|
||||
// todo: this should probably be in platform/types?
|
||||
interface ISessionInfoStorage {
|
||||
getAll(): Promise<ISessionInfo[]>;
|
||||
updateLastUsed(id: string, timestamp: number): Promise<void>;
|
||||
get(id: string): Promise<ISessionInfo | undefined>;
|
||||
add(sessionInfo: ISessionInfo): Promise<void>;
|
||||
delete(sessionId: string): Promise<void>;
|
||||
}
|
||||
|
||||
export class SessionInfoStorage implements ISessionInfoStorage {
|
||||
private readonly _name: string;
|
||||
|
||||
constructor(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
getAll() {
|
||||
getAll(): Promise<ISessionInfo[]> {
|
||||
const sessionsJson = localStorage.getItem(this._name);
|
||||
if (sessionsJson) {
|
||||
const sessions = JSON.parse(sessionsJson);
|
||||
|
@ -30,7 +51,7 @@ export class SessionInfoStorage {
|
|||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
async updateLastUsed(id, timestamp) {
|
||||
async updateLastUsed(id: string, timestamp: number): Promise<void> {
|
||||
const sessions = await this.getAll();
|
||||
if (sessions) {
|
||||
const session = sessions.find(session => session.id === id);
|
||||
|
@ -41,20 +62,20 @@ export class SessionInfoStorage {
|
|||
}
|
||||
}
|
||||
|
||||
async get(id) {
|
||||
async get(id: string): Promise<ISessionInfo | undefined> {
|
||||
const sessions = await this.getAll();
|
||||
if (sessions) {
|
||||
return sessions.find(session => session.id === id);
|
||||
}
|
||||
}
|
||||
|
||||
async add(sessionInfo) {
|
||||
async add(sessionInfo: ISessionInfo): Promise<void> {
|
||||
const sessions = await this.getAll();
|
||||
sessions.push(sessionInfo);
|
||||
localStorage.setItem(this._name, JSON.stringify(sessions));
|
||||
}
|
||||
|
||||
async delete(sessionId) {
|
||||
async delete(sessionId: string): Promise<void> {
|
||||
let sessions = await this.getAll();
|
||||
sessions = sessions.filter(s => s.id !== sessionId);
|
||||
localStorage.setItem(this._name, JSON.stringify(sessions));
|
|
@ -18,7 +18,7 @@ import {KeyDescription, Key} from "./common.js";
|
|||
import {keyFromPassphrase} from "./passphrase.js";
|
||||
import {keyFromRecoveryKey} from "./recoveryKey.js";
|
||||
import {SESSION_E2EE_KEY_PREFIX} from "../e2ee/common.js";
|
||||
import {createEnum} from "../../utils/enum.js";
|
||||
import {createEnum} from "../../utils/enum";
|
||||
|
||||
const SSSS_KEY = `${SESSION_E2EE_KEY_PREFIX}ssssKey`;
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
|
||||
import { IDBRequestError } from "./error";
|
||||
import { StorageError } from "../common";
|
||||
import { AbortError } from "../../../utils/error.js";
|
||||
import { AbortError } from "../../../utils/error";
|
||||
|
||||
let needsSyncPromise = false;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {AbortError} from "../utils/error.js";
|
||||
import {AbortError} from "../utils/error";
|
||||
|
||||
export class BaseRequest {
|
||||
constructor() {
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {AbortError} from "../utils/error.js";
|
||||
import {AbortError} from "../utils/error";
|
||||
import {BaseObservable} from "./BaseObservable";
|
||||
|
||||
// like an EventEmitter, but doesn't have an event type
|
||||
|
|
|
@ -20,11 +20,11 @@ import {MappedMap} from "./map/MappedMap.js";
|
|||
import {JoinedMap} from "./map/JoinedMap.js";
|
||||
import {BaseObservableMap} from "./map/BaseObservableMap.js";
|
||||
// re-export "root" (of chain) collections
|
||||
export { ObservableArray } from "./list/ObservableArray.js";
|
||||
export { SortedArray } from "./list/SortedArray.js";
|
||||
export { MappedList } from "./list/MappedList.js";
|
||||
export { AsyncMappedList } from "./list/AsyncMappedList.js";
|
||||
export { ConcatList } from "./list/ConcatList.js";
|
||||
export { ObservableArray } from "./list/ObservableArray";
|
||||
export { SortedArray } from "./list/SortedArray";
|
||||
export { MappedList } from "./list/MappedList";
|
||||
export { AsyncMappedList } from "./list/AsyncMappedList";
|
||||
export { ConcatList } from "./list/ConcatList";
|
||||
export { ObservableMap } from "./map/ObservableMap.js";
|
||||
|
||||
// avoid circular dependency between these classes
|
||||
|
|
|
@ -15,15 +15,14 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {BaseMappedList, runAdd, runUpdate, runRemove, runMove, runReset} from "./BaseMappedList";
|
||||
import {IListObserver} from "./BaseObservableList";
|
||||
import {BaseMappedList, Mapper, Updater, runAdd, runUpdate, runRemove, runMove, runReset} from "./BaseMappedList";
|
||||
|
||||
export class AsyncMappedList extends BaseMappedList {
|
||||
constructor(sourceList, mapper, updater, removeCallback) {
|
||||
super(sourceList, mapper, updater, removeCallback);
|
||||
this._eventQueue = null;
|
||||
}
|
||||
export class AsyncMappedList<F,T> extends BaseMappedList<F,T,Promise<T>> implements IListObserver<F> {
|
||||
private _eventQueue: AsyncEvent<F>[] | null = null;
|
||||
private _flushing: boolean = false;
|
||||
|
||||
onSubscribeFirst() {
|
||||
onSubscribeFirst(): void {
|
||||
this._sourceUnsubscribe = this._sourceList.subscribe(this);
|
||||
this._eventQueue = [];
|
||||
this._mappedValues = [];
|
||||
|
@ -35,122 +34,112 @@ export class AsyncMappedList extends BaseMappedList {
|
|||
this._flush();
|
||||
}
|
||||
|
||||
async _flush() {
|
||||
async _flush(): Promise<void> {
|
||||
if (this._flushing) {
|
||||
return;
|
||||
}
|
||||
this._flushing = true;
|
||||
try {
|
||||
while (this._eventQueue.length) {
|
||||
const event = this._eventQueue.shift();
|
||||
await event.run(this);
|
||||
while (this._eventQueue!.length) {
|
||||
const event = this._eventQueue!.shift();
|
||||
await event!.run(this);
|
||||
}
|
||||
} finally {
|
||||
this._flushing = false;
|
||||
}
|
||||
}
|
||||
|
||||
onReset() {
|
||||
onReset(): void {
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue.push(new ResetEvent());
|
||||
this._flush();
|
||||
}
|
||||
}
|
||||
|
||||
onAdd(index, value) {
|
||||
onAdd(index: number, value: F): void {
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue.push(new AddEvent(index, value));
|
||||
this._flush();
|
||||
}
|
||||
}
|
||||
|
||||
onUpdate(index, value, params) {
|
||||
onUpdate(index: number, value: F, params: any): void {
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue.push(new UpdateEvent(index, value, params));
|
||||
this._flush();
|
||||
}
|
||||
}
|
||||
|
||||
onRemove(index) {
|
||||
onRemove(index: number): void {
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue.push(new RemoveEvent(index));
|
||||
this._flush();
|
||||
}
|
||||
}
|
||||
|
||||
onMove(fromIdx, toIdx) {
|
||||
onMove(fromIdx: number, toIdx: number): void {
|
||||
if (this._eventQueue) {
|
||||
this._eventQueue.push(new MoveEvent(fromIdx, toIdx));
|
||||
this._flush();
|
||||
}
|
||||
}
|
||||
|
||||
onUnsubscribeLast() {
|
||||
this._sourceUnsubscribe();
|
||||
onUnsubscribeLast(): void {
|
||||
this._sourceUnsubscribe!();
|
||||
this._eventQueue = null;
|
||||
this._mappedValues = null;
|
||||
}
|
||||
}
|
||||
|
||||
class AddEvent {
|
||||
constructor(index, value) {
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
}
|
||||
type AsyncEvent<F> = AddEvent<F> | UpdateEvent<F> | RemoveEvent<F> | MoveEvent<F> | ResetEvent<F>
|
||||
|
||||
async run(list) {
|
||||
class AddEvent<F> {
|
||||
constructor(public index: number, public value: F) {}
|
||||
|
||||
async run<T>(list: AsyncMappedList<F,T>): Promise<void> {
|
||||
const mappedValue = await list._mapper(this.value);
|
||||
runAdd(list, this.index, mappedValue);
|
||||
}
|
||||
}
|
||||
|
||||
class UpdateEvent {
|
||||
constructor(index, value, params) {
|
||||
this.index = index;
|
||||
this.value = value;
|
||||
this.params = params;
|
||||
}
|
||||
class UpdateEvent<F> {
|
||||
constructor(public index: number, public value: F, public params: any) {}
|
||||
|
||||
async run(list) {
|
||||
async run<T>(list: AsyncMappedList<F,T>): Promise<void> {
|
||||
runUpdate(list, this.index, this.value, this.params);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveEvent {
|
||||
constructor(index) {
|
||||
this.index = index;
|
||||
}
|
||||
class RemoveEvent<F> {
|
||||
constructor(public index: number) {}
|
||||
|
||||
async run(list) {
|
||||
async run<T>(list: AsyncMappedList<F,T>): Promise<void> {
|
||||
runRemove(list, this.index);
|
||||
}
|
||||
}
|
||||
|
||||
class MoveEvent {
|
||||
constructor(fromIdx, toIdx) {
|
||||
this.fromIdx = fromIdx;
|
||||
this.toIdx = toIdx;
|
||||
}
|
||||
class MoveEvent<F> {
|
||||
constructor(public fromIdx: number, public toIdx: number) {}
|
||||
|
||||
async run(list) {
|
||||
async run<T>(list: AsyncMappedList<F,T>): Promise<void> {
|
||||
runMove(list, this.fromIdx, this.toIdx);
|
||||
}
|
||||
}
|
||||
|
||||
class ResetEvent {
|
||||
async run(list) {
|
||||
class ResetEvent<F> {
|
||||
async run<T>(list: AsyncMappedList<F,T>): Promise<void> {
|
||||
runReset(list);
|
||||
}
|
||||
}
|
||||
|
||||
import {ObservableArray} from "./ObservableArray.js";
|
||||
import {ObservableArray} from "./ObservableArray";
|
||||
import {ListObserver} from "../../mocks/ListObserver.js";
|
||||
|
||||
export function tests() {
|
||||
return {
|
||||
"events are emitted in order": async assert => {
|
||||
const double = n => n * n;
|
||||
const source = new ObservableArray();
|
||||
const source = new ObservableArray<number>();
|
||||
const mapper = new AsyncMappedList(source, async n => {
|
||||
await new Promise(r => setTimeout(r, n));
|
||||
return {n: double(n)};
|
|
@ -21,15 +21,15 @@ import {findAndUpdateInArray} from "./common";
|
|||
export type Mapper<F,T> = (value: F) => T
|
||||
export type Updater<F,T> = (mappedValue: T, params: any, value: F) => void;
|
||||
|
||||
export class BaseMappedList<F,T> extends BaseObservableList<T> {
|
||||
export class BaseMappedList<F,T,R = T> extends BaseObservableList<T> {
|
||||
protected _sourceList: BaseObservableList<F>;
|
||||
protected _sourceUnsubscribe: (() => void) | null = null;
|
||||
_mapper: Mapper<F,T>;
|
||||
_updater: Updater<F,T>;
|
||||
_mapper: Mapper<F,R>;
|
||||
_updater?: Updater<F,T>;
|
||||
_removeCallback?: (value: T) => void;
|
||||
_mappedValues: T[] | null = null;
|
||||
|
||||
constructor(sourceList: BaseObservableList<F>, mapper: Mapper<F,T>, updater: Updater<F,T>, removeCallback?: (value: T) => void) {
|
||||
constructor(sourceList: BaseObservableList<F>, mapper: Mapper<F,R>, updater?: Updater<F,T>, removeCallback?: (value: T) => void) {
|
||||
super();
|
||||
this._sourceList = sourceList;
|
||||
this._mapper = mapper;
|
||||
|
@ -50,12 +50,12 @@ export class BaseMappedList<F,T> extends BaseObservableList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
export function runAdd<F,T>(list: BaseMappedList<F,T>, index: number, mappedValue: T): void {
|
||||
export function runAdd<F,T,R>(list: BaseMappedList<F,T,R>, index: number, mappedValue: T): void {
|
||||
list._mappedValues!.splice(index, 0, mappedValue);
|
||||
list.emitAdd(index, mappedValue);
|
||||
}
|
||||
|
||||
export function runUpdate<F,T>(list: BaseMappedList<F,T>, index: number, value: F, params: any): void {
|
||||
export function runUpdate<F,T,R>(list: BaseMappedList<F,T,R>, index: number, value: F, params: any): void {
|
||||
const mappedValue = list._mappedValues![index];
|
||||
if (list._updater) {
|
||||
list._updater(mappedValue, params, value);
|
||||
|
@ -63,7 +63,7 @@ export function runUpdate<F,T>(list: BaseMappedList<F,T>, index: number, value:
|
|||
list.emitUpdate(index, mappedValue, params);
|
||||
}
|
||||
|
||||
export function runRemove<F,T>(list: BaseMappedList<F,T>, index: number): void {
|
||||
export function runRemove<F,T,R>(list: BaseMappedList<F,T,R>, index: number): void {
|
||||
const mappedValue = list._mappedValues![index];
|
||||
list._mappedValues!.splice(index, 1);
|
||||
if (list._removeCallback) {
|
||||
|
@ -72,14 +72,14 @@ export function runRemove<F,T>(list: BaseMappedList<F,T>, index: number): void {
|
|||
list.emitRemove(index, mappedValue);
|
||||
}
|
||||
|
||||
export function runMove<F,T>(list: BaseMappedList<F,T>, fromIdx: number, toIdx: number): void {
|
||||
export function runMove<F,T,R>(list: BaseMappedList<F,T,R>, fromIdx: number, toIdx: number): void {
|
||||
const mappedValue = list._mappedValues![fromIdx];
|
||||
list._mappedValues!.splice(fromIdx, 1);
|
||||
list._mappedValues!.splice(toIdx, 0, mappedValue);
|
||||
list.emitMove(fromIdx, toIdx, mappedValue);
|
||||
}
|
||||
|
||||
export function runReset<F,T>(list: BaseMappedList<F,T>): void {
|
||||
export function runReset<F,T,R>(list: BaseMappedList<F,T,R>): void {
|
||||
list._mappedValues = [];
|
||||
list.emitReset();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,18 @@ export interface IListObserver<T> {
|
|||
onMove(from: number, to: number, value: T, list: BaseObservableList<T>): void
|
||||
}
|
||||
|
||||
export abstract class BaseObservableList<T> extends BaseObservable<IListObserver<T>> {
|
||||
export function defaultObserverWith<T>(overrides: { [key in keyof IListObserver<T>]?: IListObserver<T>[key] }): IListObserver<T> {
|
||||
const defaults = {
|
||||
onReset(){},
|
||||
onAdd(){},
|
||||
onUpdate(){},
|
||||
onRemove(){},
|
||||
onMove(){},
|
||||
}
|
||||
return Object.assign(defaults, overrides);
|
||||
}
|
||||
|
||||
export abstract class BaseObservableList<T> extends BaseObservable<IListObserver<T>> implements Iterable<T> {
|
||||
emitReset() {
|
||||
for(let h of this._handlers) {
|
||||
h.onReset(this);
|
||||
|
@ -38,7 +49,7 @@ export abstract class BaseObservableList<T> extends BaseObservable<IListObserver
|
|||
}
|
||||
}
|
||||
|
||||
emitUpdate(index: number, value: T, params: any): void {
|
||||
emitUpdate(index: number, value: T, params?: any): void {
|
||||
for(let h of this._handlers) {
|
||||
h.onUpdate(index, value, params, this);
|
||||
}
|
||||
|
@ -58,6 +69,6 @@ export abstract class BaseObservableList<T> extends BaseObservable<IListObserver
|
|||
}
|
||||
}
|
||||
|
||||
abstract [Symbol.iterator](): IterableIterator<T>;
|
||||
abstract [Symbol.iterator](): Iterator<T>;
|
||||
abstract get length(): number;
|
||||
}
|
||||
|
|
|
@ -14,16 +14,18 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {BaseObservableList} from "./BaseObservableList";
|
||||
import {BaseObservableList, IListObserver} from "./BaseObservableList";
|
||||
|
||||
export class ConcatList extends BaseObservableList {
|
||||
constructor(...sourceLists) {
|
||||
export class ConcatList<T> extends BaseObservableList<T> implements IListObserver<T> {
|
||||
protected _sourceLists: BaseObservableList<T>[];
|
||||
protected _sourceUnsubscribes: (() => void)[] | null = null;
|
||||
|
||||
constructor(...sourceLists: BaseObservableList<T>[]) {
|
||||
super();
|
||||
this._sourceLists = sourceLists;
|
||||
this._sourceUnsubscribes = null;
|
||||
}
|
||||
|
||||
_offsetForSource(sourceList) {
|
||||
_offsetForSource(sourceList: BaseObservableList<T>): number {
|
||||
const listIdx = this._sourceLists.indexOf(sourceList);
|
||||
let offset = 0;
|
||||
for (let i = 0; i < listIdx; ++i) {
|
||||
|
@ -32,17 +34,17 @@ export class ConcatList extends BaseObservableList {
|
|||
return offset;
|
||||
}
|
||||
|
||||
onSubscribeFirst() {
|
||||
onSubscribeFirst(): void {
|
||||
this._sourceUnsubscribes = this._sourceLists.map(sourceList => sourceList.subscribe(this));
|
||||
}
|
||||
|
||||
onUnsubscribeLast() {
|
||||
for (const sourceUnsubscribe of this._sourceUnsubscribes) {
|
||||
onUnsubscribeLast(): void {
|
||||
for (const sourceUnsubscribe of this._sourceUnsubscribes!) {
|
||||
sourceUnsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
onReset() {
|
||||
onReset(): void {
|
||||
// TODO: not ideal if other source lists are large
|
||||
// but working impl for now
|
||||
// reset, and
|
||||
|
@ -54,11 +56,11 @@ export class ConcatList extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
onAdd(index, value, sourceList) {
|
||||
onAdd(index: number, value: T, sourceList: BaseObservableList<T>): void {
|
||||
this.emitAdd(this._offsetForSource(sourceList) + index, value);
|
||||
}
|
||||
|
||||
onUpdate(index, value, params, sourceList) {
|
||||
onUpdate(index: number, value: T, params: any, sourceList: BaseObservableList<T>): void {
|
||||
// if an update is emitted while calling source.subscribe() from onSubscribeFirst, ignore it
|
||||
// as we are not supposed to call `length` on any uninitialized list
|
||||
if (!this._sourceUnsubscribes) {
|
||||
|
@ -67,16 +69,16 @@ export class ConcatList extends BaseObservableList {
|
|||
this.emitUpdate(this._offsetForSource(sourceList) + index, value, params);
|
||||
}
|
||||
|
||||
onRemove(index, value, sourceList) {
|
||||
onRemove(index: number, value: T, sourceList: BaseObservableList<T>): void {
|
||||
this.emitRemove(this._offsetForSource(sourceList) + index, value);
|
||||
}
|
||||
|
||||
onMove(fromIdx, toIdx, value, sourceList) {
|
||||
onMove(fromIdx: number, toIdx: number, value: T, sourceList: BaseObservableList<T>): void {
|
||||
const offset = this._offsetForSource(sourceList);
|
||||
this.emitMove(offset + fromIdx, offset + toIdx, value);
|
||||
}
|
||||
|
||||
get length() {
|
||||
get length(): number {
|
||||
let len = 0;
|
||||
for (let i = 0; i < this._sourceLists.length; ++i) {
|
||||
len += this._sourceLists[i].length;
|
||||
|
@ -104,7 +106,8 @@ export class ConcatList extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
import {ObservableArray} from "./ObservableArray.js";
|
||||
import {ObservableArray} from "./ObservableArray";
|
||||
import {defaultObserverWith} from "./BaseObservableList";
|
||||
export async function tests() {
|
||||
return {
|
||||
test_length(assert) {
|
||||
|
@ -133,13 +136,13 @@ export async function tests() {
|
|||
const list2 = new ObservableArray([11, 12, 13]);
|
||||
const all = new ConcatList(list1, list2);
|
||||
let fired = false;
|
||||
all.subscribe({
|
||||
all.subscribe(defaultObserverWith({
|
||||
onAdd(index, value) {
|
||||
fired = true;
|
||||
assert.equal(index, 4);
|
||||
assert.equal(value, 11.5);
|
||||
}
|
||||
});
|
||||
}));
|
||||
list2.insert(1, 11.5);
|
||||
assert(fired);
|
||||
},
|
||||
|
@ -148,13 +151,13 @@ export async function tests() {
|
|||
const list2 = new ObservableArray([11, 12, 13]);
|
||||
const all = new ConcatList(list1, list2);
|
||||
let fired = false;
|
||||
all.subscribe({
|
||||
all.subscribe(defaultObserverWith({
|
||||
onUpdate(index, value) {
|
||||
fired = true;
|
||||
assert.equal(index, 4);
|
||||
assert.equal(value, 10);
|
||||
}
|
||||
});
|
||||
}));
|
||||
list2.emitUpdate(1, 10);
|
||||
assert(fired);
|
||||
},
|
|
@ -15,9 +15,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {IListObserver} from "./BaseObservableList";
|
||||
import {BaseMappedList, runAdd, runUpdate, runRemove, runMove, runReset} from "./BaseMappedList";
|
||||
|
||||
export class MappedList extends BaseMappedList {
|
||||
export class MappedList<F,T> extends BaseMappedList<F,T> implements IListObserver<F> {
|
||||
onSubscribeFirst() {
|
||||
this._sourceUnsubscribe = this._sourceList.subscribe(this);
|
||||
this._mappedValues = [];
|
||||
|
@ -26,16 +27,16 @@ export class MappedList extends BaseMappedList {
|
|||
}
|
||||
}
|
||||
|
||||
onReset() {
|
||||
onReset(): void {
|
||||
runReset(this);
|
||||
}
|
||||
|
||||
onAdd(index, value) {
|
||||
onAdd(index: number, value: F): void {
|
||||
const mappedValue = this._mapper(value);
|
||||
runAdd(this, index, mappedValue);
|
||||
}
|
||||
|
||||
onUpdate(index, value, params) {
|
||||
onUpdate(index: number, value: F, params: any): void {
|
||||
// if an update is emitted while calling source.subscribe() from onSubscribeFirst, ignore it
|
||||
if (!this._mappedValues) {
|
||||
return;
|
||||
|
@ -43,24 +44,25 @@ export class MappedList extends BaseMappedList {
|
|||
runUpdate(this, index, value, params);
|
||||
}
|
||||
|
||||
onRemove(index) {
|
||||
onRemove(index: number): void {
|
||||
runRemove(this, index);
|
||||
}
|
||||
|
||||
onMove(fromIdx, toIdx) {
|
||||
onMove(fromIdx: number, toIdx: number): void {
|
||||
runMove(this, fromIdx, toIdx);
|
||||
}
|
||||
|
||||
onUnsubscribeLast() {
|
||||
this._sourceUnsubscribe();
|
||||
onUnsubscribeLast(): void {
|
||||
this._sourceUnsubscribe!();
|
||||
}
|
||||
}
|
||||
|
||||
import {ObservableArray} from "./ObservableArray.js";
|
||||
import {ObservableArray} from "./ObservableArray";
|
||||
import {BaseObservableList} from "./BaseObservableList";
|
||||
import {defaultObserverWith} from "./BaseObservableList";
|
||||
|
||||
export async function tests() {
|
||||
class MockList extends BaseObservableList {
|
||||
class MockList extends BaseObservableList<number> {
|
||||
get length() {
|
||||
return 0;
|
||||
}
|
||||
|
@ -74,26 +76,26 @@ export async function tests() {
|
|||
const source = new MockList();
|
||||
const mapped = new MappedList(source, n => {return {n: n*n};});
|
||||
let fired = false;
|
||||
const unsubscribe = mapped.subscribe({
|
||||
const unsubscribe = mapped.subscribe(defaultObserverWith({
|
||||
onAdd(idx, value) {
|
||||
fired = true;
|
||||
assert.equal(idx, 0);
|
||||
assert.equal(value.n, 36);
|
||||
}
|
||||
});
|
||||
}));
|
||||
source.emitAdd(0, 6);
|
||||
assert(fired);
|
||||
unsubscribe();
|
||||
},
|
||||
test_update(assert) {
|
||||
const source = new MockList();
|
||||
const mapped = new MappedList(
|
||||
const mapped = new MappedList<number, { n: number, m?: number }>(
|
||||
source,
|
||||
n => {return {n: n*n};},
|
||||
(o, p, n) => o.m = n*n
|
||||
);
|
||||
let fired = false;
|
||||
const unsubscribe = mapped.subscribe({
|
||||
const unsubscribe = mapped.subscribe(defaultObserverWith({
|
||||
onAdd() {},
|
||||
onUpdate(idx, value) {
|
||||
fired = true;
|
||||
|
@ -101,7 +103,7 @@ export async function tests() {
|
|||
assert.equal(value.n, 36);
|
||||
assert.equal(value.m, 49);
|
||||
}
|
||||
});
|
||||
}));
|
||||
source.emitAdd(0, 6);
|
||||
source.emitUpdate(0, 7);
|
||||
assert(fired);
|
||||
|
@ -113,9 +115,9 @@ export async function tests() {
|
|||
source,
|
||||
n => {return n*n;}
|
||||
);
|
||||
mapped.subscribe({
|
||||
mapped.subscribe(defaultObserverWith({
|
||||
onUpdate() { assert.fail(); }
|
||||
});
|
||||
}));
|
||||
assert.equal(mapped.findAndUpdate(
|
||||
n => n === 100,
|
||||
() => assert.fail()
|
||||
|
@ -127,9 +129,9 @@ export async function tests() {
|
|||
source,
|
||||
n => {return n*n;}
|
||||
);
|
||||
mapped.subscribe({
|
||||
mapped.subscribe(defaultObserverWith({
|
||||
onUpdate() { assert.fail(); }
|
||||
});
|
||||
}));
|
||||
let fired = false;
|
||||
assert.equal(mapped.findAndUpdate(
|
||||
n => n === 9,
|
||||
|
@ -148,14 +150,14 @@ export async function tests() {
|
|||
n => {return n*n;}
|
||||
);
|
||||
let fired = false;
|
||||
mapped.subscribe({
|
||||
mapped.subscribe(defaultObserverWith({
|
||||
onUpdate(idx, n, params) {
|
||||
assert.equal(idx, 1);
|
||||
assert.equal(n, 9);
|
||||
assert.equal(params, "param");
|
||||
fired = true;
|
||||
}
|
||||
});
|
||||
}));
|
||||
assert.equal(mapped.findAndUpdate(n => n === 9, () => "param"), true);
|
||||
assert.equal(fired, true);
|
||||
},
|
|
@ -16,35 +16,37 @@ limitations under the License.
|
|||
|
||||
import {BaseObservableList} from "./BaseObservableList";
|
||||
|
||||
export class ObservableArray extends BaseObservableList {
|
||||
constructor(initialValues = []) {
|
||||
export class ObservableArray<T> extends BaseObservableList<T> {
|
||||
private _items: T[];
|
||||
|
||||
constructor(initialValues: T[] = []) {
|
||||
super();
|
||||
this._items = initialValues;
|
||||
}
|
||||
|
||||
append(item) {
|
||||
append(item: T): void {
|
||||
this._items.push(item);
|
||||
this.emitAdd(this._items.length - 1, item);
|
||||
}
|
||||
|
||||
remove(idx) {
|
||||
remove(idx: number): void {
|
||||
const [item] = this._items.splice(idx, 1);
|
||||
this.emitRemove(idx, item);
|
||||
}
|
||||
|
||||
insertMany(idx, items) {
|
||||
insertMany(idx: number, items: T[]): void {
|
||||
for(let item of items) {
|
||||
this.insert(idx, item);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
insert(idx, item) {
|
||||
insert(idx: number, item: T): void {
|
||||
this._items.splice(idx, 0, item);
|
||||
this.emitAdd(idx, item);
|
||||
}
|
||||
|
||||
move(fromIdx, toIdx) {
|
||||
move(fromIdx: number, toIdx: number): void {
|
||||
if (fromIdx < this._items.length && toIdx < this._items.length) {
|
||||
const [item] = this._items.splice(fromIdx, 1);
|
||||
this._items.splice(toIdx, 0, item);
|
||||
|
@ -52,24 +54,24 @@ export class ObservableArray extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
update(idx, item, params = null) {
|
||||
update(idx: number, item: T, params: any = null): void {
|
||||
if (idx < this._items.length) {
|
||||
this._items[idx] = item;
|
||||
this.emitUpdate(idx, item, params);
|
||||
}
|
||||
}
|
||||
|
||||
get array() {
|
||||
get array(): Readonly<T[]> {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
at(idx) {
|
||||
at(idx: number): T | undefined {
|
||||
if (this._items && idx >= 0 && idx < this._items.length) {
|
||||
return this._items[idx];
|
||||
}
|
||||
}
|
||||
|
||||
get length() {
|
||||
get length(): number {
|
||||
return this._items.length;
|
||||
}
|
||||
|
|
@ -15,21 +15,23 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {BaseObservableList} from "./BaseObservableList";
|
||||
import {sortedIndex} from "../../utils/sortedIndex.js";
|
||||
import {sortedIndex} from "../../utils/sortedIndex";
|
||||
import {findAndUpdateInArray} from "./common";
|
||||
|
||||
export class SortedArray extends BaseObservableList {
|
||||
constructor(comparator) {
|
||||
export class SortedArray<T> extends BaseObservableList<T> {
|
||||
private _comparator: (left: T, right: T) => number;
|
||||
private _items: T[] = [];
|
||||
|
||||
constructor(comparator: (left: T, right: T) => number) {
|
||||
super();
|
||||
this._comparator = comparator;
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
setManyUnsorted(items) {
|
||||
setManyUnsorted(items: T[]): void {
|
||||
this.setManySorted(items);
|
||||
}
|
||||
|
||||
setManySorted(items) {
|
||||
setManySorted(items: T[]): void {
|
||||
// TODO: we can make this way faster by only looking up the first and last key,
|
||||
// and merging whatever is inbetween with items
|
||||
// if items is not sorted, 💩🌀 will follow!
|
||||
|
@ -42,11 +44,11 @@ export class SortedArray extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
findAndUpdate(predicate, updater) {
|
||||
findAndUpdate(predicate: (value: T) => boolean, updater: (value: T) => any | false): boolean {
|
||||
return findAndUpdateInArray(predicate, this._items, this, updater);
|
||||
}
|
||||
|
||||
getAndUpdate(item, updater, updateParams = null) {
|
||||
getAndUpdate(item: T, updater: (existing: T, item: T) => any, updateParams: any = null): void {
|
||||
const idx = this.indexOf(item);
|
||||
if (idx !== -1) {
|
||||
const existingItem = this._items[idx];
|
||||
|
@ -56,7 +58,7 @@ export class SortedArray extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
update(item, updateParams = null) {
|
||||
update(item: T, updateParams: any = null): void {
|
||||
const idx = this.indexOf(item);
|
||||
if (idx !== -1) {
|
||||
this._items[idx] = item;
|
||||
|
@ -64,7 +66,7 @@ export class SortedArray extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
indexOf(item) {
|
||||
indexOf(item: T): number {
|
||||
const idx = sortedIndex(this._items, item, this._comparator);
|
||||
if (idx < this._items.length && this._comparator(this._items[idx], item) === 0) {
|
||||
return idx;
|
||||
|
@ -73,7 +75,7 @@ export class SortedArray extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
_getNext(item) {
|
||||
_getNext(item: T): T | undefined {
|
||||
let idx = sortedIndex(this._items, item, this._comparator);
|
||||
while(idx < this._items.length && this._comparator(this._items[idx], item) <= 0) {
|
||||
idx += 1;
|
||||
|
@ -81,7 +83,7 @@ export class SortedArray extends BaseObservableList {
|
|||
return this.get(idx);
|
||||
}
|
||||
|
||||
set(item, updateParams = null) {
|
||||
set(item: T, updateParams: any = null): void {
|
||||
const idx = sortedIndex(this._items, item, this._comparator);
|
||||
if (idx >= this._items.length || this._comparator(this._items[idx], item) !== 0) {
|
||||
this._items.splice(idx, 0, item);
|
||||
|
@ -92,21 +94,21 @@ export class SortedArray extends BaseObservableList {
|
|||
}
|
||||
}
|
||||
|
||||
get(idx) {
|
||||
get(idx: number): T | undefined {
|
||||
return this._items[idx];
|
||||
}
|
||||
|
||||
remove(idx) {
|
||||
remove(idx: number): void {
|
||||
const item = this._items[idx];
|
||||
this._items.splice(idx, 1);
|
||||
this.emitRemove(idx, item);
|
||||
}
|
||||
|
||||
get array() {
|
||||
get array(): T[] {
|
||||
return this._items;
|
||||
}
|
||||
|
||||
get length() {
|
||||
get length(): number {
|
||||
return this._items.length;
|
||||
}
|
||||
|
||||
|
@ -116,8 +118,11 @@ export class SortedArray extends BaseObservableList {
|
|||
}
|
||||
|
||||
// iterator that works even if the current value is removed while iterating
|
||||
class Iterator {
|
||||
constructor(sortedArray) {
|
||||
class Iterator<T> {
|
||||
private _sortedArray: SortedArray<T> | null
|
||||
private _current: T | null | undefined
|
||||
|
||||
constructor(sortedArray: SortedArray<T>) {
|
||||
this._sortedArray = sortedArray;
|
||||
this._current = null;
|
||||
}
|
||||
|
@ -145,7 +150,7 @@ class Iterator {
|
|||
export function tests() {
|
||||
return {
|
||||
"setManyUnsorted": assert => {
|
||||
const sa = new SortedArray((a, b) => a.localeCompare(b));
|
||||
const sa = new SortedArray<string>((a, b) => a.localeCompare(b));
|
||||
sa.setManyUnsorted(["b", "a", "c"]);
|
||||
assert.equal(sa.length, 3);
|
||||
assert.equal(sa.get(0), "a");
|
||||
|
@ -153,7 +158,7 @@ export function tests() {
|
|||
assert.equal(sa.get(2), "c");
|
||||
},
|
||||
"_getNext": assert => {
|
||||
const sa = new SortedArray((a, b) => a.localeCompare(b));
|
||||
const sa = new SortedArray<string>((a, b) => a.localeCompare(b));
|
||||
sa.setManyUnsorted(["b", "a", "f"]);
|
||||
assert.equal(sa._getNext("a"), "b");
|
||||
assert.equal(sa._getNext("b"), "f");
|
||||
|
@ -162,7 +167,7 @@ export function tests() {
|
|||
assert.equal(sa._getNext("f"), undefined);
|
||||
},
|
||||
"iterator with removals": assert => {
|
||||
const queue = new SortedArray((a, b) => a.idx - b.idx);
|
||||
const queue = new SortedArray<{idx: number}>((a, b) => a.idx - b.idx);
|
||||
queue.setManyUnsorted([{idx: 5}, {idx: 3}, {idx: 1}, {idx: 4}, {idx: 2}]);
|
||||
const it = queue[Symbol.iterator]();
|
||||
assert.equal(it.next().value.idx, 1);
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {BaseObservableList} from "./BaseObservableList";
|
||||
import {sortedIndex} from "../../utils/sortedIndex.js";
|
||||
import {sortedIndex} from "../../utils/sortedIndex";
|
||||
|
||||
/*
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import aesjs from "../../../lib/aes-js/index.js";
|
||||
import {hkdf} from "../../utils/crypto/hkdf.js";
|
||||
import {hkdf} from "../../utils/crypto/hkdf";
|
||||
import {Platform as ModernPlatform} from "./Platform.js";
|
||||
|
||||
export function Platform(container, paths) {
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import {createFetchRequest} from "./dom/request/fetch.js";
|
||||
import {xhrRequest} from "./dom/request/xhr.js";
|
||||
import {StorageFactory} from "../../matrix/storage/idb/StorageFactory";
|
||||
import {SessionInfoStorage} from "../../matrix/sessioninfo/localstorage/SessionInfoStorage.js";
|
||||
import {SessionInfoStorage} from "../../matrix/sessioninfo/localstorage/SessionInfoStorage";
|
||||
import {SettingsStorage} from "./dom/SettingsStorage.js";
|
||||
import {Encoding} from "./utils/Encoding.js";
|
||||
import {OlmWorker} from "../../matrix/e2ee/OlmWorker.js";
|
||||
|
@ -35,7 +35,7 @@ import {WorkerPool} from "./dom/WorkerPool.js";
|
|||
import {BlobHandle} from "./dom/BlobHandle.js";
|
||||
import {hasReadPixelPermission, ImageHandle, VideoHandle} from "./dom/ImageHandle.js";
|
||||
import {downloadInIframe} from "./dom/download.js";
|
||||
import {Disposables} from "../../utils/Disposables.js";
|
||||
import {Disposables} from "../../utils/Disposables";
|
||||
import {parseHTML} from "./parsehtml.js";
|
||||
import {handleAvatarError} from "./ui/avatar.js";
|
||||
|
||||
|
@ -132,11 +132,7 @@ export class Platform {
|
|||
this.clock = new Clock();
|
||||
this.encoding = new Encoding();
|
||||
this.random = Math.random;
|
||||
if (options?.development) {
|
||||
this.logger = new ConsoleLogger({platform: this});
|
||||
} else {
|
||||
this.logger = new IDBLogger({name: "hydrogen_logs", platform: this});
|
||||
}
|
||||
this._createLogger(options?.development);
|
||||
this.history = new History();
|
||||
this.onlineStatus = new OnlineStatus();
|
||||
this._serviceWorkerHandler = null;
|
||||
|
@ -162,6 +158,21 @@ export class Platform {
|
|||
this._disposables = new Disposables();
|
||||
}
|
||||
|
||||
_createLogger(isDevelopment) {
|
||||
// Make sure that loginToken does not end up in the logs
|
||||
const transformer = (item) => {
|
||||
if (item.e?.stack) {
|
||||
item.e.stack = item.e.stack.replace(/(?<=\/\?loginToken=).+/, "<snip>");
|
||||
}
|
||||
return item;
|
||||
};
|
||||
if (isDevelopment) {
|
||||
this.logger = new ConsoleLogger({platform: this});
|
||||
} else {
|
||||
this.logger = new IDBLogger({name: "hydrogen_logs", platform: this, serializedTransformer: transformer});
|
||||
}
|
||||
}
|
||||
|
||||
get updateService() {
|
||||
return this._serviceWorkerHandler;
|
||||
}
|
||||
|
@ -272,3 +283,30 @@ export class Platform {
|
|||
this._disposables.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
import {LogItem} from "../../logging/LogItem";
|
||||
export function tests() {
|
||||
return {
|
||||
"loginToken should not be in logs": (assert) => {
|
||||
const transformer = (item) => {
|
||||
if (item.e?.stack) {
|
||||
item.e.stack = item.e.stack.replace(/(?<=\/\?loginToken=).+/, "<snip>");
|
||||
}
|
||||
return item;
|
||||
};
|
||||
const logger = {
|
||||
_queuedItems: [],
|
||||
_serializedTransformer: transformer,
|
||||
_now: () => {}
|
||||
};
|
||||
logger.persist = IDBLogger.prototype._persistItem.bind(logger);
|
||||
const logItem = new LogItem("test", 1, logger);
|
||||
logItem.error = new Error();
|
||||
logItem.error.stack = "main http://localhost:3000/src/main.js:55\n<anonymous> http://localhost:3000/?loginToken=secret:26"
|
||||
logger.persist(logItem, null, false);
|
||||
const item = logger._queuedItems.pop();
|
||||
console.log(item);
|
||||
assert.strictEqual(item.json.search("secret"), -1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {AbortError} from "../../../utils/error.js";
|
||||
import {AbortError} from "../../../utils/error";
|
||||
|
||||
class Timeout {
|
||||
constructor(ms) {
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {AbortError} from "../../../utils/error.js";
|
||||
import {AbortError} from "../../../utils/error";
|
||||
|
||||
class WorkerState {
|
||||
constructor(worker) {
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
AbortError,
|
||||
ConnectionError
|
||||
} from "../../../../matrix/error.js";
|
||||
import {abortOnTimeout} from "../../../../utils/timeout.js";
|
||||
import {abortOnTimeout} from "../../../../utils/timeout";
|
||||
import {addCacheBuster} from "./common.js";
|
||||
import {xhrRequest} from "./xhr.js";
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {Range, RangeZone} from "./Range";
|
||||
import {defaultObserverWith} from "../../../../observable/list/BaseObservableList";
|
||||
|
||||
function skipOnIterator<T>(it: Iterator<T>, pos: number): boolean {
|
||||
let i = 0;
|
||||
|
@ -214,7 +215,7 @@ export class ListRange extends Range {
|
|||
}
|
||||
}
|
||||
|
||||
import {ObservableArray} from "../../../../observable/list/ObservableArray.js";
|
||||
import {ObservableArray} from "../../../../observable/list/ObservableArray";
|
||||
|
||||
export function tests() {
|
||||
return {
|
||||
|
@ -268,7 +269,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["b", "c", "d", "e"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let added = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onAdd(idx, value) {
|
||||
added = true;
|
||||
const result = range.queryAdd(idx, value, list);
|
||||
|
@ -280,7 +281,7 @@ export function tests() {
|
|||
newRange: new ListRange(1, 3, 5)
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.insert(0, "a");
|
||||
assert(added);
|
||||
},
|
||||
|
@ -288,7 +289,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "d", "e"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let added = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onAdd(idx, value) {
|
||||
added = true;
|
||||
const result = range.queryAdd(idx, value, list);
|
||||
|
@ -300,7 +301,7 @@ export function tests() {
|
|||
newRange: new ListRange(1, 3, 5)
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.insert(2, "c");
|
||||
assert(added);
|
||||
},
|
||||
|
@ -308,7 +309,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let added = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onAdd(idx, value) {
|
||||
added = true;
|
||||
const result = range.queryAdd(idx, value, list);
|
||||
|
@ -317,7 +318,7 @@ export function tests() {
|
|||
newRange: new ListRange(1, 3, 5)
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.insert(4, "e");
|
||||
assert(added);
|
||||
},
|
||||
|
@ -326,7 +327,7 @@ export function tests() {
|
|||
const viewportItemCount = 4;
|
||||
const range = new ListRange(0, 3, list.length, viewportItemCount);
|
||||
let added = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onAdd(idx, value) {
|
||||
added = true;
|
||||
const result = range.queryAdd(idx, value, list);
|
||||
|
@ -337,7 +338,7 @@ export function tests() {
|
|||
value: "c"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.insert(2, "c");
|
||||
assert(added);
|
||||
},
|
||||
|
@ -345,7 +346,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let removed = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onRemove(idx) {
|
||||
removed = true;
|
||||
const result = range.queryRemove(idx, list);
|
||||
|
@ -357,7 +358,7 @@ export function tests() {
|
|||
newRange: new ListRange(1, 3, 4)
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.remove(0);
|
||||
assert(removed);
|
||||
},
|
||||
|
@ -365,7 +366,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let removed = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onRemove(idx) {
|
||||
removed = true;
|
||||
const result = range.queryRemove(idx, list);
|
||||
|
@ -378,7 +379,7 @@ export function tests() {
|
|||
});
|
||||
assert.equal(list.length, 4);
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.remove(2);
|
||||
assert(removed);
|
||||
},
|
||||
|
@ -386,7 +387,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let removed = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onRemove(idx) {
|
||||
removed = true;
|
||||
const result = range.queryRemove(idx, list);
|
||||
|
@ -395,7 +396,7 @@ export function tests() {
|
|||
newRange: new ListRange(1, 3, 4)
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.remove(3);
|
||||
assert(removed);
|
||||
},
|
||||
|
@ -403,7 +404,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c"]);
|
||||
const range = new ListRange(1, 3, list.length);
|
||||
let removed = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onRemove(idx) {
|
||||
removed = true;
|
||||
const result = range.queryRemove(idx, list);
|
||||
|
@ -415,7 +416,7 @@ export function tests() {
|
|||
value: "a"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.remove(2);
|
||||
assert(removed);
|
||||
},
|
||||
|
@ -423,7 +424,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c"]);
|
||||
const range = new ListRange(0, 3, list.length);
|
||||
let removed = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onRemove(idx) {
|
||||
removed = true;
|
||||
const result = range.queryRemove(idx, list);
|
||||
|
@ -433,7 +434,7 @@ export function tests() {
|
|||
removeIdx: 2,
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.remove(2);
|
||||
assert(removed);
|
||||
},
|
||||
|
@ -441,7 +442,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(1, 4, list.length);
|
||||
let moved = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
moved = true;
|
||||
const result = range.queryMove(fromIdx, toIdx, value, list);
|
||||
|
@ -451,7 +452,7 @@ export function tests() {
|
|||
toIdx: 3
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.move(2, 3);
|
||||
assert(moved);
|
||||
},
|
||||
|
@ -459,7 +460,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(2, 5, list.length);
|
||||
let moved = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
moved = true;
|
||||
const result = range.queryMove(fromIdx, toIdx, value, list);
|
||||
|
@ -470,7 +471,7 @@ export function tests() {
|
|||
value: "a"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.move(0, 3); // move "a" to after "d"
|
||||
assert(moved);
|
||||
},
|
||||
|
@ -478,7 +479,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(0, 3, list.length);
|
||||
let moved = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
moved = true;
|
||||
const result = range.queryMove(fromIdx, toIdx, value, list);
|
||||
|
@ -489,7 +490,7 @@ export function tests() {
|
|||
value: "e"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.move(4, 1); // move "e" to before "b"
|
||||
assert(moved);
|
||||
},
|
||||
|
@ -497,7 +498,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(0, 3, list.length);
|
||||
let moved = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
moved = true;
|
||||
const result = range.queryMove(fromIdx, toIdx, value, list);
|
||||
|
@ -508,7 +509,7 @@ export function tests() {
|
|||
value: "d"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.move(1, 3); // move "b" to after "d"
|
||||
assert(moved);
|
||||
},
|
||||
|
@ -516,7 +517,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(2, 5, list.length);
|
||||
let moved = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
moved = true;
|
||||
const result = range.queryMove(fromIdx, toIdx, value, list);
|
||||
|
@ -527,7 +528,7 @@ export function tests() {
|
|||
value: "b"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.move(3, 0); // move "d" to before "a"
|
||||
assert(moved);
|
||||
},
|
||||
|
@ -535,7 +536,7 @@ export function tests() {
|
|||
const list = new ObservableArray(["a", "b", "c", "d", "e"]);
|
||||
const range = new ListRange(1, 4, list.length);
|
||||
let moved = false;
|
||||
list.subscribe({
|
||||
list.subscribe(defaultObserverWith({
|
||||
onMove(fromIdx, toIdx, value) {
|
||||
moved = true;
|
||||
const result = range.queryMove(fromIdx, toIdx, value, list);
|
||||
|
@ -546,7 +547,7 @@ export function tests() {
|
|||
value: "e"
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
list.move(0, 4); // move "a" to after "e"
|
||||
assert(moved);
|
||||
},
|
||||
|
|
|
@ -43,7 +43,7 @@ export class Range {
|
|||
return range.start < this.end && this.start < range.end;
|
||||
}
|
||||
|
||||
forEachInIterator<T>(it: IterableIterator<T>, callback: ((T, i: number) => void)) {
|
||||
forEachInIterator<T>(it: Iterator<T>, callback: ((T, i: number) => void)) {
|
||||
let i = 0;
|
||||
for (i = 0; i < this.start; i += 1) {
|
||||
it.next();
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
interface IAbortable {
|
||||
export interface IAbortable {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,13 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
function disposeValue(value) {
|
||||
export interface IDisposable {
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
type Disposable = IDisposable | (() => void);
|
||||
|
||||
function disposeValue(value: Disposable): void {
|
||||
if (typeof value === "function") {
|
||||
value();
|
||||
} else {
|
||||
|
@ -22,16 +28,14 @@ function disposeValue(value) {
|
|||
}
|
||||
}
|
||||
|
||||
function isDisposable(value) {
|
||||
function isDisposable(value: Disposable): boolean {
|
||||
return value && (typeof value === "function" || typeof value.dispose === "function");
|
||||
}
|
||||
|
||||
export class Disposables {
|
||||
constructor() {
|
||||
this._disposables = [];
|
||||
}
|
||||
private _disposables: Disposable[] | null = [];
|
||||
|
||||
track(disposable) {
|
||||
track(disposable: Disposable): Disposable {
|
||||
if (!isDisposable(disposable)) {
|
||||
throw new Error("Not a disposable");
|
||||
}
|
||||
|
@ -40,19 +44,23 @@ export class Disposables {
|
|||
disposeValue(disposable);
|
||||
return disposable;
|
||||
}
|
||||
this._disposables.push(disposable);
|
||||
this._disposables!.push(disposable);
|
||||
return disposable;
|
||||
}
|
||||
|
||||
untrack(disposable) {
|
||||
const idx = this._disposables.indexOf(disposable);
|
||||
untrack(disposable: Disposable): null {
|
||||
if (this.isDisposed) {
|
||||
console.warn("Disposables already disposed, cannot untrack");
|
||||
return null;
|
||||
}
|
||||
const idx = this._disposables!.indexOf(disposable);
|
||||
if (idx >= 0) {
|
||||
this._disposables.splice(idx, 1);
|
||||
this._disposables!.splice(idx, 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
dispose(): void {
|
||||
if (this._disposables) {
|
||||
for (const d of this._disposables) {
|
||||
disposeValue(d);
|
||||
|
@ -61,17 +69,17 @@ export class Disposables {
|
|||
}
|
||||
}
|
||||
|
||||
get isDisposed() {
|
||||
get isDisposed(): boolean {
|
||||
return this._disposables === null;
|
||||
}
|
||||
|
||||
disposeTracked(value) {
|
||||
disposeTracked(value: Disposable): null {
|
||||
if (value === undefined || value === null || this.isDisposed) {
|
||||
return null;
|
||||
}
|
||||
const idx = this._disposables.indexOf(value);
|
||||
const idx = this._disposables!.indexOf(value);
|
||||
if (idx !== -1) {
|
||||
const [foundValue] = this._disposables.splice(idx, 1);
|
||||
const [foundValue] = this._disposables!.splice(idx, 1);
|
||||
disposeValue(foundValue);
|
||||
} else {
|
||||
console.warn("disposable not found, did it leak?", value);
|
|
@ -15,12 +15,10 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
export class Lock {
|
||||
constructor() {
|
||||
this._promise = null;
|
||||
this._resolve = null;
|
||||
}
|
||||
private _promise?: Promise<void>;
|
||||
private _resolve?: (() => void);
|
||||
|
||||
tryTake() {
|
||||
tryTake(): boolean {
|
||||
if (!this._promise) {
|
||||
this._promise = new Promise(resolve => {
|
||||
this._resolve = resolve;
|
||||
|
@ -30,36 +28,36 @@ export class Lock {
|
|||
return false;
|
||||
}
|
||||
|
||||
async take() {
|
||||
async take(): Promise<void> {
|
||||
while(!this.tryTake()) {
|
||||
await this.released();
|
||||
}
|
||||
}
|
||||
|
||||
get isTaken() {
|
||||
get isTaken(): boolean {
|
||||
return !!this._promise;
|
||||
}
|
||||
|
||||
release() {
|
||||
release(): void {
|
||||
if (this._resolve) {
|
||||
this._promise = null;
|
||||
this._promise = undefined;
|
||||
const resolve = this._resolve;
|
||||
this._resolve = null;
|
||||
this._resolve = undefined;
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
released() {
|
||||
released(): Promise<void> | undefined {
|
||||
return this._promise;
|
||||
}
|
||||
}
|
||||
|
||||
export class MultiLock {
|
||||
constructor(locks) {
|
||||
this.locks = locks;
|
||||
|
||||
constructor(public readonly locks: Lock[]) {
|
||||
}
|
||||
|
||||
release() {
|
||||
release(): void {
|
||||
for (const lock of this.locks) {
|
||||
lock.release();
|
||||
}
|
||||
|
@ -86,9 +84,9 @@ export function tests() {
|
|||
lock.tryTake();
|
||||
|
||||
let first;
|
||||
lock.released().then(() => first = lock.tryTake());
|
||||
lock.released()!.then(() => first = lock.tryTake());
|
||||
let second;
|
||||
lock.released().then(() => second = lock.tryTake());
|
||||
lock.released()!.then(() => second = lock.tryTake());
|
||||
const promise = lock.released();
|
||||
lock.release();
|
||||
await promise;
|
|
@ -14,14 +14,12 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {Lock} from "./Lock.js";
|
||||
import {Lock} from "./Lock";
|
||||
|
||||
export class LockMap {
|
||||
constructor() {
|
||||
this._map = new Map();
|
||||
}
|
||||
export class LockMap<T> {
|
||||
private readonly _map: Map<T, Lock> = new Map();
|
||||
|
||||
async takeLock(key) {
|
||||
async takeLock(key: T): Promise<Lock> {
|
||||
let lock = this._map.get(key);
|
||||
if (lock) {
|
||||
await lock.take();
|
||||
|
@ -31,10 +29,10 @@ export class LockMap {
|
|||
this._map.set(key, lock);
|
||||
}
|
||||
// don't leave old locks lying around
|
||||
lock.released().then(() => {
|
||||
lock.released()!.then(() => {
|
||||
// give others a chance to take the lock first
|
||||
Promise.resolve().then(() => {
|
||||
if (!lock.isTaken) {
|
||||
if (!lock!.isTaken) {
|
||||
this._map.delete(key);
|
||||
}
|
||||
});
|
||||
|
@ -67,6 +65,7 @@ export function tests() {
|
|||
ranSecond = true;
|
||||
assert.equal(returnedLock.isTaken, true);
|
||||
// peek into internals, naughty
|
||||
// @ts-ignore
|
||||
assert.equal(lockMap._map.get("foo"), returnedLock);
|
||||
});
|
||||
lock.release();
|
||||
|
@ -84,6 +83,7 @@ export function tests() {
|
|||
// double delay to make sure cleanup logic ran
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
// @ts-ignore
|
||||
assert.equal(lockMap._map.has("foo"), false);
|
||||
},
|
||||
|
|
@ -15,16 +15,18 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
export class RetainedValue {
|
||||
constructor(freeCallback) {
|
||||
private readonly _freeCallback: () => void;
|
||||
private _retentionCount: number = 1;
|
||||
|
||||
constructor(freeCallback: () => void) {
|
||||
this._freeCallback = freeCallback;
|
||||
this._retentionCount = 1;
|
||||
}
|
||||
|
||||
retain() {
|
||||
retain(): void {
|
||||
this._retentionCount += 1;
|
||||
}
|
||||
|
||||
release() {
|
||||
release(): void {
|
||||
this._retentionCount -= 1;
|
||||
if (this._retentionCount === 0) {
|
||||
this._freeCallback();
|
|
@ -6,8 +6,10 @@
|
|||
* Based on https://github.com/junkurihara/jscu/blob/develop/packages/js-crypto-hkdf/src/hkdf.ts
|
||||
*/
|
||||
|
||||
import type {Crypto} from "../../platform/web/dom/Crypto.js";
|
||||
|
||||
// forked this code to make it use the cryptoDriver for HMAC that is more backwards-compatible
|
||||
export async function hkdf(cryptoDriver, key, salt, info, hash, length) {
|
||||
export async function hkdf(cryptoDriver: Crypto, key: Uint8Array, salt: Uint8Array, info: Uint8Array, hash: "SHA-256" | "SHA-512", length: number): Promise<Uint8Array> {
|
||||
length = length / 8;
|
||||
const len = cryptoDriver.digestSize(hash);
|
||||
|
|
@ -6,17 +6,19 @@
|
|||
* Based on https://github.com/junkurihara/jscu/blob/develop/packages/js-crypto-pbkdf/src/pbkdf.ts
|
||||
*/
|
||||
|
||||
import type {Crypto} from "../../platform/web/dom/Crypto.js";
|
||||
|
||||
// not used atm, but might in the future
|
||||
// forked this code to make it use the cryptoDriver for HMAC that is more backwards-compatible
|
||||
|
||||
|
||||
const nwbo = (num, len) => {
|
||||
const nwbo = (num: number, len: number): Uint8Array => {
|
||||
const arr = new Uint8Array(len);
|
||||
for(let i=0; i<len; i++) arr[i] = 0xFF && (num >> ((len - i - 1)*8));
|
||||
return arr;
|
||||
};
|
||||
|
||||
export async function pbkdf2(cryptoDriver, password, iterations, salt, hash, length) {
|
||||
export async function pbkdf2(cryptoDriver: Crypto, password: Uint8Array, iterations: number, salt: Uint8Array, hash: "SHA-256" | "SHA-512", length: number): Promise<Uint8Array> {
|
||||
const dkLen = length / 8;
|
||||
if (iterations <= 0) {
|
||||
throw new Error('InvalidIterationCount');
|
||||
|
@ -30,7 +32,7 @@ export async function pbkdf2(cryptoDriver, password, iterations, salt, hash, len
|
|||
const l = Math.ceil(dkLen/hLen);
|
||||
const r = dkLen - (l-1)*hLen;
|
||||
|
||||
const funcF = async (i) => {
|
||||
const funcF = async (i: number) => {
|
||||
const seed = new Uint8Array(salt.length + 4);
|
||||
seed.set(salt);
|
||||
seed.set(nwbo(i+1, 4), salt.length);
|
||||
|
@ -46,7 +48,7 @@ export async function pbkdf2(cryptoDriver, password, iterations, salt, hash, len
|
|||
return {index: i, value: outputF};
|
||||
};
|
||||
|
||||
const Tis = [];
|
||||
const Tis: Promise<{index: number, value: Uint8Array}>[] = [];
|
||||
const DK = new Uint8Array(dkLen);
|
||||
for(let i = 0; i < l; i++) {
|
||||
Tis.push(funcF(i));
|
|
@ -14,12 +14,9 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
export function createEnum(...values) {
|
||||
export function createEnum(...values: string[]): Readonly<{}> {
|
||||
const obj = {};
|
||||
for (const value of values) {
|
||||
if (typeof value !== "string") {
|
||||
throw new Error("Invalid enum value name" + value?.toString());
|
||||
}
|
||||
obj[value] = value;
|
||||
}
|
||||
return Object.freeze(obj);
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
export class AbortError extends Error {
|
||||
get name() {
|
||||
get name(): string {
|
||||
return "AbortError";
|
||||
}
|
||||
}
|
|
@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
export function formatSize(size, decimals = 2) {
|
||||
|
||||
export function formatSize(size: number, decimals: number = 2): string {
|
||||
if (Number.isSafeInteger(size)) {
|
||||
const base = Math.min(3, Math.floor(Math.log(size) / Math.log(1024)));
|
||||
const formattedSize = Math.round(size / Math.pow(1024, base)).toFixed(decimals);
|
||||
|
@ -25,4 +26,5 @@ export function formatSize(size, decimals = 2) {
|
|||
case 3: return `${formattedSize} GB`;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
export function mergeMap(src, dst) {
|
||||
export function mergeMap<K, V>(src: Map<K, V> | undefined, dst: Map<K, V>): void {
|
||||
if (src) {
|
||||
for (const [key, value] of src.entries()) {
|
||||
dst.set(key, value);
|
|
@ -22,7 +22,7 @@ limitations under the License.
|
|||
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||||
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
*/
|
||||
export function sortedIndex(array, value, comparator) {
|
||||
export function sortedIndex<T>(array: T[], value: T, comparator: (x:T, y:T) => number): number {
|
||||
let low = 0;
|
||||
let high = array.length;
|
||||
|
|
@ -16,9 +16,12 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import {ConnectionError} from "../matrix/error.js";
|
||||
import type {Timeout} from "../platform/web/dom/Clock.js"
|
||||
import type {IAbortable} from "./AbortableOperation";
|
||||
|
||||
type TimeoutCreator = (ms: number) => Timeout;
|
||||
|
||||
export function abortOnTimeout(createTimeout, timeoutAmount, requestResult, responsePromise) {
|
||||
export function abortOnTimeout(createTimeout: TimeoutCreator, timeoutAmount: number, requestResult: IAbortable, responsePromise: Promise<Response>) {
|
||||
const timeout = createTimeout(timeoutAmount);
|
||||
// abort request if timeout finishes first
|
||||
let timedOut = false;
|
|
@ -3124,10 +3124,10 @@ import-fresh@^3.0.0, import-fresh@^3.2.1:
|
|||
parent-module "^1.0.0"
|
||||
resolve-from "^4.0.0"
|
||||
|
||||
impunity@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/impunity/-/impunity-1.0.8.tgz#d6db44e8a15ca2cdaed6a5c478a770853cb5a56e"
|
||||
integrity sha512-6jMqYrvY2SA/PZ+yheJYd3eJ3zcO8dWmHRVy/BSjnKMEmIVB+lMO30MZOkG+kHH0eJuaGOKv0BrZmgwE6NUDRg==
|
||||
impunity@^1.0.9:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/impunity/-/impunity-1.0.9.tgz#8524d96f07c26987519ec693c4c4d3ab49254b03"
|
||||
integrity sha512-tfy7GRHeE9JVURKM7dqfTAZItGFeA/DRrlhgMLUuzSig3jF+AYSUV26tGTMGrfCN0Cb9hNz6xrZnNwa5M1hz4Q==
|
||||
dependencies:
|
||||
colors "^1.3.3"
|
||||
commander "^6.1.0"
|
||||
|
|
Loading…
Reference in a new issue