mirror of
https://github.com/trailbaseio/trailbase.git
synced 2026-01-31 14:18:52 -06:00
Add WebSocket subscription API and tests to JS/TS client.
This commit is contained in:
@@ -37,10 +37,10 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.2",
|
||||
"eslint": "^9.39.2",
|
||||
"execa": "^9.6.1",
|
||||
"globals": "^17.0.0",
|
||||
"http-status": "^2.1.0",
|
||||
"jsdom": "^27.4.0",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"oauth2-mock-server": "^8.2.0",
|
||||
"prettier": "^3.8.0",
|
||||
"tinybench": "^6.0.0",
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { LoginStatusResponse } from "@bindings/LoginStatusResponse";
|
||||
import type { LogoutRequest } from "@bindings/LogoutRequest";
|
||||
import type { RefreshRequest } from "@bindings/RefreshRequest";
|
||||
import type { RefreshResponse } from "@bindings/RefreshResponse";
|
||||
import type { WsProtocol } from "@bindings/WsProtocol";
|
||||
|
||||
export type User = {
|
||||
id: string;
|
||||
@@ -521,6 +522,70 @@ export class RecordApiImpl<
|
||||
|
||||
return body.pipeThrough(transformStream);
|
||||
}
|
||||
|
||||
async subscribeWs(
|
||||
id: RecordId,
|
||||
opts?: SubscribeOpts,
|
||||
): Promise<ReadableStream<Event>> {
|
||||
const params = new URLSearchParams();
|
||||
params.append("ws", "true");
|
||||
|
||||
const filters = opts?.filters ?? [];
|
||||
if (filters.length > 0) {
|
||||
for (const filter of filters) {
|
||||
addFiltersToParams(params, "filter", filter);
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise<ReadableStream<Event>>((resolve, reject) => {
|
||||
const host = this.client.base?.host ?? "";
|
||||
const protocol = this.client.base?.protocol === "https" ? "wss" : "ws";
|
||||
const url = `${protocol}://${host}${recordApiBasePath}/${this.name}/subscribe/${id}?${params}`;
|
||||
|
||||
const socket = new WebSocket(url);
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
reject("WS connection timeout");
|
||||
}, 5000);
|
||||
|
||||
const readable = new ReadableStream({
|
||||
start: (controller) => {
|
||||
socket.addEventListener("open", (_openEvent) => {
|
||||
// Initialize connection and authenticate.
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
Init: {
|
||||
auth_token: this.client.tokens()?.auth_token ?? null,
|
||||
},
|
||||
} as WsProtocol),
|
||||
);
|
||||
|
||||
clearTimeout(timeout);
|
||||
resolve(readable);
|
||||
});
|
||||
|
||||
socket.addEventListener("close", () => {
|
||||
controller.close();
|
||||
});
|
||||
|
||||
socket.addEventListener("error", (err) => {
|
||||
controller.error(err);
|
||||
});
|
||||
|
||||
// Listen for messages
|
||||
socket.addEventListener("message", (event) => {
|
||||
if (typeof event.data !== "string") {
|
||||
new Error("expected JSON string");
|
||||
}
|
||||
controller.enqueue(JSON.parse(event.data));
|
||||
});
|
||||
},
|
||||
cancel: () => {
|
||||
socket.close();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ThinClient {
|
||||
@@ -629,7 +694,8 @@ class ClientImpl implements Client {
|
||||
}
|
||||
|
||||
public get base(): URL | undefined {
|
||||
return this._client.base;
|
||||
const b = this._client.base;
|
||||
return b !== undefined ? new URL(b) : undefined;
|
||||
}
|
||||
|
||||
/// Low-level access to tokens (auth, refresh, csrf) useful for persisting them.
|
||||
@@ -958,6 +1024,7 @@ export const exportedForTesting = isDev
|
||||
? {
|
||||
base64Decode,
|
||||
base64Encode,
|
||||
subscribeWs: (api: RecordApiImpl, id: RecordId) => api.subscribeWs(id),
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export const PORT: number = 4005;
|
||||
export const ADDRESS: string = `127.0.0.1:${PORT}`;
|
||||
export const USE_WS: boolean = false;
|
||||
|
||||
@@ -7,12 +7,12 @@ import {
|
||||
initClient,
|
||||
urlSafeBase64Encode,
|
||||
} from "../../src/index";
|
||||
import type { Client, Event } from "../../src/index";
|
||||
import type { Client, Event, RecordApiImpl } from "../../src/index";
|
||||
import { status } from "http-status";
|
||||
import { v7 as uuidv7, parse as uuidParse } from "uuid";
|
||||
import { ADDRESS } from "../constants";
|
||||
import { ADDRESS, USE_WS } from "../constants";
|
||||
|
||||
const { base64Encode } = exportedForTesting!;
|
||||
const { base64Encode, subscribeWs } = exportedForTesting!;
|
||||
|
||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
@@ -484,6 +484,41 @@ test("Subscribe to entire table", async () => {
|
||||
expect(events[2]["Delete"]["text_not_null"]).equals(updatedMessage);
|
||||
});
|
||||
|
||||
if (USE_WS) {
|
||||
test("Subscribe to entire table via WebSocket", async () => {
|
||||
const client = await connect();
|
||||
const api = client.records<NewSimpleStrict>("simple_strict_table");
|
||||
|
||||
const eventStream = await subscribeWs(api as RecordApiImpl, "*");
|
||||
|
||||
const now = new Date().getTime();
|
||||
const createMessage = `ts client ws realtime test 0: =?&${now}`;
|
||||
const id = (await api.create({
|
||||
text_not_null: createMessage,
|
||||
})) as string;
|
||||
|
||||
const updatedMessage = `ts client ws updated realtime test 0: ${now}`;
|
||||
const updatedValue: Partial<SimpleStrict> = {
|
||||
text_not_null: updatedMessage,
|
||||
};
|
||||
await api.update(id, updatedValue);
|
||||
await api.delete(id);
|
||||
|
||||
const events: Event[] = [];
|
||||
for await (const event of eventStream) {
|
||||
events.push(event);
|
||||
if (events.length === 3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expect(events).toHaveLength(3);
|
||||
expect(events[0]["Insert"]["text_not_null"]).equals(createMessage);
|
||||
expect(events[1]["Update"]["text_not_null"]).equals(updatedMessage);
|
||||
expect(events[2]["Delete"]["text_not_null"]).equals(updatedMessage);
|
||||
});
|
||||
}
|
||||
|
||||
test("Subscribe to table with record filters", async () => {
|
||||
const client = await connect();
|
||||
const api = client.records<NewSimpleStrict>("simple_strict_table");
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
import { createVitest } from "vitest/node";
|
||||
import { cwd } from "node:process";
|
||||
import { join } from "node:path";
|
||||
import { execa, type Subprocess } from "execa";
|
||||
import { existsSync } from "node:fs";
|
||||
import type { ChildProcess } from "node:child_process";
|
||||
import { join, resolve } from "node:path";
|
||||
import spawn from "nano-spawn";
|
||||
|
||||
import { ADDRESS, PORT } from "./constants";
|
||||
import { ADDRESS, PORT, USE_WS } from "./constants";
|
||||
|
||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
async function initTrailBase(): Promise<{ subprocess: Subprocess | null }> {
|
||||
async function initTrailBase(): Promise<{ subprocess: ChildProcess | null }> {
|
||||
if (PORT === 4000) {
|
||||
// Rely on externally bootstrapped instance.
|
||||
return { subprocess: null };
|
||||
@@ -20,31 +22,42 @@ async function initTrailBase(): Promise<{ subprocess: Subprocess | null }> {
|
||||
throw Error(`Unexpected CWD: ${pwd}`);
|
||||
}
|
||||
|
||||
const root = join(pwd, "..", "..", "..", "..");
|
||||
|
||||
const build = await execa({ cwd: root })`cargo build`;
|
||||
if (build.failed) {
|
||||
console.error("STDOUT:", build.stdout);
|
||||
console.error("STDERR:", build.stderr);
|
||||
throw Error("cargo build failed");
|
||||
const root = resolve(__dirname, "../../../../..");
|
||||
if (!existsSync(`${root}/Cargo.lock`)) {
|
||||
throw new Error(root);
|
||||
}
|
||||
|
||||
const subprocess = execa({
|
||||
const features = USE_WS ? ["--features=ws"] : [];
|
||||
await spawn("cargo", ["build", ...features], { cwd: root });
|
||||
|
||||
const args = [
|
||||
"run",
|
||||
...features,
|
||||
"--",
|
||||
"--data-dir=client/testfixture",
|
||||
`--public-url=http://${ADDRESS}`,
|
||||
"run",
|
||||
`--address=${ADDRESS}`,
|
||||
"--runtime-threads=1",
|
||||
];
|
||||
|
||||
const subprocess = spawn("cargo", args, {
|
||||
cwd: root,
|
||||
stdout: process.stdout,
|
||||
stderr: process.stdout,
|
||||
})`cargo run -- --data-dir client/testfixture --public-url http://${ADDRESS} run -a ${ADDRESS} --runtime-threads 1`;
|
||||
});
|
||||
|
||||
// NOTE: debug builds of trail loading JS-WASM can take a long time.
|
||||
for (let i = 0; i < 300; ++i) {
|
||||
if ((subprocess.exitCode ?? 0) > 0) {
|
||||
const child = await subprocess.nodeChildProcess;
|
||||
if ((child.exitCode ?? 0) > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`http://${ADDRESS}/api/healthcheck`);
|
||||
if (response.ok) {
|
||||
return { subprocess };
|
||||
return { subprocess: child };
|
||||
}
|
||||
|
||||
console.log(await response.text());
|
||||
@@ -55,10 +68,10 @@ async function initTrailBase(): Promise<{ subprocess: Subprocess | null }> {
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
subprocess.kill();
|
||||
const child = await subprocess.nodeChildProcess;
|
||||
child.kill();
|
||||
|
||||
const result = await subprocess;
|
||||
console.error("EXIT:", result.exitCode);
|
||||
console.error("STDOUT:", result.stdout);
|
||||
console.error("STDERR:", result.stderr);
|
||||
|
||||
|
||||
106
pnpm-lock.yaml
generated
106
pnpm-lock.yaml
generated
@@ -248,9 +248,6 @@ importers:
|
||||
eslint:
|
||||
specifier: ^9.39.2
|
||||
version: 9.39.2(jiti@2.6.1)
|
||||
execa:
|
||||
specifier: ^9.6.1
|
||||
version: 9.6.1
|
||||
globals:
|
||||
specifier: ^17.0.0
|
||||
version: 17.0.0
|
||||
@@ -260,6 +257,9 @@ importers:
|
||||
jsdom:
|
||||
specifier: ^27.4.0
|
||||
version: 27.4.0
|
||||
nano-spawn:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
oauth2-mock-server:
|
||||
specifier: ^8.2.0
|
||||
version: 8.2.0
|
||||
@@ -2352,9 +2352,6 @@ packages:
|
||||
'@rushstack/ts-command-line@5.1.5':
|
||||
resolution: {integrity: sha512-YmrFTFUdHXblYSa+Xc9OO9FsL/XFcckZy0ycQ6q7VSBsVs5P0uD9vcges5Q9vctGlVdu27w+Ct6IuJ458V0cTQ==}
|
||||
|
||||
'@sec-ant/readable-stream@0.4.1':
|
||||
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
||||
|
||||
'@shikijs/core@3.21.0':
|
||||
resolution: {integrity: sha512-AXSQu/2n1UIQekY8euBJlvFYZIw0PHY63jUzGbrOma4wPxzznJXTXkri+QcHeBNaFxiiOljKxxJkVSoB3PjbyA==}
|
||||
|
||||
@@ -2376,10 +2373,6 @@ packages:
|
||||
'@shikijs/vscode-textmate@10.0.2':
|
||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||
|
||||
'@sindresorhus/merge-streams@4.0.0':
|
||||
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@solid-devtools/debugger@0.23.4':
|
||||
resolution: {integrity: sha512-EfTB1Eo313wztQYGJ4Ec/wE70Ay2d603VCXfT3RlyqO5QfLrQGRHX5NXC07hJpQTJJJ3tbNgzO7+ZKo76MM5uA==}
|
||||
peerDependencies:
|
||||
@@ -3870,10 +3863,6 @@ packages:
|
||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
engines: {node: '>=0.8.x'}
|
||||
|
||||
execa@9.6.1:
|
||||
resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==}
|
||||
engines: {node: ^18.19.0 || >=20.5.0}
|
||||
|
||||
expect-type@1.3.0:
|
||||
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -3931,10 +3920,6 @@ packages:
|
||||
picomatch:
|
||||
optional: true
|
||||
|
||||
figures@6.1.0:
|
||||
resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
@@ -4035,10 +4020,6 @@ packages:
|
||||
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
get-stream@9.0.1:
|
||||
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
github-slugger@2.0.0:
|
||||
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
|
||||
|
||||
@@ -4219,10 +4200,6 @@ packages:
|
||||
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
human-signals@8.0.1:
|
||||
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
|
||||
i18n-iso-countries@7.14.0:
|
||||
resolution: {integrity: sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg==}
|
||||
engines: {node: '>= 12'}
|
||||
@@ -4349,10 +4326,6 @@ packages:
|
||||
is-promise@4.0.0:
|
||||
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
|
||||
|
||||
is-stream@4.0.1:
|
||||
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
is-unicode-supported@1.3.0:
|
||||
resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -4934,10 +4907,6 @@ packages:
|
||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
npm-run-path@6.0.0:
|
||||
resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
|
||||
@@ -5042,10 +5011,6 @@ packages:
|
||||
parse-latin@7.0.0:
|
||||
resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
|
||||
|
||||
parse-ms@4.0.0:
|
||||
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||
resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
|
||||
|
||||
@@ -5080,10 +5045,6 @@ packages:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-key@4.0.0:
|
||||
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
|
||||
@@ -5221,10 +5182,6 @@ packages:
|
||||
resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||
|
||||
pretty-ms@9.3.0:
|
||||
resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
prismjs@1.30.0:
|
||||
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -5701,10 +5658,6 @@ packages:
|
||||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
strip-final-newline@4.0.0:
|
||||
resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
strip-indent@3.0.0:
|
||||
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -6010,10 +5963,6 @@ packages:
|
||||
unicode-trie@2.0.0:
|
||||
resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
|
||||
|
||||
unicorn-magic@0.3.0:
|
||||
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
unified@11.0.5:
|
||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||
|
||||
@@ -8014,8 +7963,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
'@sec-ant/readable-stream@0.4.1': {}
|
||||
|
||||
'@shikijs/core@3.21.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 3.21.0
|
||||
@@ -8049,8 +7996,6 @@ snapshots:
|
||||
|
||||
'@shikijs/vscode-textmate@10.0.2': {}
|
||||
|
||||
'@sindresorhus/merge-streams@4.0.0': {}
|
||||
|
||||
'@solid-devtools/debugger@0.23.4(solid-js@1.9.10)':
|
||||
dependencies:
|
||||
'@nothing-but/utils': 0.12.1
|
||||
@@ -10158,21 +10103,6 @@ snapshots:
|
||||
|
||||
events@3.3.0: {}
|
||||
|
||||
execa@9.6.1:
|
||||
dependencies:
|
||||
'@sindresorhus/merge-streams': 4.0.0
|
||||
cross-spawn: 7.0.6
|
||||
figures: 6.1.0
|
||||
get-stream: 9.0.1
|
||||
human-signals: 8.0.1
|
||||
is-plain-obj: 4.1.0
|
||||
is-stream: 4.0.1
|
||||
npm-run-path: 6.0.0
|
||||
pretty-ms: 9.3.0
|
||||
signal-exit: 4.1.0
|
||||
strip-final-newline: 4.0.0
|
||||
yoctocolors: 2.1.2
|
||||
|
||||
expect-type@1.3.0: {}
|
||||
|
||||
express@5.2.1:
|
||||
@@ -10261,10 +10191,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.3
|
||||
|
||||
figures@6.1.0:
|
||||
dependencies:
|
||||
is-unicode-supported: 2.1.0
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
flat-cache: 4.0.1
|
||||
@@ -10363,11 +10289,6 @@ snapshots:
|
||||
dependencies:
|
||||
pump: 3.0.3
|
||||
|
||||
get-stream@9.0.1:
|
||||
dependencies:
|
||||
'@sec-ant/readable-stream': 0.4.1
|
||||
is-stream: 4.0.1
|
||||
|
||||
github-slugger@2.0.0: {}
|
||||
|
||||
glob-parent@5.1.2:
|
||||
@@ -10680,8 +10601,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
human-signals@8.0.1: {}
|
||||
|
||||
i18n-iso-countries@7.14.0:
|
||||
dependencies:
|
||||
diacritics: 1.3.0
|
||||
@@ -10775,8 +10694,6 @@ snapshots:
|
||||
|
||||
is-promise@4.0.0: {}
|
||||
|
||||
is-stream@4.0.1: {}
|
||||
|
||||
is-unicode-supported@1.3.0: {}
|
||||
|
||||
is-unicode-supported@2.1.0: {}
|
||||
@@ -11557,11 +11474,6 @@ snapshots:
|
||||
|
||||
normalize-path@3.0.0: {}
|
||||
|
||||
npm-run-path@6.0.0:
|
||||
dependencies:
|
||||
path-key: 4.0.0
|
||||
unicorn-magic: 0.3.0
|
||||
|
||||
nth-check@2.1.1:
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
@@ -11712,8 +11624,6 @@ snapshots:
|
||||
unist-util-visit-children: 3.0.0
|
||||
vfile: 6.0.3
|
||||
|
||||
parse-ms@4.0.0: {}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
@@ -11743,8 +11653,6 @@ snapshots:
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-key@4.0.0: {}
|
||||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
path-to-regexp@8.3.0: {}
|
||||
@@ -11827,10 +11735,6 @@ snapshots:
|
||||
ansi-styles: 5.2.0
|
||||
react-is: 17.0.2
|
||||
|
||||
pretty-ms@9.3.0:
|
||||
dependencies:
|
||||
parse-ms: 4.0.0
|
||||
|
||||
prismjs@1.30.0: {}
|
||||
|
||||
process@0.11.10: {}
|
||||
@@ -12537,8 +12441,6 @@ snapshots:
|
||||
|
||||
strip-bom@3.0.0: {}
|
||||
|
||||
strip-final-newline@4.0.0: {}
|
||||
|
||||
strip-indent@3.0.0:
|
||||
dependencies:
|
||||
min-indent: 1.0.1
|
||||
@@ -12858,8 +12760,6 @@ snapshots:
|
||||
pako: 0.2.9
|
||||
tiny-inflate: 1.0.3
|
||||
|
||||
unicorn-magic@0.3.0: {}
|
||||
|
||||
unified@11.0.5:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
Reference in New Issue
Block a user