Fix Tests

This commit is contained in:
thororen1234 2024-11-19 17:08:13 -05:00
parent 1681eabe74
commit bb0a9888de
11 changed files with 13 additions and 1545 deletions

View file

@ -48,6 +48,7 @@
"fflate": "^0.8.2",
"gifenc": "github:mattdesl/gifenc#64842fca317b112a8590f8fef2bf3825da8f6fe3",
"jsqr": "1.4.0",
"idb": "8.0.0",
"monaco-editor": "^0.50.0",
"nanoid": "^5.0.7",
"usercss-meta": "^0.12.0",
@ -120,4 +121,4 @@
"node": ">=18",
"pnpm": ">=9"
}
}
}

View file

@ -49,6 +49,9 @@ importers:
gifenc:
specifier: github:mattdesl/gifenc#64842fca317b112a8590f8fef2bf3825da8f6fe3
version: https://codeload.github.com/mattdesl/gifenc/tar.gz/64842fca317b112a8590f8fef2bf3825da8f6fe3
idb:
specifier: 8.0.0
version: 8.0.0
jsqr:
specifier: 1.4.0
version: 1.4.0
@ -1544,6 +1547,9 @@ packages:
humanize-ms@1.2.1:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
idb@8.0.0:
resolution: {integrity: sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw==}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@ -3848,6 +3854,8 @@ snapshots:
dependencies:
ms: 2.1.2
idb@8.0.0: {}
ieee754@1.2.1: {}
ignore@5.2.4: {}

View file

@ -4,10 +4,11 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { DBSchema, IDBPDatabase, openDB } from "idb";
import { LoggedMessageJSON } from "./types";
import { getMessageStatus } from "./utils";
import { DB_NAME, DB_VERSION } from "./utils/constants";
import { DBSchema, IDBPDatabase, openDB } from "./utils/idb";
import { getAttachmentBlobUrl } from "./utils/saveImage";
export enum DBMessageStatus {

View file

@ -1,6 +0,0 @@
ISC License (ISC)
Copyright (c) 2016, Jake Archibald <jaffathecake@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View file

@ -1,78 +0,0 @@
/* eslint-disable simple-header/header */
import { IDBPCursor, IDBPIndex, IDBPObjectStore } from "./entry.js";
import { Func, instanceOfAny } from "./util.js";
import { replaceTraps, reverseTransformCache, unwrap } from "./wrap-idb-value.js";
const advanceMethodProps = ["continue", "continuePrimaryKey", "advance"];
const methodMap: { [s: string]: Func; } = {};
const advanceResults = new WeakMap<IDBPCursor, Promise<IDBPCursor | null>>();
const ittrProxiedCursorToOriginalProxy = new WeakMap<IDBPCursor, IDBPCursor>();
const cursorIteratorTraps: ProxyHandler<any> = {
get(target, prop) {
if (!advanceMethodProps.includes(prop as string)) return target[prop];
let cachedFunc = methodMap[prop as string];
if (!cachedFunc) {
cachedFunc = methodMap[prop as string] = function (
this: IDBPCursor,
...args: any
) {
advanceResults.set(
this,
(ittrProxiedCursorToOriginalProxy.get(this) as any)[prop](...args),
);
};
}
return cachedFunc;
},
};
async function* iterate(
this: IDBPObjectStore | IDBPIndex | IDBPCursor,
...args: any[]
): AsyncIterableIterator<any> {
// tslint:disable-next-line:no-this-assignment
let cursor: typeof this | null = this;
if (!(cursor instanceof IDBCursor)) {
cursor = await (cursor as IDBPObjectStore | IDBPIndex).openCursor(...args);
}
if (!cursor) return;
cursor = cursor as IDBPCursor;
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
// Map this double-proxy back to the original, so other cursor methods work.
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
while (cursor) {
yield proxiedCursor;
// If one of the advancing methods was not called, call continue().
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
advanceResults.delete(proxiedCursor);
}
}
function isIteratorProp(target: any, prop: number | string | symbol) {
return (
(prop === Symbol.asyncIterator &&
instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||
(prop === "iterate" && instanceOfAny(target, [IDBIndex, IDBObjectStore]))
);
}
replaceTraps(oldTraps => ({
...oldTraps,
get(target, prop, receiver) {
if (isIteratorProp(target, prop)) return iterate;
return oldTraps.get!(target, prop, receiver);
},
has(target, prop) {
return isIteratorProp(target, prop) || oldTraps.has!(target, prop);
},
}));

View file

@ -1,75 +0,0 @@
/* eslint-disable simple-header/header */
import { IDBPDatabase, IDBPIndex } from "./entry.js";
import { Func } from "./util.js";
import { replaceTraps } from "./wrap-idb-value.js";
const readMethods = ["get", "getKey", "getAll", "getAllKeys", "count"];
const writeMethods = ["put", "add", "delete", "clear"];
const cachedMethods = new Map<string, Func>();
function getMethod(
target: any,
prop: string | number | symbol,
): Func | undefined {
if (
!(
target instanceof IDBDatabase &&
!(prop in target) &&
typeof prop === "string"
)
) {
return;
}
if (cachedMethods.get(prop)) return cachedMethods.get(prop);
const targetFuncName: string = prop.replace(/FromIndex$/, "");
const useIndex = prop !== targetFuncName;
const isWrite = writeMethods.includes(targetFuncName);
if (
// Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
!(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||
!(isWrite || readMethods.includes(targetFuncName))
) {
return;
}
const method = async function (
this: IDBPDatabase,
storeName: string,
...args: any[]
) {
// isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
const tx = this.transaction(storeName, isWrite ? "readwrite" : "readonly");
let target:
| typeof tx.store
| IDBPIndex<unknown, string[], string, string, "readwrite" | "readonly"> =
tx.store;
if (useIndex) target = target.index(args.shift());
// Must reject if op rejects.
// If it's a write operation, must reject if tx.done rejects.
// Must reject with op rejection first.
// Must resolve with op value.
// Must handle both promises (no unhandled rejections)
return (
await Promise.all([
(target as any)[targetFuncName](...args),
isWrite && tx.done,
])
)[0];
};
cachedMethods.set(prop, method);
return method;
}
replaceTraps(oldTraps => ({
...oldTraps,
get: (target, prop, receiver) =>
getMethod(target, prop) || oldTraps.get!(target, prop, receiver),
has: (target, prop) =>
!!getMethod(target, prop) || oldTraps.has!(target, prop),
}));

File diff suppressed because it is too large Load diff

View file

@ -1,5 +0,0 @@
/* eslint-disable simple-header/header */
export * from "./entry.js";
import "./database-extras.js";
import "./async-iterators.js";

View file

@ -1,9 +0,0 @@
/* eslint-disable simple-header/header */
export type Constructor = new (...args: any[]) => any;
export type Func = (...args: any[]) => any;
export const instanceOfAny = (
object: any,
constructors: Constructor[],
): boolean => constructors.some(c => object instanceof c);

View file

@ -1,227 +0,0 @@
/* eslint-disable simple-header/header */
import {
IDBPCursor,
IDBPCursorWithValue,
IDBPDatabase,
IDBPIndex,
IDBPObjectStore,
IDBPTransaction,
} from "./entry.js";
import { Constructor, Func, instanceOfAny } from "./util.js";
let idbProxyableTypes: Constructor[];
let cursorAdvanceMethods: Func[];
// This is a function to prevent it throwing up in node environments.
function getIdbProxyableTypes(): Constructor[] {
return (
idbProxyableTypes ||
(idbProxyableTypes = [
IDBDatabase,
IDBObjectStore,
IDBIndex,
IDBCursor,
IDBTransaction,
])
);
}
// This is a function to prevent it throwing up in node environments.
function getCursorAdvanceMethods(): Func[] {
return (
cursorAdvanceMethods ||
(cursorAdvanceMethods = [
IDBCursor.prototype.advance,
IDBCursor.prototype.continue,
IDBCursor.prototype.continuePrimaryKey,
])
);
}
const transactionDoneMap: WeakMap<
IDBTransaction,
Promise<void>
> = new WeakMap();
const transformCache = new WeakMap();
export const reverseTransformCache = new WeakMap();
function promisifyRequest<T>(request: IDBRequest<T>): Promise<T> {
const promise = new Promise<T>((resolve, reject) => {
const unlisten = () => {
request.removeEventListener("success", success);
request.removeEventListener("error", error);
};
const success = () => {
resolve(wrap(request.result as any) as any);
unlisten();
};
const error = () => {
reject(request.error);
unlisten();
};
request.addEventListener("success", success);
request.addEventListener("error", error);
});
// This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This
// is because we create many promises from a single IDBRequest.
reverseTransformCache.set(promise, request);
return promise;
}
function cacheDonePromiseForTransaction(tx: IDBTransaction): void {
// Early bail if we've already created a done promise for this transaction.
if (transactionDoneMap.has(tx)) return;
const done = new Promise<void>((resolve, reject) => {
const unlisten = () => {
tx.removeEventListener("complete", complete);
tx.removeEventListener("error", error);
tx.removeEventListener("abort", error);
};
const complete = () => {
resolve();
unlisten();
};
const error = () => {
reject(tx.error || new DOMException("AbortError", "AbortError"));
unlisten();
};
tx.addEventListener("complete", complete);
tx.addEventListener("error", error);
tx.addEventListener("abort", error);
});
// Cache it for later retrieval.
transactionDoneMap.set(tx, done);
}
let idbProxyTraps: ProxyHandler<any> = {
get(target, prop, receiver) {
if (target instanceof IDBTransaction) {
// Special handling for transaction.done.
if (prop === "done") return transactionDoneMap.get(target);
// Make tx.store return the only store in the transaction, or undefined if there are many.
if (prop === "store") {
return receiver.objectStoreNames[1]
? undefined
: receiver.objectStore(receiver.objectStoreNames[0]);
}
}
// Else transform whatever we get back.
return wrap(target[prop]);
},
set(target, prop, value) {
target[prop] = value;
return true;
},
has(target, prop) {
if (
target instanceof IDBTransaction &&
(prop === "done" || prop === "store")
) {
return true;
}
return prop in target;
},
};
export function replaceTraps(
callback: (currentTraps: ProxyHandler<any>) => ProxyHandler<any>,
): void {
idbProxyTraps = callback(idbProxyTraps);
}
function wrapFunction<T extends Func>(func: T): Function {
// Due to expected object equality (which is enforced by the caching in `wrap`), we
// only create one new func per func.
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
// with real promises, so each advance methods returns a new promise for the cursor object, or
// undefined if the end of the cursor has been reached.
if (getCursorAdvanceMethods().includes(func)) {
return function (this: IDBPCursor, ...args: Parameters<T>) {
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
// the original object.
func.apply(unwrap(this), args);
return wrap(this.request);
};
}
return function (this: any, ...args: Parameters<T>) {
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
// the original object.
return wrap(func.apply(unwrap(this), args));
};
}
function transformCachableValue(value: any): any {
if (typeof value === "function") return wrapFunction(value);
// This doesn't return, it just creates a 'done' promise for the transaction,
// which is later returned for transaction.done (see idbObjectHandler).
if (value instanceof IDBTransaction) cacheDonePromiseForTransaction(value);
if (instanceOfAny(value, getIdbProxyableTypes()))
return new Proxy(value, idbProxyTraps);
// Return the same value back if we're not going to transform it.
return value;
}
/**
* Enhance an IDB object with helpers.
*
* @param value The thing to enhance.
*/
export function wrap(value: IDBDatabase): IDBPDatabase;
export function wrap(value: IDBIndex): IDBPIndex;
export function wrap(value: IDBObjectStore): IDBPObjectStore;
export function wrap(value: IDBTransaction): IDBPTransaction;
export function wrap(
value: IDBOpenDBRequest,
): Promise<IDBPDatabase | undefined>;
export function wrap<T>(value: IDBRequest<T>): Promise<T>;
export function wrap(value: any): any {
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
if (value instanceof IDBRequest) return promisifyRequest(value);
// If we've already transformed this value before, reuse the transformed value.
// This is faster, but it also provides object equality.
if (transformCache.has(value)) return transformCache.get(value);
const newValue = transformCachableValue(value);
// Not all types are transformed.
// These may be primitive types, so they can't be WeakMap keys.
if (newValue !== value) {
transformCache.set(value, newValue);
reverseTransformCache.set(newValue, value);
}
return newValue;
}
/**
* Revert an enhanced IDB object to a plain old miserable IDB one.
*
* Will also revert a promise back to an IDBRequest.
*
* @param value The enhanced object to revert.
*/
interface Unwrap {
(value: IDBPCursorWithValue<any, any, any, any, any>): IDBCursorWithValue;
(value: IDBPCursor<any, any, any, any, any>): IDBCursor;
(value: IDBPDatabase): IDBDatabase;
(value: IDBPIndex<any, any, any, any, any>): IDBIndex;
(value: IDBPObjectStore<any, any, any, any>): IDBObjectStore;
(value: IDBPTransaction<any, any, any>): IDBTransaction;
<T extends any>(value: Promise<IDBPDatabase<T>>): IDBOpenDBRequest;
(value: Promise<IDBPDatabase>): IDBOpenDBRequest;
<T>(value: Promise<T>): IDBRequest<T>;
}
export const unwrap: Unwrap = (value: any): any =>
reverseTransformCache.get(value);

View file

@ -24,9 +24,9 @@ import {
set,
} from "@api/DataStore";
import { sleep } from "@utils/misc";
import { LoggedAttachment } from "userplugins/vc-message-logger-enhanced/types";
import { Flogger, Native } from "../..";
import { LoggedAttachment } from "../../types";
import { DEFAULT_IMAGE_CACHE_DIR } from "../constants";
const ImageStore = createStore("MessageLoggerImageData", "MessageLoggerImageStore");