From 82a8bd628f9b85e6b085523c25978c0ceb0cfab4 Mon Sep 17 00:00:00 2001 From: Ryan Morshead Date: Thu, 23 Mar 2023 16:07:30 -0700 Subject: [PATCH] rewrite the client in typescript (#951) * initial work to rewrite the client in typescript * minor fixes * fix js tests * misc fixes * rewrite event-to-object * rewrite event-to-object tests * finish tests * improve typescript configuration * show npm version * workspace order * minor fixes * rework docs extension + misc changes * build before check types * fix typos * move client under namespace dir * fix types in noxfile --- .pre-commit-config.yaml | 2 +- docs/source/_custom_js/package-lock.json | 55 +- docs/source/_custom_js/package.json | 2 +- docs/source/_custom_js/src/index.js | 26 +- noxfile.py | 110 +- src/client/.gitignore | 2 + src/client/{ => apps/ui}/index.html | 10 +- src/client/apps/ui/package.json | 30 + .../ui}/public/assets/reactpy-logo.ico | Bin src/client/apps/ui/src/index.ts | 14 + src/client/apps/ui/tsconfig.json | 14 + src/client/{ => apps/ui}/vite.config.js | 4 +- src/client/package-lock.json | 2873 ++++------------- src/client/package.json | 21 +- .../packages/{ => @reactpy}/client/.gitignore | 0 .../packages/{ => @reactpy}/client/README.md | 0 .../packages/@reactpy/client/package.json | 37 + .../@reactpy/client/src/components.tsx | 231 ++ .../packages/@reactpy/client/src/index.ts | 5 + .../packages/@reactpy/client/src/logger.ts | 5 + .../packages/@reactpy/client/src/messages.ts | 32 + .../packages/@reactpy/client/src/mount.tsx | 8 + .../@reactpy/client/src/reactpy-client.ts | 274 ++ .../@reactpy/client/src/reactpy-vdom.tsx | 261 ++ .../packages/@reactpy/client/tsconfig.json | 14 + src/client/packages/app/package-lock.json | 65 - src/client/packages/app/package.json | 23 - src/client/packages/app/src/index.js | 34 - src/client/packages/client/package.json | 35 - src/client/packages/client/src/components.js | 220 -- src/client/packages/client/src/contexts.js | 6 - .../packages/client/src/element-utils.js | 82 - .../packages/client/src/event-to-object.js | 240 -- .../packages/client/src/import-source.js | 134 - src/client/packages/client/src/index.js | 4 - src/client/packages/client/src/mount.js | 105 - src/client/packages/client/src/server.js | 46 - .../client/tests/event-to-object.test.js | 353 -- .../packages/client/tests/tooling/dom.js | 16 - .../packages/event-to-object/package.json | 34 + .../packages/event-to-object/src/events.ts | 263 ++ .../packages/event-to-object/src/index.ts | 427 +++ .../tests/event-to-object.test.ts | 381 +++ .../event-to-object/tests/tooling/check.ts | 47 + .../event-to-object/tests/tooling/mock.ts | 61 + .../tests/tooling/setup.js | 5 +- .../packages/event-to-object/tsconfig.json | 9 + .../event-to-object/tsconfig.tests.json | 16 + src/client/tsconfig.package.json | 20 + tests/test_backend/test_utils.py | 2 +- tests/test_sample.py | 1 - 51 files changed, 2947 insertions(+), 3712 deletions(-) create mode 100644 src/client/.gitignore rename src/client/{ => apps/ui}/index.html (69%) create mode 100644 src/client/apps/ui/package.json rename src/client/{ => apps/ui}/public/assets/reactpy-logo.ico (100%) create mode 100644 src/client/apps/ui/src/index.ts create mode 100644 src/client/apps/ui/tsconfig.json rename src/client/{ => apps/ui}/vite.config.js (66%) rename src/client/packages/{ => @reactpy}/client/.gitignore (100%) rename src/client/packages/{ => @reactpy}/client/README.md (100%) create mode 100644 src/client/packages/@reactpy/client/package.json create mode 100644 src/client/packages/@reactpy/client/src/components.tsx create mode 100644 src/client/packages/@reactpy/client/src/index.ts create mode 100644 src/client/packages/@reactpy/client/src/logger.ts create mode 100644 src/client/packages/@reactpy/client/src/messages.ts create mode 100644 src/client/packages/@reactpy/client/src/mount.tsx create mode 100644 src/client/packages/@reactpy/client/src/reactpy-client.ts create mode 100644 src/client/packages/@reactpy/client/src/reactpy-vdom.tsx create mode 100644 src/client/packages/@reactpy/client/tsconfig.json delete mode 100644 src/client/packages/app/package-lock.json delete mode 100644 src/client/packages/app/package.json delete mode 100644 src/client/packages/app/src/index.js delete mode 100644 src/client/packages/client/package.json delete mode 100644 src/client/packages/client/src/components.js delete mode 100644 src/client/packages/client/src/contexts.js delete mode 100644 src/client/packages/client/src/element-utils.js delete mode 100644 src/client/packages/client/src/event-to-object.js delete mode 100644 src/client/packages/client/src/import-source.js delete mode 100644 src/client/packages/client/src/index.js delete mode 100644 src/client/packages/client/src/mount.js delete mode 100644 src/client/packages/client/src/server.js delete mode 100644 src/client/packages/client/tests/event-to-object.test.js delete mode 100644 src/client/packages/client/tests/tooling/dom.js create mode 100644 src/client/packages/event-to-object/package.json create mode 100644 src/client/packages/event-to-object/src/events.ts create mode 100644 src/client/packages/event-to-object/src/index.ts create mode 100644 src/client/packages/event-to-object/tests/event-to-object.test.ts create mode 100644 src/client/packages/event-to-object/tests/tooling/check.ts create mode 100644 src/client/packages/event-to-object/tests/tooling/mock.ts rename src/client/packages/{client => event-to-object}/tests/tooling/setup.js (79%) create mode 100644 src/client/packages/event-to-object/tsconfig.json create mode 100644 src/client/packages/event-to-object/tsconfig.tests.json create mode 100644 src/client/tsconfig.package.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9a67422d5..b28e5d978 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,6 +9,6 @@ repos: - id: isort name: isort - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.0.0-alpha.4 + rev: v3.0.0-alpha.6 hooks: - id: prettier diff --git a/docs/source/_custom_js/package-lock.json b/docs/source/_custom_js/package-lock.json index 5e8cdba10..5df90e9fb 100644 --- a/docs/source/_custom_js/package-lock.json +++ b/docs/source/_custom_js/package-lock.json @@ -8,7 +8,7 @@ "name": "reactpy-docs-example-loader", "version": "1.0.0", "dependencies": { - "@reactpy/client": "file:../../../src/client/packages/client" + "@reactpy/client": "file:../../../src/client/packages/@reactpy/client" }, "devDependencies": { "@rollup/plugin-commonjs": "^21.0.1", @@ -19,46 +19,48 @@ } }, "../../../src/client/packages/@reactpy/client": { - "version": "0.44.0", + "version": "0.2.0", "integrity": "sha512-pIK5eNwFSHKXg7ClpASWFVKyZDYxz59MSFpVaX/OqJFkrJaAxBuhKGXNTMXmuyWOL5Iyvb/ErwwDRxQRzMNkfQ==", - "extraneous": true, "license": "MIT", "dependencies": { - "fast-json-patch": "^3.0.0-1", - "htm": "^3.0.3" + "event-to-object": "^0.1.0", + "json-pointer": "^0.6.2" }, "devDependencies": { - "jsdom": "16.5.0", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" }, "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" + "react": ">=16 <18", + "react-dom": ">=16 <18" } }, "../../../src/client/packages/client": { "name": "@reactpy/client", - "version": "1.0.0-a6", + "version": "0.2.0", + "extraneous": true, "license": "MIT", "dependencies": { - "htm": "^3.0.3", + "event-to-object": "^0.1.0", "json-pointer": "^0.6.2" }, "devDependencies": { - "jsdom": "16.5.0", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" }, "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" + "react": ">=16 <18", + "react-dom": ">=16 <18" } }, "node_modules/@reactpy/client": { - "resolved": "../../../src/client/packages/client", + "resolved": "../../../src/client/packages/@reactpy/client", "link": true }, "node_modules/@rollup/plugin-commonjs": { @@ -433,14 +435,15 @@ }, "dependencies": { "@reactpy/client": { - "version": "file:../../../src/client/packages/client", + "version": "file:../../../src/client/packages/@reactpy/client", "requires": { - "htm": "^3.0.3", - "jsdom": "16.5.0", + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "event-to-object": "^0.1.0", "json-pointer": "^0.6.2", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" } }, "@rollup/plugin-commonjs": { diff --git a/docs/source/_custom_js/package.json b/docs/source/_custom_js/package.json index 5d3e41d13..1d19613f5 100644 --- a/docs/source/_custom_js/package.json +++ b/docs/source/_custom_js/package.json @@ -15,6 +15,6 @@ "rollup": "^2.35.1" }, "dependencies": { - "@reactpy/client": "file:../../../src/client/packages/client" + "@reactpy/client": "file:../../../src/client/packages/@reactpy/client" } } diff --git a/docs/source/_custom_js/src/index.js b/docs/source/_custom_js/src/index.js index 41a21334d..da04d98c7 100644 --- a/docs/source/_custom_js/src/index.js +++ b/docs/source/_custom_js/src/index.js @@ -1,4 +1,4 @@ -import { mountWithLayoutServer, LayoutServerInfo } from "@reactpy/client"; +import { SimpleReactPyClient, mount } from "@reactpy/client"; let didMountDebug = false; @@ -6,7 +6,7 @@ export function mountWidgetExample( mountID, viewID, reactpyServerHost, - useActivateButton + useActivateButton, ) { let reactpyHost, reactpyPort; if (reactpyServerHost) { @@ -16,27 +16,27 @@ export function mountWidgetExample( reactpyPort = window.location.port; } - const serverInfo = new LayoutServerInfo({ - host: reactpyHost, - port: reactpyPort, - path: "/_reactpy/", - query: `view_id=${viewID}`, - secure: window.location.protocol == "https:", + const client = new SimpleReactPyClient({ + serverLocation: { + url: `${window.location.protocol}//${reactpyHost}:${reactpyPort}`, + route: "/", + query: `?view_id=${viewID}`, + }, }); const mountEl = document.getElementById(mountID); let isMounted = false; triggerIfInViewport(mountEl, () => { if (!isMounted) { - activateView(mountEl, serverInfo, useActivateButton); + activateView(mountEl, client, useActivateButton); isMounted = true; } }); } -function activateView(mountEl, serverInfo, useActivateButton) { +function activateView(mountEl, client, useActivateButton) { if (!useActivateButton) { - mountWithLayoutServer(mountEl, serverInfo); + mount(mountEl, client); return; } @@ -51,7 +51,7 @@ function activateView(mountEl, serverInfo, useActivateButton) { mountEl.setAttribute("class", "interactive widget-container"); mountWithLayoutServer(mountEl, serverInfo); } - }) + }), ); function fadeOutElementThenCallback(element, callback) { @@ -87,7 +87,7 @@ function triggerIfInViewport(element, callback) { { root: null, threshold: 0.1, // set offset 0.1 means trigger if atleast 10% of element in viewport - } + }, ); observer.observe(element); diff --git a/noxfile.py b/noxfile.py index 0d1a02ae4..a37549103 100644 --- a/noxfile.py +++ b/noxfile.py @@ -35,7 +35,6 @@ def __call__(self, session: Session) -> Callable[[bool], None]: SRC_DIR = ROOT_DIR / "src" CLIENT_DIR = SRC_DIR / "client" REACTPY_DIR = SRC_DIR / "reactpy" -LANGUAGE_TYPES: list[LanguageName] = ["py", "js"] TAG_PATTERN = re.compile( # start r"^" @@ -46,7 +45,6 @@ def __call__(self, session: Session) -> Callable[[bool], None]: # end r"$" ) -print(TAG_PATTERN.pattern) REMAINING_ARGS = Option(nargs=REMAINDER, type=str) @@ -60,6 +58,7 @@ def __call__(self, session: Session) -> Callable[[bool], None]: def setup_checks(session: Session) -> None: session.install("--upgrade", "pip") session.run("pip", "--version") + session.run("npm", "--version", external=True) @group.setup("check-javascript") @@ -88,6 +87,12 @@ def format(session: Session) -> None: session.run("npm", "run", "format", external=True) +@group.session +def tsc(session: Session) -> None: + session.chdir(CLIENT_DIR) + session.run("npx", "tsc", "-b", "-w", "packages/app", external=True) + + @group.session def example(session: Session) -> None: """Run an example""" @@ -232,21 +237,24 @@ def check_docs(session: Session) -> None: @group.session -def check_javascript_suite(session: Session) -> None: - """Run the Javascript-based test suite and ensure it bundles succesfully""" - session.run("npm", "run", "test", external=True) +def check_javascript_tests(session: Session) -> None: + session.run("npm", "run", "check:tests", external=True) @group.session -def check_javascript_build(session: Session) -> None: - """Run the Javascript-based test suite and ensure it bundles succesfully""" - session.run("npm", "run", "test", external=True) +def check_javascript_format(session: Session) -> None: + session.run("npm", "run", "check:format", external=True) @group.session -def check_javascript_format(session: Session) -> None: - """Check that Javascript style guidelines are being followed""" - session.run("npm", "run", "check-format", external=True) +def check_javascript_types(session: Session) -> None: + session.run("npm", "run", "build", external=True) + session.run("npm", "run", "check:types", external=True) + + +@group.session +def check_javascript_build(session: Session) -> None: + session.run("npm", "run", "build", external=True) @group.session @@ -266,7 +274,17 @@ def build_python(session: Session) -> None: @group.session -def publish(session: Session, dry_run: bool = False) -> None: +def publish( + session: Session, + publish_dry_run: Annotated[ + bool, + Option(help="whether to test the release process"), + ] = False, + publish_fake_tags: Annotated[ + Sequence[str], + Option(nargs="*", type=str, help="fake tags to use for a dry run release"), + ] = (), +) -> None: packages = get_packages(session) release_prep: dict[LanguageName, ReleasePrepFunc] = { @@ -274,8 +292,20 @@ def publish(session: Session, dry_run: bool = False) -> None: "py": prepare_python_release, } + if publish_fake_tags and not publish_dry_run: + session.error("Cannot specify --publish-fake-tags without --publish-dry-run") + + parsed_tags: list[TagInfo] = [] + for tag in publish_fake_tags or get_current_tags(session): + tag_info = parse_tag(tag) + if tag_info is None: + session.error( + f"Invalid tag {tag} - must be of the form --" + ) + parsed_tags.append(tag_info) # type: ignore + publishers: list[tuple[Path, Callable[[bool], None]]] = [] - for tag, tag_pkg, tag_ver in get_current_tags(session): + for tag, tag_pkg, tag_ver in parsed_tags: if tag_pkg not in packages: session.error(f"Tag {tag} references package {tag_pkg} that does not exist") @@ -293,7 +323,7 @@ def publish(session: Session, dry_run: bool = False) -> None: for pkg_path, publish in publishers: session.log(f"Publishing {pkg_path}...") session.chdir(pkg_path) - publish(dry_run) + publish(publish_dry_run) # --- Utilities ------------------------------------------------------------------------ @@ -386,23 +416,28 @@ def get_packages(session: Session) -> dict[str, PackageInfo]: } # collect javascript packages - for pkg in (CLIENT_DIR / "packages").glob("*"): - pkg_json_file = pkg / "package.json" - if not pkg_json_file.exists(): - session.error(f"package.json not found in {pkg}") + js_package_paths: list[Path] = [] + for maybed_pkg in (CLIENT_DIR / "packages").glob("*"): + if not (maybed_pkg / "package.json").exists(): + for nmaybe_namespaced_pkg in maybed_pkg.glob("*"): + if (nmaybe_namespaced_pkg / "package.json").exists(): + js_package_paths.append(nmaybe_namespaced_pkg) + else: + js_package_paths.append(maybed_pkg) + + # get javascript package info + for pkg in js_package_paths: + pkg_json_file = pkg / "package.json" # we already know this exists pkg_json = json.loads(pkg_json_file.read_text()) pkg_name = pkg_json.get("name") pkg_version = pkg_json.get("version") - if pkg_version is None: - session.log(f"Skipping - {pkg_name} has no name or version in package.json") + if pkg_version is None or pkg_name is None: + session.log(f"Skipping - {pkg_name} has no name/version in package.json") continue - if pkg_name is None: - session.error(f"Package {pkg} has no name in package.json") - if pkg_name in packages: session.error(f"Duplicate package name {pkg_name}") @@ -417,7 +452,7 @@ class PackageInfo(NamedTuple): version: str -def get_current_tags(session: Session) -> list[TagInfo]: +def get_current_tags(session: Session) -> list[str]: """Get tags for the current commit""" # check if unstaged changes try: @@ -465,24 +500,16 @@ def get_current_tags(session: Session) -> list[TagInfo]: if not tags: session.error("No tags found for current commit") - parsed_tags: list[TagInfo] = [] - for tag in tags: - match = TAG_PATTERN.match(tag) - if not match: - session.error( - f"Invalid tag {tag} - must be of the form --" - ) - parsed_tags.append( - TagInfo( - tag, - match["name"], # type: ignore[index] - match["version"], # type: ignore[index] - ) - ) + session.log(f"Found tags: {tags}") + + return tags - session.log(f"Found tags: {[info.tag for info in parsed_tags]}") - return parsed_tags +def parse_tag(tag: str) -> TagInfo | None: + match = TAG_PATTERN.match(tag) + if not match: + return None + return TagInfo(tag, match["name"], match["version"]) class TagInfo(NamedTuple): @@ -506,5 +533,4 @@ def get_reactpy_package_version(session: Session) -> str: # type: ignore[return # remove the quotes [1:-1] ) - else: - session.error(f"No version found in {pkg_root_init_file}") + session.error(f"No version found in {pkg_root_init_file}") diff --git a/src/client/.gitignore b/src/client/.gitignore new file mode 100644 index 000000000..52128d3e1 --- /dev/null +++ b/src/client/.gitignore @@ -0,0 +1,2 @@ +tsconfig.tsbuildinfo +packages/**/package-lock.json diff --git a/src/client/index.html b/src/client/apps/ui/index.html similarity index 69% rename from src/client/index.html rename to src/client/apps/ui/index.html index a7a3cff4f..e94280368 100644 --- a/src/client/index.html +++ b/src/client/apps/ui/index.html @@ -1,15 +1,15 @@ - + + {__head__}
- diff --git a/src/client/apps/ui/package.json b/src/client/apps/ui/package.json new file mode 100644 index 000000000..28d233ad4 --- /dev/null +++ b/src/client/apps/ui/package.json @@ -0,0 +1,30 @@ +{ + "author": "Ryan Morshead", + "license": "MIT", + "main": "src/dist/index.js", + "types": "src/dist/index.d.ts", + "description": "A client application for ReactPy implemented in React", + "dependencies": { + "@reactpy/client": "^0.2.0", + "preact": "^10.7.0" + }, + "devDependencies": { + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5", + "vite": "^3.1.8" + }, + "repository": { + "type": "git", + "url": "https://github.com/reactive-python/reactpy" + }, + "scripts": { + "build": "vite build", + "format": "prettier --write .", + "test": "npm run check:tests", + "check:format": "prettier --check .", + "check:tests": "echo 'no tests'", + "check:types": "tsc --noEmit" + } +} diff --git a/src/client/public/assets/reactpy-logo.ico b/src/client/apps/ui/public/assets/reactpy-logo.ico similarity index 100% rename from src/client/public/assets/reactpy-logo.ico rename to src/client/apps/ui/public/assets/reactpy-logo.ico diff --git a/src/client/apps/ui/src/index.ts b/src/client/apps/ui/src/index.ts new file mode 100644 index 000000000..8a19c53f9 --- /dev/null +++ b/src/client/apps/ui/src/index.ts @@ -0,0 +1,14 @@ +import { mount, SimpleReactPyClient } from "@reactpy/client"; + +export function app(element: HTMLElement) { + mount( + element, + new SimpleReactPyClient({ + serverLocation: { + url: document.location.origin, + route: document.location.pathname, + query: document.location.search, + }, + }), + ); +} diff --git a/src/client/apps/ui/tsconfig.json b/src/client/apps/ui/tsconfig.json new file mode 100644 index 000000000..397ee2d69 --- /dev/null +++ b/src/client/apps/ui/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.package.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "composite": true + }, + "include": ["src"], + "references": [ + { + "path": "../../packages/@reactpy/client" + } + ] +} diff --git a/src/client/vite.config.js b/src/client/apps/ui/vite.config.js similarity index 66% rename from src/client/vite.config.js rename to src/client/apps/ui/vite.config.js index 7bfe66bca..aaa3e80b2 100644 --- a/src/client/vite.config.js +++ b/src/client/apps/ui/vite.config.js @@ -1,12 +1,12 @@ import { defineConfig } from "vite"; export default defineConfig({ - build: { outDir: "../reactpy/_client", emptyOutDir: true }, + build: { outDir: "../../../reactpy/_client", emptyOutDir: true }, resolve: { alias: { react: "preact/compat", "react-dom": "preact/compat", }, }, - base: "/_reactpy", + base: "/_reactpy/", }); diff --git a/src/client/package-lock.json b/src/client/package-lock.json index 1570074f6..d2c013aa9 100644 --- a/src/client/package-lock.json +++ b/src/client/package-lock.json @@ -1,23 +1,34 @@ { "name": "client", - "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "1.0.0", "license": "MIT", "workspaces": [ - "./packages/*" - ], + "packages/event-to-object", + "packages/@reactpy/client", + "apps/ui" + ] + }, + "apps/ui": { + "license": "MIT", + "dependencies": { + "@reactpy/client": "^0.2.0", + "preact": "^10.7.0" + }, "devDependencies": { + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5", "vite": "^3.1.8" } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", - "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", "cpu": [ "arm" ], @@ -31,9 +42,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", - "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "cpu": [ "loong64" ], @@ -46,284 +57,119 @@ "node": ">=12" } }, - "node_modules/@reactpy/app": { - "resolved": "packages/app", - "link": true - }, "node_modules/@reactpy/client": { - "resolved": "packages/client", + "resolved": "packages/@reactpy/client", "link": true }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "node_modules/@types/json-pointer": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/@types/json-pointer/-/json-pointer-1.0.31.tgz", + "integrity": "sha512-hTPul7Um6LqsHXHQpdkXTU7Oysjsf+9k4Yfmg6JhSKG/jj9QuQGyMUdj6trPH6WHiIdxw7nYSROgOxeFmCVK2w==", "dev": true }, - "node_modules/bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/@types/react": { + "version": "17.0.53", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", + "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", "dev": true, "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" } }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/@types/react-dom": { + "version": "17.0.19", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", + "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", "dev": true, "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" + "@types/react": "^17" } }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "dev": true }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", "dev": true }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/dequal": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", - "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true, "engines": { "node": ">=0.3.1" } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "node_modules/esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "node_modules/esbuild-android-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", - "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "cpu": [ "x64" ], @@ -337,9 +183,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", - "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "cpu": [ "arm64" ], @@ -353,9 +199,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", - "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "cpu": [ "x64" ], @@ -369,9 +215,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", - "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "cpu": [ "arm64" ], @@ -385,9 +231,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", - "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "cpu": [ "x64" ], @@ -401,9 +247,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", - "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "cpu": [ "arm64" ], @@ -417,9 +263,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", - "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "cpu": [ "ia32" ], @@ -433,9 +279,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", - "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "cpu": [ "x64" ], @@ -449,9 +295,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", - "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "cpu": [ "arm" ], @@ -465,9 +311,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", - "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "cpu": [ "arm64" ], @@ -481,9 +327,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", - "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "cpu": [ "mips64el" ], @@ -497,9 +343,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", - "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "cpu": [ "ppc64" ], @@ -513,9 +359,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", - "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "cpu": [ "riscv64" ], @@ -529,9 +375,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", - "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "cpu": [ "s390x" ], @@ -545,9 +391,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", - "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "cpu": [ "x64" ], @@ -561,9 +407,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", - "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "cpu": [ "x64" ], @@ -577,9 +423,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", - "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "cpu": [ "x64" ], @@ -593,9 +439,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", - "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "cpu": [ "ia32" ], @@ -609,9 +455,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", - "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "cpu": [ "x64" ], @@ -625,9 +471,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", - "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "cpu": [ "arm64" ], @@ -640,130 +486,15 @@ "node": ">=12" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "node_modules/event-to-object": { + "resolved": "packages/event-to-object", + "link": true }, "node_modules/foreach": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -784,36 +515,19 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", + "node_modules/happy-dom": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-8.9.0.tgz", + "integrity": "sha512-JZwJuGdR7ko8L61136YzmrLv7LgTh5b8XaEM3P709mLjyQuXJ3zHTDXvUtBBahRjGlcYW0zGjIiEWizoTUGKfA==", "dev": true, "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" + "css.escape": "^1.5.1", + "he": "^1.2.0", + "iconv-lite": "^0.6.3", + "node-fetch": "^2.x.x", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0" } }, "node_modules/has": { @@ -828,45 +542,22 @@ "node": ">= 0.4.0" } }, - "node_modules/htm": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/htm/-/htm-3.0.4.tgz", - "integrity": "sha512-VRdvxX3tmrXuT/Ovt59NMp/ORMFi4bceFMDjos1PV4E0mV+5votuID8R60egR9A4U8nLt238R/snlJGz3UYiTQ==" - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/http-signature": { + "node_modules/he": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "bin": { + "he": "bin/he" } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -884,92 +575,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "node_modules/js-tokens": { "version": "4.0.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "peer": true }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsdom": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.0.tgz", - "integrity": "sha512-QxZH0nmDTnTTVI0YDm4RUlaUPl5dcyn62G5TMDNfMmTW+J1u1v9gCR8WR+WZ6UghAa7nKJjDOFaI00eMMWvJFQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.0.5", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.4.4", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/json-pointer": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", @@ -978,61 +589,15 @@ "foreach": "^2.0.4" } }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/kleur": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", - "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true, "engines": { "node": ">=6" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1041,7 +606,8 @@ }, "node_modules/loose-envify": { "version": "1.4.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -1050,31 +616,10 @@ "loose-envify": "cli.js" } }, - "node_modules/mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", - "dev": true, - "dependencies": { - "mime-db": "1.47.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, "engines": { "node": ">=4" @@ -1092,77 +637,41 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, "engines": { - "node": "*" + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/object-assign": { "version": "4.1.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "peer": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -1170,9 +679,9 @@ "dev": true }, "node_modules/postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "dev": true, "funding": [ { @@ -1194,204 +703,56 @@ } }, "node_modules/preact": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.0.tgz", - "integrity": "sha512-9MEURwzNMKpAil/t6+wabDIJI6oG6GnwypYxiJDvQnW+fHDTt51PYuLZ1QUM31hFr7sDaj9qTaShAF9VIxuxGQ==", + "version": "10.13.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.13.1.tgz", + "integrity": "sha512-KyoXVDU5OqTpG9LXlB3+y639JAGzl8JSBXLn1J9HTSB3gbKcuInga7bZnXLlxmK94ntTs1EFeZp0lrja2AuBYQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" } }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "3.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0-alpha.6.tgz", + "integrity": "sha512-AdbQSZ6Oo+iy9Ekzmsgno05P1uX2vqPkjOMJqRfP8hTe+m6iDw4Nt7bPFpWZ/HYCU+3f0P5U0o2ghxQwwkLH7A==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prop-types": { - "version": "15.7.2", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "node_modules/react": { - "version": "16.14.0", - "license": "MIT", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "peer": true, "dependencies": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "16.14.0", - "license": "MIT", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "peer": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - }, - "peerDependencies": { - "react": "^16.14.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "license": "MIT", - "peer": true - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=0.10.0" + "scheduler": "^0.20.2" }, "peerDependencies": { - "request": "^2.34" + "react": "17.0.2" } }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -1409,59 +770,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/sade": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", - "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, "dependencies": { "mri": "^1.1.0" }, "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/scheduler": { - "version": "0.19.1", - "license": "MIT", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "peer": true, "dependencies": { "loose-envify": "^1.1.0", @@ -1477,35 +822,6 @@ "node": ">=0.10.0" } }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -1518,141 +834,54 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/totalist": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-2.0.0.tgz", - "integrity": "sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "node_modules/tsm": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tsm/-/tsm-2.3.0.tgz", + "integrity": "sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2" + "esbuild": "^0.15.16" + }, + "bin": { + "tsm": "bin.js" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "node": ">=12" } }, - "node_modules/utf-8-validate": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", - "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, - "hasInstallScript": true, - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=6.14.2" + "node": ">=4.2.0" } }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } + "node_modules/ui": { + "resolved": "apps/ui", + "link": true }, "node_modules/uvu": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.1.tgz", - "integrity": "sha512-JGxttnOGDFs77FaZ0yMUHIzczzQ5R1IlDeNW6Wymw6gAscwMdAffVOP6TlxLIfReZyK8tahoGwWZaTCJzNFDkg==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", "dev": true, "dependencies": { "dequal": "^2.0.0", "diff": "^5.0.0", "kleur": "^4.0.3", - "sade": "^1.7.3", - "totalist": "^2.0.0" + "sade": "^1.7.3" }, "bin": { "uvu": "bin.js" @@ -1661,30 +890,16 @@ "node": ">=8" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "node_modules/vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", + "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", "dev": true, "dependencies": { "esbuild": "^0.15.9", - "postcss": "^8.4.16", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "~2.78.0" + "rollup": "^2.79.1" }, "bin": { "vite": "bin/vite.js" @@ -1696,12 +911,17 @@ "fsevents": "~2.3.2" }, "peerDependencies": { + "@types/node": ">= 14", "less": "*", "sass": "*", "stylus": "*", + "sugarss": "*", "terser": "^5.4.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "less": { "optional": true }, @@ -1711,771 +931,420 @@ "stylus": { "optional": true }, + "sugarss": { + "optional": true + }, "terser": { "optional": true } } }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", - "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, "engines": { "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.12", - "@esbuild/linux-loong64": "0.15.12", - "esbuild-android-64": "0.15.12", - "esbuild-android-arm64": "0.15.12", - "esbuild-darwin-64": "0.15.12", - "esbuild-darwin-arm64": "0.15.12", - "esbuild-freebsd-64": "0.15.12", - "esbuild-freebsd-arm64": "0.15.12", - "esbuild-linux-32": "0.15.12", - "esbuild-linux-64": "0.15.12", - "esbuild-linux-arm": "0.15.12", - "esbuild-linux-arm64": "0.15.12", - "esbuild-linux-mips64le": "0.15.12", - "esbuild-linux-ppc64le": "0.15.12", - "esbuild-linux-riscv64": "0.15.12", - "esbuild-linux-s390x": "0.15.12", - "esbuild-netbsd-64": "0.15.12", - "esbuild-openbsd-64": "0.15.12", - "esbuild-sunos-64": "0.15.12", - "esbuild-windows-32": "0.15.12", - "esbuild-windows-64": "0.15.12", - "esbuild-windows-arm64": "0.15.12" - } - }, - "node_modules/vite/node_modules/rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { + "node_modules/whatwg-encoding": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "dependencies": { - "xml-name-validator": "^3.0.0" + "iconv-lite": "0.6.3" }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true, "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" + "node": ">=12" } }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, "node_modules/whatwg-url": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", - "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "node_modules/whatwg-url/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "packages/@reactpy/app": { - "version": "1.0.0", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@reactpy/client": "file:packages/@reactpy/client", - "preact": "^10.7.0" - }, - "devDependencies": { - "prettier": "^2.5.1" - } - }, - "packages/@reactpy/app/packages/@reactpy/client": { - "version": "0.0.1", - "extraneous": true, - "dependencies": { - "fast-json-patch": "^3.0.0-1", - "htm": "^3.0.3", - "jsdom": "16.5.0", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" - } - }, "packages/@reactpy/client": { - "version": "1.0.0", - "extraneous": true, + "version": "0.2.0", "license": "MIT", "dependencies": { - "htm": "^3.0.3", + "event-to-object": "^0.1.0", "json-pointer": "^0.6.2" }, "devDependencies": { - "jsdom": "16.5.0", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" }, "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" + "react": ">=16 <18", + "react-dom": ">=16 <18" } }, "packages/app": { "name": "@reactpy/app", - "version": "0.45.0", + "extraneous": true, "license": "MIT", "dependencies": { - "@reactpy/client": "file:packages/client", + "@reactpy/client": "^0.1.0", "preact": "^10.7.0" }, "devDependencies": { - "prettier": "^2.5.1" + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5", + "vite": "^3.1.8" } }, - "packages/app/node_modules/@reactpy/client": { - "resolved": "packages/app/packages/client", - "link": true - }, - "packages/app/packages/client": {}, "packages/client": { "name": "@reactpy/client", - "version": "0.45.0", + "version": "0.2.0", + "extraneous": true, "license": "MIT", "dependencies": { - "htm": "^3.0.3", + "event-to-object": "^0.1.0", "json-pointer": "^0.6.2" }, "devDependencies": { - "jsdom": "16.5.0", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" }, "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" + "react": ">=16 <18", + "react-dom": ">=16 <18" } }, - "packages/idom-app-react": { - "name": "@reactpy/app", - "version": "1.0.0-a5", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@reactpy/client": "file:packages/@reactpy/client", - "preact": "^10.7.0" - }, - "devDependencies": { - "prettier": "^2.5.1" - } - }, - "packages/idom-app-react/packages/@reactpy/client": { - "extraneous": true - }, - "packages/idom-client-react": { - "name": "@reactpy/client", - "version": "1.0.0-a5", - "extraneous": true, + "packages/event-to-object": { + "version": "0.1.0", "license": "MIT", "dependencies": { - "htm": "^3.0.3", + "event-to-object": "file:packages/event-to-object", "json-pointer": "^0.6.2" }, "devDependencies": { - "jsdom": "16.5.0", + "happy-dom": "^8.9.0", "lodash": "^4.17.21", - "prettier": "^2.5.1", + "prettier": "^3.0.0-alpha.6", + "tsm": "^2.0.0", + "typescript": "^4.9.5", "uvu": "^0.5.1" - }, - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" } - } - }, - "dependencies": { - "@esbuild/android-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.12.tgz", - "integrity": "sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.12.tgz", - "integrity": "sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==", - "dev": true, - "optional": true }, - "@reactpy/app": { - "version": "file:packages/app", - "requires": { - "@reactpy/client": "file:packages/client", - "preact": "^10.7.0", - "prettier": "^2.5.1" - }, - "dependencies": { - "@reactpy/client": { - "version": "file:packages/app/packages/client" - } - } - }, - "@reactpy/client": { - "version": "file:packages/client", - "requires": { - "htm": "^3.0.3", - "jsdom": "16.5.0", - "json-pointer": "^0.6.2", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" - } - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "node-gyp-build": "^4.3.0" - } + "packages/event-to-object/node_modules/event-to-object": { + "resolved": "packages/event-to-object/packages/event-to-object", + "link": true }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "packages/event-to-object/packages/event-to-object": {} + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "dev": true, + "optional": true }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "dev": true, + "optional": true + }, + "@reactpy/client": { + "version": "file:packages/@reactpy/client", "requires": { - "delayed-stream": "~1.0.0" + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "event-to-object": "^0.1.0", + "json-pointer": "^0.6.2", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "@types/json-pointer": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/@types/json-pointer/-/json-pointer-1.0.31.tgz", + "integrity": "sha512-hTPul7Um6LqsHXHQpdkXTU7Oysjsf+9k4Yfmg6JhSKG/jj9QuQGyMUdj6trPH6WHiIdxw7nYSROgOxeFmCVK2w==", "dev": true }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", "dev": true }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "@types/react": { + "version": "17.0.53", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.53.tgz", + "integrity": "sha512-1yIpQR2zdYu1Z/dc1OxC+MA6GR240u3gcnP4l6mvj/PJiVaqHsQPmWttsvHsfnhfPbU2FuGmo0wSITPygjBmsw==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" } }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "@types/react-dom": { + "version": "17.0.19", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", + "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", "dev": true, "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "@types/react": "^17" } }, - "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "dev": true }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", "dev": true }, "dequal": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz", - "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", "dev": true }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "esbuild-android-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.12.tgz", - "integrity": "sha512-MJKXwvPY9g0rGps0+U65HlTsM1wUs9lbjt5CU19RESqycGFDRijMDQsh68MtbzkqWSRdEtiKS1mtPzKneaAI0Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "dev": true, "optional": true }, "esbuild-android-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.12.tgz", - "integrity": "sha512-Hc9SEcZbIMhhLcvhr1DH+lrrec9SFTiRzfJ7EGSBZiiw994gfkVV6vG0sLWqQQ6DD7V4+OggB+Hn0IRUdDUqvA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "dev": true, "optional": true }, "esbuild-darwin-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.12.tgz", - "integrity": "sha512-qkmqrTVYPFiePt5qFjP8w/S+GIUMbt6k8qmiPraECUWfPptaPJUGkCKrWEfYFRWB7bY23FV95rhvPyh/KARP8Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "dev": true, "optional": true }, "esbuild-darwin-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.12.tgz", - "integrity": "sha512-z4zPX02tQ41kcXMyN3c/GfZpIjKoI/BzHrdKUwhC/Ki5BAhWv59A9M8H+iqaRbwpzYrYidTybBwiZAIWCLJAkw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "dev": true, "optional": true }, "esbuild-freebsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.12.tgz", - "integrity": "sha512-XFL7gKMCKXLDiAiBjhLG0XECliXaRLTZh6hsyzqUqPUf/PY4C6EJDTKIeqqPKXaVJ8+fzNek88285krSz1QECw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "dev": true, "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.12.tgz", - "integrity": "sha512-jwEIu5UCUk6TjiG1X+KQnCGISI+ILnXzIzt9yDVrhjug2fkYzlLbl0K43q96Q3KB66v6N1UFF0r5Ks4Xo7i72g==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "dev": true, "optional": true }, "esbuild-linux-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.12.tgz", - "integrity": "sha512-uSQuSEyF1kVzGzuIr4XM+v7TPKxHjBnLcwv2yPyCz8riV8VUCnO/C4BF3w5dHiVpCd5Z1cebBtZJNlC4anWpwA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "dev": true, "optional": true }, "esbuild-linux-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.12.tgz", - "integrity": "sha512-QcgCKb7zfJxqT9o5z9ZUeGH1k8N6iX1Y7VNsEi5F9+HzN1OIx7ESxtQXDN9jbeUSPiRH1n9cw6gFT3H4qbdvcA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "dev": true, "optional": true }, "esbuild-linux-arm": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.12.tgz", - "integrity": "sha512-Wf7T0aNylGcLu7hBnzMvsTfEXdEdJY/hY3u36Vla21aY66xR0MS5I1Hw8nVquXjTN0A6fk/vnr32tkC/C2lb0A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "dev": true, "optional": true }, "esbuild-linux-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.12.tgz", - "integrity": "sha512-HtNq5xm8fUpZKwWKS2/YGwSfTF+339L4aIA8yphNKYJckd5hVdhfdl6GM2P3HwLSCORS++++7++//ApEwXEuAQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "dev": true, "optional": true }, "esbuild-linux-mips64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.12.tgz", - "integrity": "sha512-Qol3+AvivngUZkTVFgLpb0H6DT+N5/zM3V1YgTkryPYFeUvuT5JFNDR3ZiS6LxhyF8EE+fiNtzwlPqMDqVcc6A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "dev": true, "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.12.tgz", - "integrity": "sha512-4D8qUCo+CFKaR0cGXtGyVsOI7w7k93Qxb3KFXWr75An0DHamYzq8lt7TNZKoOq/Gh8c40/aKaxvcZnTgQ0TJNg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "dev": true, "optional": true }, "esbuild-linux-riscv64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.12.tgz", - "integrity": "sha512-G9w6NcuuCI6TUUxe6ka0enjZHDnSVK8bO+1qDhMOCtl7Tr78CcZilJj8SGLN00zO5iIlwNRZKHjdMpfFgNn1VA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "dev": true, "optional": true }, "esbuild-linux-s390x": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.12.tgz", - "integrity": "sha512-Lt6BDnuXbXeqSlVuuUM5z18GkJAZf3ERskGZbAWjrQoi9xbEIsj/hEzVnSAFLtkfLuy2DE4RwTcX02tZFunXww==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "dev": true, "optional": true }, "esbuild-netbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.12.tgz", - "integrity": "sha512-jlUxCiHO1dsqoURZDQts+HK100o0hXfi4t54MNRMCAqKGAV33JCVvMplLAa2FwviSojT/5ZG5HUfG3gstwAG8w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "dev": true, "optional": true }, "esbuild-openbsd-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.12.tgz", - "integrity": "sha512-1o1uAfRTMIWNOmpf8v7iudND0L6zRBYSH45sofCZywrcf7NcZA+c7aFsS1YryU+yN7aRppTqdUK1PgbZVaB1Dw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "dev": true, "optional": true }, "esbuild-sunos-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.12.tgz", - "integrity": "sha512-nkl251DpoWoBO9Eq9aFdoIt2yYmp4I3kvQjba3jFKlMXuqQ9A4q+JaqdkCouG3DHgAGnzshzaGu6xofGcXyPXg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "dev": true, "optional": true }, "esbuild-windows-32": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.12.tgz", - "integrity": "sha512-WlGeBZHgPC00O08luIp5B2SP4cNCp/PcS+3Pcg31kdcJPopHxLkdCXtadLU9J82LCfw4TVls21A6lilQ9mzHrw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "dev": true, "optional": true }, "esbuild-windows-64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.12.tgz", - "integrity": "sha512-VActO3WnWZSN//xjSfbiGOSyC+wkZtI8I4KlgrTo5oHJM6z3MZZBCuFaZHd8hzf/W9KPhF0lY8OqlmWC9HO5AA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "dev": true, "optional": true }, "esbuild-windows-arm64": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.12.tgz", - "integrity": "sha512-Of3MIacva1OK/m4zCNIvBfz8VVROBmQT+gRX6pFTLPngFYcj6TFH/12VveAqq1k9VB2l28EoVMNMUCcmsfwyuA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "dev": true, "optional": true }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, + "event-to-object": { + "version": "file:packages/event-to-object", "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" + "event-to-object": "file:packages/event-to-object", + "happy-dom": "^8.9.0", + "json-pointer": "^0.6.2", + "lodash": "^4.17.21", + "prettier": "^3.0.0-alpha.6", + "tsm": "^2.0.0", + "typescript": "^4.9.5", + "uvu": "^0.5.1" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + "event-to-object": { + "version": "file:packages/event-to-object/packages/event-to-object" } } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, "foreach": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", @@ -2489,29 +1358,19 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "happy-dom": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-8.9.0.tgz", + "integrity": "sha512-JZwJuGdR7ko8L61136YzmrLv7LgTh5b8XaEM3P709mLjyQuXJ3zHTDXvUtBBahRjGlcYW0zGjIiEWizoTUGKfA==", "dev": true, "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "css.escape": "^1.5.1", + "he": "^1.2.0", + "iconv-lite": "^0.6.3", + "node-fetch": "^2.x.x", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0" } }, "has": { @@ -2523,38 +1382,19 @@ "function-bind": "^1.1.1" } }, - "htm": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/htm/-/htm-3.0.4.tgz", - "integrity": "sha512-VRdvxX3tmrXuT/Ovt59NMp/ORMFi4bceFMDjos1PV4E0mV+5votuID8R60egR9A4U8nLt238R/snlJGz3UYiTQ==" - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "http-signature": { + "he": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "is-core-module": { @@ -2566,76 +1406,12 @@ "has": "^1.0.3" } }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "peer": true }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.0.tgz", - "integrity": "sha512-QxZH0nmDTnTTVI0YDm4RUlaUPl5dcyn62G5TMDNfMmTW+J1u1v9gCR8WR+WZ6UghAa7nKJjDOFaI00eMMWvJFQ==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.0.5", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.4.4", - "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - } - } - }, "json-pointer": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/json-pointer/-/json-pointer-0.6.2.tgz", @@ -2644,52 +1420,12 @@ "foreach": "^2.0.4" } }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, "kleur": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz", - "integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "dev": true }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2698,30 +1434,17 @@ }, "loose-envify": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "peer": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } }, - "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", - "dev": true - }, - "mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", - "dev": true, - "requires": { - "mime-db": "1.47.0" - } - }, "mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true }, "nanoid": { @@ -2730,62 +1453,27 @@ "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true }, - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "dev": true, - "optional": true, - "peer": true - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "requires": { + "whatwg-url": "^5.0.0" + } }, "object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "peer": true }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2793,9 +1481,9 @@ "dev": true }, "postcss": { - "version": "8.4.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", - "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "dev": true, "requires": { "nanoid": "^3.3.4", @@ -2804,156 +1492,37 @@ } }, "preact": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.0.tgz", - "integrity": "sha512-9MEURwzNMKpAil/t6+wabDIJI6oG6GnwypYxiJDvQnW+fHDTt51PYuLZ1QUM31hFr7sDaj9qTaShAF9VIxuxGQ==" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true + "version": "10.13.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.13.1.tgz", + "integrity": "sha512-KyoXVDU5OqTpG9LXlB3+y639JAGzl8JSBXLn1J9HTSB3gbKcuInga7bZnXLlxmK94ntTs1EFeZp0lrja2AuBYQ==" }, "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "peer": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "version": "3.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0-alpha.6.tgz", + "integrity": "sha512-AdbQSZ6Oo+iy9Ekzmsgno05P1uX2vqPkjOMJqRfP8hTe+m6iDw4Nt7bPFpWZ/HYCU+3f0P5U0o2ghxQwwkLH7A==", "dev": true }, "react": { - "version": "16.14.0", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "peer": true, "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" } }, "react-dom": { - "version": "16.14.0", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "peer": true, "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" - } - }, - "react-is": { - "version": "16.13.1", - "peer": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" + "scheduler": "^0.20.2" } }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -2965,38 +1534,34 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, "sade": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", - "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", "dev": true, "requires": { "mri": "^1.1.0" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, "scheduler": { - "version": "0.19.1", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "peer": true, "requires": { "loose-envify": "^1.1.0", @@ -3009,286 +1574,108 @@ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "totalist": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-2.0.0.tgz", - "integrity": "sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==", - "dev": true - }, - "tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "tsm": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tsm/-/tsm-2.3.0.tgz", + "integrity": "sha512-++0HFnmmR+gMpDtKTnW3XJ4yv9kVGi20n+NfyQWB9qwJvTaIWY9kBmzek2YUQK5APTQ/1DTrXmm4QtFPmW9Rzw==", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "esbuild": "^0.15.16" } }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "utf-8-validate": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", - "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", - "dev": true, - "optional": true, - "peer": true, + "ui": { + "version": "file:apps/ui", "requires": { - "node-gyp-build": "^4.3.0" + "@reactpy/client": "^0.2.0", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "preact": "^10.7.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5", + "vite": "^3.1.8" } }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, "uvu": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.1.tgz", - "integrity": "sha512-JGxttnOGDFs77FaZ0yMUHIzczzQ5R1IlDeNW6Wymw6gAscwMdAffVOP6TlxLIfReZyK8tahoGwWZaTCJzNFDkg==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", "dev": true, "requires": { "dequal": "^2.0.0", "diff": "^5.0.0", "kleur": "^4.0.3", - "sade": "^1.7.3", - "totalist": "^2.0.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "sade": "^1.7.3" } }, "vite": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.1.8.tgz", - "integrity": "sha512-m7jJe3nufUbuOfotkntGFupinL/fmuTNuQmiVE7cH2IZMuf4UbfbGYMUT3jVWgGYuRVLY9j8NnrRqgw5rr5QTg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", + "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", "dev": true, "requires": { "esbuild": "^0.15.9", "fsevents": "~2.3.2", - "postcss": "^8.4.16", + "postcss": "^8.4.18", "resolve": "^1.22.1", - "rollup": "~2.78.0" - }, - "dependencies": { - "esbuild": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.12.tgz", - "integrity": "sha512-PcT+/wyDqJQsRVhaE9uX/Oq4XLrFh0ce/bs2TJh4CSaw9xuvI+xFrH2nAYOADbhQjUgAhNWC5LKoUsakm4dxng==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.15.12", - "@esbuild/linux-loong64": "0.15.12", - "esbuild-android-64": "0.15.12", - "esbuild-android-arm64": "0.15.12", - "esbuild-darwin-64": "0.15.12", - "esbuild-darwin-arm64": "0.15.12", - "esbuild-freebsd-64": "0.15.12", - "esbuild-freebsd-arm64": "0.15.12", - "esbuild-linux-32": "0.15.12", - "esbuild-linux-64": "0.15.12", - "esbuild-linux-arm": "0.15.12", - "esbuild-linux-arm64": "0.15.12", - "esbuild-linux-mips64le": "0.15.12", - "esbuild-linux-ppc64le": "0.15.12", - "esbuild-linux-riscv64": "0.15.12", - "esbuild-linux-s390x": "0.15.12", - "esbuild-netbsd-64": "0.15.12", - "esbuild-openbsd-64": "0.15.12", - "esbuild-sunos-64": "0.15.12", - "esbuild-windows-32": "0.15.12", - "esbuild-windows-64": "0.15.12", - "esbuild-windows-arm64": "0.15.12" - } - }, - "rollup": { - "version": "2.78.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.78.1.tgz", - "integrity": "sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - } - } - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" + "rollup": "^2.79.1" } }, "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true }, "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "requires": { - "iconv-lite": "0.4.24" + "iconv-lite": "0.6.3" } }, "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true }, "whatwg-url": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", - "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "requires": { - "lodash": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + } } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true } } } diff --git a/src/client/package.json b/src/client/package.json index d480580f2..d6c1a99ba 100644 --- a/src/client/package.json +++ b/src/client/package.json @@ -1,20 +1,17 @@ { - "devDependencies": { - "vite": "^3.1.8" - }, "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/reactive-python/reactpy" - }, "scripts": { - "build": "vite build", - "check-format": "npm --workspaces run check-format", + "publish": "npm --workspaces publish", + "test": "npm --workspaces test", + "build": "npm --workspaces run build", "format": "npm --workspaces run format", - "test": "npm --workspaces test" + "check:format": "npm --workspaces run check:format", + "check:tests": "npm --workspaces run check:tests", + "check:types": "npm --workspaces run check:types" }, - "version": "1.0.0", "workspaces": [ - "./packages/*" + "packages/event-to-object", + "packages/@reactpy/client", + "apps/ui" ] } diff --git a/src/client/packages/client/.gitignore b/src/client/packages/@reactpy/client/.gitignore similarity index 100% rename from src/client/packages/client/.gitignore rename to src/client/packages/@reactpy/client/.gitignore diff --git a/src/client/packages/client/README.md b/src/client/packages/@reactpy/client/README.md similarity index 100% rename from src/client/packages/client/README.md rename to src/client/packages/@reactpy/client/README.md diff --git a/src/client/packages/@reactpy/client/package.json b/src/client/packages/@reactpy/client/package.json new file mode 100644 index 000000000..c878a3069 --- /dev/null +++ b/src/client/packages/@reactpy/client/package.json @@ -0,0 +1,37 @@ +{ + "author": "Ryan Morshead", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "description": "A client for ReactPy implemented in React", + "license": "MIT", + "name": "@reactpy/client", + "type": "module", + "version": "0.2.0", + "dependencies": { + "event-to-object": "^0.1.0", + "json-pointer": "^0.6.2" + }, + "devDependencies": { + "@types/json-pointer": "^1.0.31", + "@types/react": "^17.0", + "@types/react-dom": "^17.0", + "prettier": "^3.0.0-alpha.6", + "typescript": "^4.9.5" + }, + "peerDependencies": { + "react": ">=16 <18", + "react-dom": ">=16 <18" + }, + "repository": { + "type": "git", + "url": "https://github.com/reactive-python/reactpy" + }, + "scripts": { + "build": "tsc -b", + "format": "prettier --write .", + "test": "npm run check:tests", + "check:format": "prettier --check .", + "check:tests": "echo 'no tests'", + "check:types": "tsc --noEmit" + } +} diff --git a/src/client/packages/@reactpy/client/src/components.tsx b/src/client/packages/@reactpy/client/src/components.tsx new file mode 100644 index 000000000..02edae067 --- /dev/null +++ b/src/client/packages/@reactpy/client/src/components.tsx @@ -0,0 +1,231 @@ +import React, { + createElement, + createContext, + useState, + useRef, + useContext, + useEffect, + Fragment, + MutableRefObject, + ChangeEvent, +} from "react"; +// @ts-ignore +import { set as setJsonPointer } from "json-pointer"; +import { LayoutUpdateMessage } from "./messages"; +import { + ReactPyVdom, + ReactPyComponent, + createChildren, + createAttributes, + loadImportSource, + ImportSourceBinding, +} from "./reactpy-vdom"; +import { ReactPyClient } from "./reactpy-client"; + +const ClientContext = createContext(null as any); + +export function Layout(props: { client: ReactPyClient }): JSX.Element { + const currentModel: ReactPyVdom = useState({ tagName: "" })[0]; + const forceUpdate = useForceUpdate(); + + useEffect(() => { + props.client.onMessage( + "layout-update", + ({ path, model }) => { + if (path === "") { + Object.assign(currentModel, model); + } else { + setJsonPointer(currentModel, path, model); + } + forceUpdate(); + }, + ); + props.client.start(); + return () => props.client.stop(); + }, [currentModel, props.client]); + + return ( + + + + ); +} + +export function Element({ model }: { model: ReactPyVdom }): JSX.Element | null { + if (model.error !== undefined) { + if (model.error) { + return
{model.error}
; + } else { + return null; + } + } + + let SpecializedElement: ReactPyComponent; + if (model.tagName in SPECIAL_ELEMENTS) { + SpecializedElement = + SPECIAL_ELEMENTS[model.tagName as keyof typeof SPECIAL_ELEMENTS]; + } else if (model.importSource) { + SpecializedElement = ImportedElement; + } else { + SpecializedElement = StandardElement; + } + + return ; +} + +function StandardElement({ model }: { model: ReactPyVdom }) { + const client = React.useContext(ClientContext); + // Use createElement here to avoid warning about variable numbers of children not + // having keys. Warning about this must now be the responsibility of the client + // providing the models instead of the client rendering them. + return createElement( + model.tagName === "" ? Fragment : model.tagName, + createAttributes(model, client), + ...createChildren(model, (child) => { + return ; + }), + ); +} + +function UserInputElement({ model }: { model: ReactPyVdom }): JSX.Element { + const client = useContext(ClientContext); + const props = createAttributes(model, client); + const [value, setValue] = React.useState(props.value); + + // honor changes to value from the client via props + React.useEffect(() => setValue(props.value), [props.value]); + + const givenOnChange = props.onChange; + if (typeof givenOnChange === "function") { + props.onChange = (event: ChangeEvent) => { + // immediately update the value to give the user feedback + setValue(event.target.value); + // allow the client to respond (and possibly change the value) + givenOnChange(event); + }; + } + + // Use createElement here to avoid warning about variable numbers of children not + // having keys. Warning about this must now be the responsibility of the client + // providing the models instead of the client rendering them. + return createElement( + model.tagName, + // overwrite + { ...props, value }, + ...createChildren(model, (child) => ( + + )), + ); +} + +function ScriptElement({ model }: { model: ReactPyVdom }) { + const ref = useRef(null); + + React.useEffect(() => { + if (!ref.current) { + return; + } + const scriptContent = model?.children?.filter( + (value): value is string => typeof value == "string", + )[0]; + + let scriptElement: HTMLScriptElement; + if (model.attributes) { + scriptElement = document.createElement("script"); + for (const [k, v] of Object.entries(model.attributes)) { + scriptElement.setAttribute(k, v); + } + if (scriptContent) { + scriptElement.appendChild(document.createTextNode(scriptContent)); + } + ref.current.appendChild(scriptElement); + } else if (scriptContent) { + let scriptResult = eval(scriptContent); + if (typeof scriptResult == "function") { + return scriptResult(); + } + } + }, [model.key, ref.current]); + + return
; +} + +function ImportedElement({ model }: { model: ReactPyVdom }) { + const importSourceVdom = model.importSource; + const importSourceRef = useImportSource(model); + + if (!importSourceVdom) { + return null; + } + + const importSourceFallback = importSourceVdom.fallback; + + if (!importSourceVdom) { + // display a fallback if one was given + if (!importSourceFallback) { + return null; + } else if (typeof importSourceFallback === "string") { + return
{importSourceFallback}
; + } else { + return ; + } + } else { + return
; + } +} + +function useForceUpdate() { + const [, setState] = useState(false); + return () => setState((old) => !old); +} + +function useImportSource(model: ReactPyVdom): MutableRefObject { + const vdomImportSource = model.importSource; + + const mountPoint = useRef(null); + const client = React.useContext(ClientContext); + const [binding, setBinding] = useState(null); + + React.useEffect(() => { + let unmounted = false; + + if (vdomImportSource) { + loadImportSource(vdomImportSource, client).then((bind) => { + if (!unmounted && mountPoint.current) { + setBinding(bind(mountPoint.current)); + } + }); + } + + return () => { + unmounted = true; + if ( + binding && + vdomImportSource && + !vdomImportSource.unmountBeforeUpdate + ) { + binding.unmount(); + } + }; + }, [client, vdomImportSource, setBinding, mountPoint.current]); + + // this effect must run every time in case the model has changed + useEffect(() => { + if (!(binding && vdomImportSource)) { + return; + } + binding.render(model); + if (vdomImportSource.unmountBeforeUpdate) { + return binding.unmount; + } + }); + + return mountPoint; +} + +const SPECIAL_ELEMENTS = { + input: UserInputElement, + script: ScriptElement, + select: UserInputElement, + textarea: UserInputElement, +}; diff --git a/src/client/packages/@reactpy/client/src/index.ts b/src/client/packages/@reactpy/client/src/index.ts new file mode 100644 index 000000000..548fcbfc7 --- /dev/null +++ b/src/client/packages/@reactpy/client/src/index.ts @@ -0,0 +1,5 @@ +export * from "./components"; +export * from "./messages"; +export * from "./mount"; +export * from "./reactpy-client"; +export * from "./reactpy-vdom"; diff --git a/src/client/packages/@reactpy/client/src/logger.ts b/src/client/packages/@reactpy/client/src/logger.ts new file mode 100644 index 000000000..4c4cdd264 --- /dev/null +++ b/src/client/packages/@reactpy/client/src/logger.ts @@ -0,0 +1,5 @@ +export default { + log: (...args: any[]): void => console.log("[ReactPy]", ...args), + warn: (...args: any[]): void => console.warn("[ReactPy]", ...args), + error: (...args: any[]): void => console.error("[ReactPy]", ...args), +}; diff --git a/src/client/packages/@reactpy/client/src/messages.ts b/src/client/packages/@reactpy/client/src/messages.ts new file mode 100644 index 000000000..eb33cdea5 --- /dev/null +++ b/src/client/packages/@reactpy/client/src/messages.ts @@ -0,0 +1,32 @@ +import { ReactPyVdom } from "./reactpy-vdom"; + +export interface IMessage { + type: string; +} + +export type ConnectionOpenMessage = { + type: "connection-open"; +}; + +export type ConnectionCloseMessage = { + type: "connection-close"; +}; + +export type LayoutUpdateMessage = { + type: "layout-update"; + path: string; + model: ReactPyVdom; +}; + +export type LayoutEventMessage = { + type: "layout-event"; + target: string; + data: any; +}; + +export type IncomingMessage = + | LayoutUpdateMessage + | ConnectionOpenMessage + | ConnectionCloseMessage; +export type OutgoingMessage = LayoutEventMessage; +export type Message = IncomingMessage | OutgoingMessage; diff --git a/src/client/packages/@reactpy/client/src/mount.tsx b/src/client/packages/@reactpy/client/src/mount.tsx new file mode 100644 index 000000000..0b824a4ee --- /dev/null +++ b/src/client/packages/@reactpy/client/src/mount.tsx @@ -0,0 +1,8 @@ +import React from "react"; +import { render } from "react-dom"; +import { Layout } from "./components"; +import { ReactPyClient } from "./reactpy-client"; + +export function mount(element: HTMLElement, client: ReactPyClient): void { + render(, element); +} diff --git a/src/client/packages/@reactpy/client/src/reactpy-client.ts b/src/client/packages/@reactpy/client/src/reactpy-client.ts new file mode 100644 index 000000000..9a8f8a4bf --- /dev/null +++ b/src/client/packages/@reactpy/client/src/reactpy-client.ts @@ -0,0 +1,274 @@ +import { OutgoingMessage, IncomingMessage } from "./messages"; +import { ReactPyModule } from "./reactpy-vdom"; +import logger from "./logger"; + +/** + * A client for communicating with a ReactPy server. + */ +export interface ReactPyClient { + /** + * Connect to the server and start receiving messages. + * + * Message handlers should be registered before calling this method in order to + * garuntee that messages are not missed. + */ + start: () => void; + /** + * Disconnect from the server and stop receiving messages. + */ + stop: () => void; + /** + * Register a handler for a message type. + */ + onMessage: ( + type: M["type"], + handler: (message: M) => void, + ) => void; + /** + * Send a message to the server. + */ + sendMessage: (message: OutgoingMessage) => void; + /** + * Dynamically load a module from the server. + */ + loadModule: (moduleName: string) => Promise; +} + +export type SimpleReactPyClientProps = { + serverLocation?: LocationProps; + reconnectOptions?: ReconnectProps; +}; + +/** + * The location of the server. + * + * This is used to determine the location of the server's API endpoints. All endpoints + * are expected to be found at the base URL, with the following paths: + * + * - `_reactpy/stream/${route}${query}`: The websocket endpoint for the stream. + * - `_reactpy/modules`: The directory containing the dynamically loaded modules. + * - `_reactpy/assets`: The directory containing the static assets. + */ +type LocationProps = { + /** + * The base URL of the server. + * + * @default - document.location.origin + */ + url: string; + /** + * The route to the page being rendered. + * + * @default - document.location.pathname + */ + route: string; + /** + * The query string of the page being rendered. + * + * @default - document.location.search + */ + query: string; +}; + +type ReconnectProps = { + maxInterval?: number; + maxRetries?: number; + backoffRate?: number; + intervalJitter?: number; +}; + +export class SimpleReactPyClient implements ReactPyClient { + private resolveShouldOpen: (value: unknown) => void; + private resolveShouldClose: (value: unknown) => void; + private readonly urls: ServerUrls; + private readonly handlers: { + [key in IncomingMessage["type"]]: ((message: any) => void)[]; + }; + private readonly socket: { current?: WebSocket }; + + constructor(props: SimpleReactPyClientProps) { + this.handlers = { + "connection-open": [], + "connection-close": [], + "layout-update": [], + }; + + this.urls = getServerUrls( + props.serverLocation || { + url: document.location.origin, + route: document.location.pathname, + query: document.location.search, + }, + ); + + this.resolveShouldOpen = () => { + throw new Error("Could not start client"); + }; + this.resolveShouldClose = () => { + throw new Error("Could not stop client"); + }; + const shouldOpen = new Promise((r) => (this.resolveShouldOpen = r)); + const shouldClose = new Promise((r) => (this.resolveShouldClose = r)); + + this.socket = startReconnectingWebSocket({ + shouldOpen, + shouldClose, + url: this.urls.stream, + onOpen: () => this.handleIncoming({ type: "connection-open" }), + onMessage: async ({ data }) => this.handleIncoming(JSON.parse(data)), + onClose: () => this.handleIncoming({ type: "connection-close" }), + ...props.reconnectOptions, + }); + } + + start(): void { + logger.log("starting client..."); + this.resolveShouldOpen(undefined); + } + + stop(): void { + logger.log("stopping client..."); + this.resolveShouldClose(undefined); + } + + onMessage( + type: M["type"], + handler: (message: M) => void, + ): void { + this.handlers[type].push(handler); + } + + sendMessage(message: OutgoingMessage): void { + this.socket.current?.send(JSON.stringify(message)); + } + + loadModule(moduleName: string): Promise { + return import(`${this.urls.modules}/${moduleName}`); + } + + private handleIncoming(message: IncomingMessage): void { + if (!message.type) { + logger.warn("Received message without type", message); + return; + } + + const messageHandlers: ((m: any) => void)[] | undefined = + this.handlers[message.type]; + if (!messageHandlers) { + logger.warn("Received message without handler", message); + return; + } + + messageHandlers.forEach((h) => h(message)); + } +} + +type ServerUrls = { + base: URL; + stream: string; + modules: string; + assets: string; +}; + +function getServerUrls(props: LocationProps): ServerUrls { + const base = new URL(`${props.url || document.location.origin}/_reactpy`); + const modules = `${base}/modules`; + const assets = `${base}/assets`; + + const streamProtocol = `ws${base.protocol === "https:" ? "s" : ""}`; + const streamPath = rtrim(`${base.pathname}/stream${props.route || ""}`, "/"); + const stream = `${streamProtocol}://${base.host}${streamPath}${props.query}`; + + return { base, modules, assets, stream }; +} + +function startReconnectingWebSocket( + props: { + shouldOpen: Promise; + shouldClose: Promise; + url: string; + onOpen: () => void; + onMessage: (message: MessageEvent) => void; + onClose: () => void; + } & ReconnectProps, +) { + const { + maxInterval = 60000, + maxRetries = 50, + backoffRate = 1.1, + intervalJitter = 0.1, + } = props; + + const startInterval = 750; + let retries = 0; + let interval = startInterval; + let closed = false; + let everConnected = false; + const socket: { current?: WebSocket } = {}; + + const connect = () => { + if (closed) { + return; + } + socket.current = new WebSocket(props.url); + socket.current.onopen = () => { + everConnected = true; + logger.log("client connected"); + interval = startInterval; + retries = 0; + props.onOpen(); + }; + socket.current.onmessage = props.onMessage; + socket.current.onclose = () => { + if (!everConnected) { + logger.log("failed to connect"); + return; + } + + logger.log("client disconnected"); + props.onClose(); + + if (retries >= maxRetries) { + return; + } + + const thisInterval = addJitter(interval, intervalJitter); + logger.log( + `reconnecting in ${(thisInterval / 1000).toPrecision(4)} seconds...`, + ); + setTimeout(connect, thisInterval); + interval = nextInterval(interval, backoffRate, maxInterval); + retries++; + }; + }; + + props.shouldOpen.then(connect); + props.shouldClose.then(() => { + closed = true; + socket.current?.close(); + }); + + return socket; +} + +function nextInterval( + currentInterval: number, + backoffRate: number, + maxInterval: number, +): number { + return Math.min( + currentInterval * + // increase interval by backoff rate + backoffRate, + // don't exceed max interval + maxInterval, + ); +} + +function addJitter(interval: number, jitter: number): number { + return interval + (Math.random() * jitter * interval * 2 - jitter * interval); +} + +function rtrim(text: string, trim: string): string { + return text.replace(new RegExp(`${trim}+$`), ""); +} diff --git a/src/client/packages/@reactpy/client/src/reactpy-vdom.tsx b/src/client/packages/@reactpy/client/src/reactpy-vdom.tsx new file mode 100644 index 000000000..0d4f9c213 --- /dev/null +++ b/src/client/packages/@reactpy/client/src/reactpy-vdom.tsx @@ -0,0 +1,261 @@ +import React, { ComponentType } from "react"; +import { ReactPyClient } from "./reactpy-client"; +import serializeEvent from "event-to-object"; + +export async function loadImportSource( + vdomImportSource: ReactPyVdomImportSource, + client: ReactPyClient, +): Promise { + let module: ReactPyModule; + if (vdomImportSource.sourceType === "URL") { + module = await import(vdomImportSource.source); + } else { + module = await client.loadModule(vdomImportSource.source); + } + if (typeof module.bind !== "function") { + throw new Error( + `${vdomImportSource.source} did not export a function 'bind'`, + ); + } + + return (node: HTMLElement) => { + const binding = module.bind(node, { + sendMessage: client.sendMessage, + onMessage: client.onMessage, + }); + if ( + !( + typeof binding.create === "function" && + typeof binding.render === "function" && + typeof binding.unmount === "function" + ) + ) { + console.error(`${vdomImportSource.source} returned an impropper binding`); + return null; + } + + return { + render: (model) => + binding.render( + createImportSourceElement({ + client, + module, + binding, + model, + currentImportSource: vdomImportSource, + }), + ), + unmount: binding.unmount, + }; + }; +} + +function createImportSourceElement(props: { + client: ReactPyClient; + module: ReactPyModule; + binding: ReactPyModuleBinding; + model: ReactPyVdom; + currentImportSource: ReactPyVdomImportSource; +}): any { + let type: any; + if (props.model.importSource) { + if ( + !isImportSourceEqual(props.currentImportSource, props.model.importSource) + ) { + console.error( + "Parent element import source " + + stringifyImportSource(props.currentImportSource) + + " does not match child's import source " + + stringifyImportSource(props.model.importSource), + ); + return null; + } else if (!props.module[props.model.tagName]) { + console.error( + "Module from source " + + stringifyImportSource(props.currentImportSource) + + ` does not export ${props.model.tagName}`, + ); + return null; + } else { + type = props.module[props.model.tagName]; + } + } else { + type = props.model.tagName; + } + return props.binding.create( + type, + createAttributes(props.model, props.client), + createChildren(props.model, (child) => + createImportSourceElement({ + ...props, + model: child, + }), + ), + ); +} + +function isImportSourceEqual( + source1: ReactPyVdomImportSource, + source2: ReactPyVdomImportSource, +) { + return ( + source1.source === source2.source && + source1.sourceType === source2.sourceType + ); +} + +function stringifyImportSource(importSource: ReactPyVdomImportSource) { + return JSON.stringify({ + source: importSource.source, + sourceType: importSource.sourceType, + }); +} + +export function createChildren( + model: ReactPyVdom, + createChild: (child: ReactPyVdom) => Child, +): (Child | string)[] { + if (!model.children) { + return []; + } else { + return model.children.map((child) => { + switch (typeof child) { + case "object": + return createChild(child); + case "string": + return child; + } + }); + } +} + +export function createAttributes( + model: ReactPyVdom, + client: ReactPyClient, +): { [key: string]: any } { + return Object.fromEntries( + Object.entries({ + // Normal HTML attributes + ...model.attributes, + // Construct event handlers + ...Object.fromEntries( + Object.entries(model.eventHandlers || {}).map(([name, handler]) => + createEventHandler(client, name, handler), + ), + ), + // Convert snake_case to camelCase names + }).map(normalizeAttribute), + ); +} + +function createEventHandler( + client: ReactPyClient, + name: string, + { target, preventDefault, stopPropagation }: ReactPyVdomEventHandler, +): [string, () => void] { + return [ + name, + function () { + const data = Array.from(arguments).map((value) => { + if (!(typeof value === "object" && value.nativeEvent)) { + return value; + } + const event = value as React.SyntheticEvent; + if (preventDefault) { + event.preventDefault(); + } + if (stopPropagation) { + event.stopPropagation(); + } + return serializeEvent(event.nativeEvent); + }); + client.sendMessage({ type: "layout-event", data, target }); + }, + ]; +} + +function normalizeAttribute([key, value]: [string, any]): [string, any] { + let normKey = key; + let normValue = value; + + if (key === "style" && typeof value === "object") { + normValue = Object.fromEntries( + Object.entries(value).map(([k, v]) => [snakeToCamel(k), v]), + ); + } else if ( + key.startsWith("data_") || + key.startsWith("aria_") || + DASHED_HTML_ATTRS.includes(key) + ) { + normKey = key.split("_").join("-"); + } else { + normKey = snakeToCamel(key); + } + return [normKey, normValue]; +} + +function snakeToCamel(str: string): string { + return str.replace(/([_][a-z])/g, (group) => + group.toUpperCase().replace("_", ""), + ); +} + +// see list of HTML attributes with dashes in them: +// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#attribute_list +const DASHED_HTML_ATTRS = ["accept_charset", "http_equiv"]; + +export type ReactPyComponent = ComponentType<{ model: ReactPyVdom }>; + +export type ReactPyVdom = { + tagName: string; + key?: string; + attributes?: { [key: string]: string }; + children?: (ReactPyVdom | string)[]; + error?: string; + eventHandlers?: { [key: string]: ReactPyVdomEventHandler }; + importSource?: ReactPyVdomImportSource; +}; + +export type ReactPyVdomEventHandler = { + target: string; + preventDefault?: boolean; + stopPropagation?: boolean; +}; + +export type ReactPyVdomImportSource = { + source: string; + sourceType?: "URL" | "NAME"; + fallback?: string | ReactPyVdom; + unmountBeforeUpdate?: boolean; +}; + +export type ReactPyModule = { + bind: ( + node: HTMLElement, + context: ReactPyModuleBindingContext, + ) => ReactPyModuleBinding; +} & { [key: string]: any }; + +export type ReactPyModuleBindingContext = { + sendMessage: ReactPyClient["sendMessage"]; + onMessage: ReactPyClient["onMessage"]; +}; + +export type ReactPyModuleBinding = { + create: ( + type: any, + props?: any, + children?: (any | string | ReactPyVdom)[], + ) => any; + render: (element: any) => void; + unmount: () => void; +}; + +export type BindImportSource = ( + node: HTMLElement, +) => ImportSourceBinding | null; + +export type ImportSourceBinding = { + render: (model: ReactPyVdom) => void; + unmount: () => void; +}; diff --git a/src/client/packages/@reactpy/client/tsconfig.json b/src/client/packages/@reactpy/client/tsconfig.json new file mode 100644 index 000000000..2e1483e10 --- /dev/null +++ b/src/client/packages/@reactpy/client/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../../tsconfig.package.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "composite": true + }, + "include": ["src"], + "references": [ + { + "path": "../../event-to-object" + } + ] +} diff --git a/src/client/packages/app/package-lock.json b/src/client/packages/app/package-lock.json deleted file mode 100644 index 9d1075eb8..000000000 --- a/src/client/packages/app/package-lock.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@reactpy/app", - "version": "0.38.0-a1", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@reactpy/app", - "version": "0.38.0-a1", - "license": "MIT", - "dependencies": { - "@reactpy/client": "file:packages/@reactpy/client", - "preact": "^10.7.0" - }, - "devDependencies": { - "prettier": "^2.5.1" - } - }, - "node_modules/@reactpy/client": { - "resolved": "packages/@reactpy/client", - "link": true - }, - "node_modules/preact": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.0.tgz", - "integrity": "sha512-9MEURwzNMKpAil/t6+wabDIJI6oG6GnwypYxiJDvQnW+fHDTt51PYuLZ1QUM31hFr7sDaj9qTaShAF9VIxuxGQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/prettier": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", - "integrity": "sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "packages/@reactpy/client": {} - }, - "dependencies": { - "@reactpy/client": { - "version": "file:packages/@reactpy/client" - }, - "preact": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.7.0.tgz", - "integrity": "sha512-9MEURwzNMKpAil/t6+wabDIJI6oG6GnwypYxiJDvQnW+fHDTt51PYuLZ1QUM31hFr7sDaj9qTaShAF9VIxuxGQ==" - }, - "prettier": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.1.tgz", - "integrity": "sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==", - "dev": true - } - } -} diff --git a/src/client/packages/app/package.json b/src/client/packages/app/package.json deleted file mode 100644 index 0424577a9..000000000 --- a/src/client/packages/app/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "author": "Ryan Morshead", - "dependencies": { - "@reactpy/client": "file:packages/client", - "preact": "^10.7.0" - }, - "description": "A client application for ReactPy implemented in React", - "devDependencies": { - "prettier": "^2.5.1" - }, - "license": "MIT", - "main": "src/index.js", - "name": "@reactpy/app", - "repository": { - "type": "git", - "url": "https://github.com/reactive-python/reactpy" - }, - "scripts": { - "check-format": "prettier --check ./src", - "format": "prettier --write ./src", - "test": "echo 'no tests'" - } -} diff --git a/src/client/packages/app/src/index.js b/src/client/packages/app/src/index.js deleted file mode 100644 index 27d62ce09..000000000 --- a/src/client/packages/app/src/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import { mountWithLayoutServer, LayoutServerInfo } from "@reactpy/client"; - -export function mount(mountPoint) { - const serverInfo = new LayoutServerInfo({ - host: document.location.hostname, - port: document.location.port, - query: queryParams.user.toString(), - secure: document.location.protocol == "https:", - }); - mountWithLayoutServer(mountPoint, serverInfo, shouldReconnect() ? 45 : 0); -} - -function shouldReconnect() { - return queryParams.reserved.get("noReconnect") === null; -} - -const queryParams = (() => { - const reservedParams = new URLSearchParams(); - const userParams = new URLSearchParams(window.location.search); - - const reservedParamNames = ["noReconnect"]; - reservedParamNames.forEach((name) => { - const value = userParams.get(name); - if (value !== null) { - reservedParams.append(name, userParams.get(name)); - userParams.delete(name); - } - }); - - return { - reserved: reservedParams, - user: userParams, - }; -})(); diff --git a/src/client/packages/client/package.json b/src/client/packages/client/package.json deleted file mode 100644 index e9bf4cc13..000000000 --- a/src/client/packages/client/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "author": "Ryan Morshead", - "dependencies": { - "htm": "^3.0.3", - "json-pointer": "^0.6.2" - }, - "description": "A client for ReactPy implemented in React", - "devDependencies": { - "jsdom": "16.5.0", - "lodash": "^4.17.21", - "prettier": "^2.5.1", - "uvu": "^0.5.1" - }, - "files": [ - "src/**/*.js" - ], - "license": "MIT", - "main": "src/index.js", - "name": "@reactpy/client", - "peerDependencies": { - "react": ">=16", - "react-dom": ">=16" - }, - "repository": { - "type": "git", - "url": "https://github.com/reactive-python/reactpy" - }, - "scripts": { - "check-format": "prettier --check ./src ./tests", - "format": "prettier --write ./src ./tests", - "test": "uvu tests" - }, - "type": "module", - "version": "0.1.0" -} diff --git a/src/client/packages/client/src/components.js b/src/client/packages/client/src/components.js deleted file mode 100644 index 4f2953d32..000000000 --- a/src/client/packages/client/src/components.js +++ /dev/null @@ -1,220 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import htm from "htm"; -import { set as setJsonPointer } from "json-pointer"; - -import { useImportSource } from "./import-source.js"; -import { LayoutContext } from "./contexts.js"; - -import { - createElementAttributes, - createElementChildren, -} from "./element-utils.js"; - -const html = htm.bind(React.createElement); - -export function Layout({ saveUpdateHook, sendEvent, loadImportSource }) { - const currentModel = React.useState({})[0]; - const forceUpdate = useForceUpdate(); - - const patchModel = React.useCallback( - ({ path, model }) => { - if (!path) { - Object.assign(currentModel, model); - } else { - setJsonPointer(currentModel, path, model); - } - forceUpdate(); - }, - [currentModel] - ); - - React.useEffect(() => saveUpdateHook(patchModel), [patchModel]); - - if (!Object.keys(currentModel).length) { - return html`<${React.Fragment} />`; - } - - return html` - <${LayoutContext.Provider} value=${{ sendEvent, loadImportSource }}> - <${Element} model=${currentModel} /> - - `; -} - -export function Element({ model }) { - if (model.error !== undefined) { - if (model.error) { - return html`
${model.error}
`; - } else { - return null; - } - } else if (model.tagName == "script") { - return html`<${ScriptElement} model=${model} />`; - } else if (["input", "select", "textarea"].includes(model.tagName)) { - return html`<${UserInputElement} model=${model} />`; - } else if (model.importSource) { - return html`<${ImportedElement} model=${model} />`; - } else { - return html`<${StandardElement} model=${model} />`; - } -} - -function StandardElement({ model }) { - const layoutContext = React.useContext(LayoutContext); - - let type; - if (model.tagName == "") { - type = React.Fragment; - } else { - type = model.tagName; - } - - // Use createElement here to avoid warning about variable numbers of children not - // having keys. Warning about this must now be the responsibility of the server - // providing the models instead of the client rendering them. - return React.createElement( - type, - createElementAttributes(model, layoutContext.sendEvent), - ...createElementChildren( - model, - (model) => html`<${Element} key=${model.key} model=${model} />` - ) - ); -} - -// Element with a value attribute controlled by user input -function UserInputElement({ model }) { - const ref = React.useRef(); - const layoutContext = React.useContext(LayoutContext); - - const props = createElementAttributes(model, layoutContext.sendEvent); - - // Because we handle events asynchronously, we must leave the value uncontrolled in - // order to allow all changes committed by the user to be recorded in the order they - // occur. If we don't the user may commit multiple changes before we render next - // causing the content of prior changes to be overwritten by subsequent changes. - let value = props.value; - delete props.value; - - // Instead of controlling the value, we set it in an effect. - React.useEffect(() => { - if (value !== undefined) { - ref.current.value = value; - } - }, [ref.current, value]); - - // Track a buffer of observed values in order to avoid flicker - const observedValues = React.useState([])[0]; - if (observedValues) { - if (value === observedValues[0]) { - observedValues.shift(); - value = observedValues[observedValues.length - 1]; - } else { - observedValues.length = 0; - } - } - - const givenOnChange = props.onChange; - if (typeof givenOnChange === "function") { - props.onChange = (event) => { - observedValues.push(event.target.value); - givenOnChange(event); - }; - } - - // Use createElement here to avoid warning about variable numbers of children not - // having keys. Warning about this must now be the responsibility of the server - // providing the models instead of the client rendering them. - return React.createElement( - model.tagName, - { - ...props, - ref: (target) => { - ref.current = target; - }, - }, - ...createElementChildren( - model, - (model) => html`<${Element} key=${model.key} model=${model} />` - ) - ); -} - -function ScriptElement({ model }) { - const ref = React.useRef(); - React.useEffect(() => { - if (model?.children?.length > 1) { - console.error("Too many children for 'script' element."); - } - - let scriptContent = model?.children?.[0]; - - let scriptElement; - if (model.attributes) { - scriptElement = document.createElement("script"); - for (const [k, v] of Object.entries(model.attributes)) { - scriptElement.setAttribute(k, v); - } - scriptElement.appendChild(document.createTextNode(scriptContent)); - ref.current.appendChild(scriptElement); - } else { - let scriptResult = eval(scriptContent); - if (typeof scriptResult == "function") { - return scriptResult(); - } - } - }, [model.key]); - return html`
`; -} - -function ImportedElement({ model }) { - const layoutContext = React.useContext(LayoutContext); - - const importSourceFallback = model.importSource.fallback; - const importSource = useImportSource(model.importSource); - - if (!importSource) { - // display a fallback if one was given - if (!importSourceFallback) { - return html`
`; - } else if (typeof importSourceFallback === "string") { - return html`
${importSourceFallback}
`; - } else { - return html`<${StandardElement} model=${importSourceFallback} />`; - } - } else { - return html`<${_ImportedElement} - model=${model} - importSource=${importSource} - />`; - } -} - -function _ImportedElement({ model, importSource }) { - const layoutContext = React.useContext(LayoutContext); - const mountPoint = React.useRef(null); - const sourceBinding = React.useRef(null); - - React.useEffect(() => { - sourceBinding.current = importSource.bind(mountPoint.current); - if (!importSource.data.unmountBeforeUpdate) { - return sourceBinding.current.unmount; - } - }, []); - - // this effect must run every time in case the model has changed - React.useEffect(() => { - sourceBinding.current.render(model); - if (importSource.data.unmountBeforeUpdate) { - return sourceBinding.current.unmount; - } - }); - - return html`
`; -} - -function useForceUpdate() { - const [, updateState] = React.useState(); - return React.useCallback(() => updateState({}), []); -} diff --git a/src/client/packages/client/src/contexts.js b/src/client/packages/client/src/contexts.js deleted file mode 100644 index c6ad86978..000000000 --- a/src/client/packages/client/src/contexts.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from "react"; - -export const LayoutContext = React.createContext({ - sendEvent: undefined, - loadImportSource: undefined, -}); diff --git a/src/client/packages/client/src/element-utils.js b/src/client/packages/client/src/element-utils.js deleted file mode 100644 index 01610804e..000000000 --- a/src/client/packages/client/src/element-utils.js +++ /dev/null @@ -1,82 +0,0 @@ -import { serializeEvent } from "./event-to-object.js"; - -export function createElementChildren(model, createElement) { - if (!model.children) { - return []; - } else { - return model.children - .filter((x) => x) // filter nulls - .map((child) => { - switch (typeof child) { - case "object": - return createElement(child); - case "string": - return child; - } - }); - } -} - -export function createElementAttributes(model, sendEvent) { - const attributes = Object.assign({}, model.attributes); - - if (model.eventHandlers) { - for (const [eventName, eventSpec] of Object.entries(model.eventHandlers)) { - attributes[eventName] = createEventHandler(sendEvent, eventSpec); - } - } - - return Object.fromEntries(Object.entries(attributes).map(normalizeAttribute)); -} - -function createEventHandler(sendEvent, eventSpec) { - return function () { - const data = Array.from(arguments).map((value) => { - if (typeof value === "object" && value.nativeEvent) { - if (eventSpec["preventDefault"]) { - value.preventDefault(); - } - if (eventSpec["stopPropagation"]) { - value.stopPropagation(); - } - return serializeEvent(value); - } else { - return value; - } - }); - sendEvent({ - data: data, - target: eventSpec["target"], - }); - }; -} - -function normalizeAttribute([key, value]) { - let normKey = key; - let normValue = value; - - if (key === "style" && typeof value === "object") { - normValue = Object.fromEntries( - Object.entries(value).map(([k, v]) => [snakeToCamel(k), v]) - ); - } else if ( - key.startsWith("data_") || - key.startsWith("aria_") || - DASHED_HTML_ATTRS.includes(key) - ) { - normKey = key.replaceAll("_", "-"); - } else { - normKey = snakeToCamel(key); - } - return [normKey, normValue]; -} - -function snakeToCamel(str) { - return str.replace(/([_][a-z])/g, (group) => - group.toUpperCase().replace("_", "") - ); -} - -// see list of HTML attributes with dashes in them: -// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#attribute_list -const DASHED_HTML_ATTRS = ["accept_charset", "http_equiv"]; diff --git a/src/client/packages/client/src/event-to-object.js b/src/client/packages/client/src/event-to-object.js deleted file mode 100644 index e35f652e5..000000000 --- a/src/client/packages/client/src/event-to-object.js +++ /dev/null @@ -1,240 +0,0 @@ -export function serializeEvent(event) { - const data = {}; - - if (event.type in eventTransforms) { - Object.assign(data, eventTransforms[event.type](event)); - } - - data.target = serializeDomElement(event.target); - data.currentTarget = - event.target === event.currentTarget - ? data.target - : serializeDomElement(event.currentTarget); - data.relatedTarget = serializeDomElement(event.relatedTarget); - - return data; -} - -function serializeDomElement(element) { - let elementData = null; - if (element) { - elementData = defaultElementTransform(element); - if (element.tagName in elementTransforms) { - elementTransforms[element.tagName].forEach((trans) => - Object.assign(elementData, trans(element)) - ); - } - } - return elementData; -} - -const elementTransformCategories = { - hasValue: (element) => ({ - value: element.value, - }), - hasCurrentTime: (element) => ({ - currentTime: element.currentTime, - }), - hasFiles: (element) => { - if (element?.type === "file") { - return { - files: Array.from(element.files).map((file) => ({ - lastModified: file.lastModified, - name: file.name, - size: file.size, - type: file.type, - })), - }; - } else { - return {}; - } - }, - hasElements: (element) => { - const { elements } = element; - const indices = [...Array(elements.length).keys()]; - return { - elements: indices.map((index) => serializeDomElement(elements[index])), - }; - }, - hasName: (element) => { - const { name } = element; - // In some edge cases, "name" may not be a string. For example, in the case of - // `
`, the "name" attribute of the `
` will - // be the `` element. - return typeof name === "string" ? { name } : {}; - }, -}; - -function defaultElementTransform(element) { - return { boundingClientRect: element.getBoundingClientRect() }; -} - -const elementTagCategories = { - hasValue: [ - "BUTTON", - "INPUT", - "OPTION", - "LI", - "METER", - "PROGRESS", - "PARAM", - "SELECT", - "TEXTAREA", - ], - hasCurrentTime: ["AUDIO", "VIDEO"], - hasFiles: ["INPUT"], - hasElements: ["FORM"], - hasName: [ - "BUTTON", - "FORM", - "FIELDSET", - "IFRAME", - "INPUT", - "KEYGEN", - "OBJECT", - "OUTPUT", - "SELECT", - "TEXTAREA", - "MAP", - "META", - "PARAM", - ], -}; - -const elementTransforms = {}; - -Object.keys(elementTagCategories).forEach((category) => { - elementTagCategories[category].forEach((type) => { - const transforms = - elementTransforms[type] || (elementTransforms[type] = []); - transforms.push(elementTransformCategories[category]); - }); -}); - -function EventTransformCategories() { - this.clipboard = (event) => ({ - clipboardData: event.clipboardData, - }); - this.composition = (event) => ({ - data: event.data, - }); - this.keyboard = (event) => ({ - altKey: event.altKey, - charCode: event.charCode, - ctrlKey: event.ctrlKey, - key: event.key, - keyCode: event.keyCode, - locale: event.locale, - location: event.location, - metaKey: event.metaKey, - repeat: event.repeat, - shiftKey: event.shiftKey, - which: event.which, - }); - this.mouse = (event) => ({ - altKey: event.altKey, - button: event.button, - buttons: event.buttons, - clientX: event.clientX, - clientY: event.clientY, - ctrlKey: event.ctrlKey, - metaKey: event.metaKey, - pageX: event.pageX, - pageY: event.pageY, - screenX: event.screenX, - screenY: event.screenY, - shiftKey: event.shiftKey, - }); - this.pointer = (event) => ({ - ...this.mouse(event), - pointerId: event.pointerId, - width: event.width, - height: event.height, - pressure: event.pressure, - tiltX: event.tiltX, - tiltY: event.tiltY, - pointerType: event.pointerType, - isPrimary: event.isPrimary, - }); - this.selection = () => { - return { selectedText: window.getSelection().toString() }; - }; - this.touch = (event) => ({ - altKey: event.altKey, - ctrlKey: event.ctrlKey, - metaKey: event.metaKey, - shiftKey: event.shiftKey, - }); - this.ui = (event) => ({ - detail: event.detail, - }); - this.wheel = (event) => ({ - deltaMode: event.deltaMode, - deltaX: event.deltaX, - deltaY: event.deltaY, - deltaZ: event.deltaZ, - }); - this.animation = (event) => ({ - animationName: event.animationName, - pseudoElement: event.pseudoElement, - elapsedTime: event.elapsedTime, - }); - this.transition = (event) => ({ - propertyName: event.propertyName, - pseudoElement: event.pseudoElement, - elapsedTime: event.elapsedTime, - }); -} - -const eventTypeCategories = { - clipboard: ["copy", "cut", "paste"], - composition: ["compositionend", "compositionstart", "compositionupdate"], - keyboard: ["keydown", "keypress", "keyup"], - mouse: [ - "click", - "contextmenu", - "doubleclick", - "drag", - "dragend", - "dragenter", - "dragexit", - "dragleave", - "dragover", - "dragstart", - "drop", - "mousedown", - "mouseenter", - "mouseleave", - "mousemove", - "mouseout", - "mouseover", - "mouseup", - ], - pointer: [ - "pointerdown", - "pointermove", - "pointerup", - "pointercancel", - "gotpointercapture", - "lostpointercapture", - "pointerenter", - "pointerleave", - "pointerover", - "pointerout", - ], - selection: ["select"], - touch: ["touchcancel", "touchend", "touchmove", "touchstart"], - ui: ["scroll"], - wheel: ["wheel"], - animation: ["animationstart", "animationend", "animationiteration"], - transition: ["transitionend"], -}; - -const eventTransforms = {}; - -const eventTransformCategories = new EventTransformCategories(); -Object.keys(eventTypeCategories).forEach((category) => { - eventTypeCategories[category].forEach((type) => { - eventTransforms[type] = eventTransformCategories[category]; - }); -}); diff --git a/src/client/packages/client/src/import-source.js b/src/client/packages/client/src/import-source.js deleted file mode 100644 index 7c09c7c5d..000000000 --- a/src/client/packages/client/src/import-source.js +++ /dev/null @@ -1,134 +0,0 @@ -import React from "react"; - -import { LayoutContext } from "./contexts.js"; - -import { - createElementAttributes, - createElementChildren, -} from "./element-utils.js"; - -export function useImportSource(modelImportSource) { - const layoutContext = React.useContext(LayoutContext); - const [importSource, setImportSource] = React.useState(null); - - React.useEffect(() => { - let unmounted = false; - - loadModelImportSource(layoutContext, modelImportSource).then((src) => { - if (!unmounted) { - setImportSource(src); - } - }); - - return () => { - unmounted = true; - }; - }, [layoutContext, modelImportSource, setImportSource]); - - return importSource; -} - -function loadModelImportSource(layoutContext, importSource) { - return layoutContext - .loadImportSource(importSource.source, importSource.sourceType) - .then((module) => { - if (typeof module.bind === "function") { - return { - data: importSource, - bind: (node) => { - const shortImportSource = { - source: importSource.source, - sourceType: importSource.sourceType, - }; - const binding = module.bind(node, layoutContext); - if ( - typeof binding.create === "function" && - typeof binding.render === "function" && - typeof binding.unmount === "function" - ) { - return { - render: (model) => - binding.render( - createElementFromModuleBinding( - layoutContext, - importSource, - module, - binding, - model - ) - ), - unmount: binding.unmount, - }; - } else { - console.error( - `${importSource.source} returned an impropper binding` - ); - } - }, - }; - } else { - console.error( - `${importSource.source} did not export a function 'bind'` - ); - } - }); -} - -function createElementFromModuleBinding( - layoutContext, - currentImportSource, - module, - binding, - model -) { - let type; - if (model.importSource) { - if (!isImportSourceEqual(currentImportSource, model.importSource)) { - console.error( - "Parent element import source " + - stringifyImportSource(currentImportSource) + - " does not match child's import source " + - stringifyImportSource(model.importSource) - ); - return null; - } else if (!module[model.tagName]) { - console.error( - "Module from source " + - stringifyImportSource(currentImportSource) + - ` does not export ${model.tagName}` - ); - return null; - } else { - type = module[model.tagName]; - } - } else { - type = model.tagName; - } - return binding.create( - type, - createElementAttributes(model, layoutContext.sendEvent), - createElementChildren(model, (child) => - createElementFromModuleBinding( - layoutContext, - currentImportSource, - module, - binding, - child - ) - ) - ); -} - -function isImportSourceEqual(source1, source2) { - return ( - source1.source === source2.source && - source1.sourceType === source2.sourceType - ); -} - -function stringifyImportSource(importSource) { - return JSON.stringify({ - source: importSource.source, - sourceType: importSource.sourceType, - }); -} diff --git a/src/client/packages/client/src/index.js b/src/client/packages/client/src/index.js deleted file mode 100644 index 8f7769652..000000000 --- a/src/client/packages/client/src/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./mount.js"; -export * from "./contexts.js"; -export * from "./components.js"; -export * from "./server.js"; diff --git a/src/client/packages/client/src/mount.js b/src/client/packages/client/src/mount.js deleted file mode 100644 index c7472eb12..000000000 --- a/src/client/packages/client/src/mount.js +++ /dev/null @@ -1,105 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { Layout } from "./components.js"; - -export function mountLayout(mountElement, layoutProps) { - ReactDOM.render(React.createElement(Layout, layoutProps), mountElement); -} - -export function mountLayoutWithWebSocket( - element, - endpoint, - loadImportSource, - maxReconnectTimeout -) { - mountLayoutWithReconnectingWebSocket( - element, - endpoint, - loadImportSource, - maxReconnectTimeout - ); -} - -function mountLayoutWithReconnectingWebSocket( - element, - endpoint, - loadImportSource, - maxReconnectTimeout, - mountState = { - everMounted: false, - reconnectAttempts: 0, - reconnectTimeoutRange: 0, - } -) { - const socket = new WebSocket(endpoint); - - const updateHookPromise = new LazyPromise(); - - socket.onopen = (event) => { - console.info(`ReactPy WebSocket connected.`); - - if (mountState.everMounted) { - ReactDOM.unmountComponentAtNode(element); - } - _resetOpenMountState(mountState); - - mountLayout(element, { - loadImportSource, - saveUpdateHook: updateHookPromise.resolve, - sendEvent: (event) => socket.send(JSON.stringify(event)), - }); - }; - - socket.onmessage = (event) => { - const message = JSON.parse(event.data); - updateHookPromise.promise.then((update) => update(message)); - }; - - socket.onclose = (event) => { - if (!maxReconnectTimeout) { - console.info(`ReactPy WebSocket connection lost.`); - return; - } - - const reconnectTimeout = _nextReconnectTimeout( - maxReconnectTimeout, - mountState - ); - - console.info( - `ReactPy WebSocket connection lost. Reconnecting in ${reconnectTimeout} seconds...` - ); - - setTimeout(function () { - mountState.reconnectAttempts++; - mountLayoutWithReconnectingWebSocket( - element, - endpoint, - loadImportSource, - maxReconnectTimeout, - mountState - ); - }, reconnectTimeout * 1000); - }; -} - -function _resetOpenMountState(mountState) { - mountState.everMounted = true; - mountState.reconnectAttempts = 0; - mountState.reconnectTimeoutRange = 0; -} - -function _nextReconnectTimeout(maxReconnectTimeout, mountState) { - const timeout = - Math.floor(Math.random() * mountState.reconnectTimeoutRange) || 1; - mountState.reconnectTimeoutRange = - (mountState.reconnectTimeoutRange + 5) % maxReconnectTimeout; - return timeout; -} - -function LazyPromise() { - this.promise = new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; - }); -} diff --git a/src/client/packages/client/src/server.js b/src/client/packages/client/src/server.js deleted file mode 100644 index 557f228f7..000000000 --- a/src/client/packages/client/src/server.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { mountLayoutWithWebSocket } from "./mount.js"; - -export function mountWithLayoutServer( - element, - serverInfo, - maxReconnectTimeout -) { - const loadImportSource = (source, sourceType) => - import( - sourceType == "NAME" ? serverInfo.path.module(source) : source - ).catch((error) => { - // Added a catch to silence a build warning caller so we just re-throw. - // The caller is actually responsible for catching this error. - throw error; - }); - - mountLayoutWithWebSocket( - element, - serverInfo.path.stream, - loadImportSource, - maxReconnectTimeout - ); -} - -export function LayoutServerInfo({ host, port, path, query, secure }) { - const wsProtocol = `ws${secure ? "s" : ""}`; - const wsBaseUrl = `${wsProtocol}://${host}:${port}`; - - let pathName = path || new URL(document.baseURI).pathname; - if (pathName.endsWith("/")) { - pathName = pathName.slice(0, -1); - } - - if (query) { - query = `?${query}`; - } else { - query = ""; - } - - this.path = { - stream: `${wsBaseUrl}/_reactpy/stream${pathName}${query}`, - module: (source) => `/_reactpy/modules/${source}`, - }; -} diff --git a/src/client/packages/client/tests/event-to-object.test.js b/src/client/packages/client/tests/event-to-object.test.js deleted file mode 100644 index 596a9dd4e..000000000 --- a/src/client/packages/client/tests/event-to-object.test.js +++ /dev/null @@ -1,353 +0,0 @@ -import { test } from "uvu"; -import lodash from "lodash"; -import * as assert from "uvu/assert"; -import { serializeEvent } from "../src/event-to-object.js"; -import "./tooling/setup.js"; - -const mockBoundingRect = { - left: 0, - top: 0, - right: 0, - bottom: 0, - x: 0, - y: 0, - width: 0, -}; - -const mockElement = { - tagName: null, - getBoundingClientRect: () => mockBoundingRect, -}; - -const allTargetData = { - files: [ - { - lastModified: 0, - name: "something", - type: "some-type", - size: 0, - }, - ], - value: "something", - currentTime: 35, - tagName: null, // overwritten in tests - elements: [ - { ...mockElement, tagName: "INPUT", value: "first" }, - { ...mockElement, tagName: "INPUT", value: "second" }, - ], -}; - -function assertEqualSerializedEventData(eventData, expectedSerializedData) { - const commonEventData = { - target: mockElement, - currentTarget: mockElement, - relatedTarget: mockElement, - }; - - const commonSerializedEventData = { - target: { boundingClientRect: mockBoundingRect }, - currentTarget: { boundingClientRect: mockBoundingRect }, - relatedTarget: { boundingClientRect: mockBoundingRect }, - }; - - assert.equal( - serializeEvent(lodash.merge({}, commonEventData, eventData)), - lodash.merge({}, commonSerializedEventData, expectedSerializedData) - ); -} - -[ - { - case: "adds 'files' and 'value' attributes for INPUT if type=file", - tagName: "INPUT", - addTargetAttrs: { type: "file" }, - output: { - target: { - files: allTargetData.files, - value: allTargetData.value, - }, - }, - }, - ...["BUTTON", "INPUT", "OPTION", "LI", "METER", "PROGRESS", "PARAM"].map( - (tagName) => ({ - case: `adds 'value' attribute for ${tagName} element`, - tagName, - output: { target: { value: allTargetData.value } }, - }) - ), - ...["AUDIO", "VIDEO"].map((tagName) => ({ - case: `adds 'currentTime' attribute for ${tagName} element`, - tagName, - output: { target: { currentTime: allTargetData.currentTime } }, - })), - ...["FORM"].map((tagName) => ({ - case: `adds 'elements' attribute for ${tagName} element`, - tagName, - output: { - target: { - elements: [ - { - value: "first", - boundingClientRect: mockBoundingRect, - }, - { - value: "second", - boundingClientRect: mockBoundingRect, - }, - ], - }, - }, - })), -].forEach((expectation) => { - test(`serializeEvent() ${expectation.case}`, () => { - const eventData = { - target: { - ...allTargetData, - tagName: expectation.tagName, - }, - }; - if (expectation.addTargetAttrs) { - Object.assign(eventData.target, expectation.addTargetAttrs); - } - assertEqualSerializedEventData(eventData, expectation.output); - }); -}); - -const allEventData = { - type: null, // set in text - target: { tagName: null }, // avoid triggering target specific transformations - clipboardData: "clipboardData", - data: "data", - altKey: "altKey", - charCode: "charCode", - ctrlKey: "ctrlKey", - key: "key", - keyCode: "keyCode", - locale: "locale", - location: "location", - metaKey: "metaKey", - repeat: "repeat", - shiftKey: "shiftKey", - which: "which", - altKey: "altKey", - button: "button", - buttons: "buttons", - clientX: "clientX", - clientY: "clientY", - ctrlKey: "ctrlKey", - form: "form", - metaKey: "metaKey", - pageX: "pageX", - pageY: "pageY", - screenX: "screenX", - screenY: "screenY", - shiftKey: "shiftKey", - pointerId: "pointerId", - width: "width", - height: "height", - pressure: "pressure", - tiltX: "tiltX", - tiltY: "tiltY", - pointerType: "pointerType", - isPrimary: "isPrimary", - altKey: "altKey", - ctrlKey: "ctrlKey", - metaKey: "metaKey", - shiftKey: "shiftKey", - detail: "detail", - deltaMode: "deltaMode", - deltaX: "deltaX", - deltaY: "deltaY", - deltaZ: "deltaZ", - animationName: "animationName", - pseudoElement: "pseudoElement", - elapsedTime: "elapsedTime", - propertyName: "propertyName", - pseudoElement: "pseudoElement", - elapsedTime: "elapsedTime", -}; - -[ - ...["copy", "cut", "paste"].map((eventType) => ({ - eventType, - case: "clipboard", - output: { clipboardData: "clipboardData" }, - })), - ...["compositionend", "compositionstart", "compositionupdate"].map( - (eventType) => ({ - eventType, - case: "composition", - output: { data: "data" }, - }) - ), - ...["keydown", "keypress", "keyup"].map((eventType) => ({ - eventType, - case: "keyboard", - output: { - altKey: "altKey", - charCode: "charCode", - ctrlKey: "ctrlKey", - key: "key", - keyCode: "keyCode", - locale: "locale", - location: "location", - metaKey: "metaKey", - repeat: "repeat", - shiftKey: "shiftKey", - which: "which", - }, - })), - ...[ - "click", - "contextmenu", - "doubleclick", - "drag", - "dragend", - "dragenter", - "dragexit", - "dragleave", - "dragover", - "dragstart", - "drop", - "mousedown", - "mouseenter", - "mouseleave", - "mousemove", - "mouseout", - "mouseover", - "mouseup", - ].map((eventType) => ({ - eventType, - case: "mouse", - output: { - altKey: "altKey", - button: "button", - buttons: "buttons", - clientX: "clientX", - clientY: "clientY", - ctrlKey: "ctrlKey", - metaKey: "metaKey", - pageX: "pageX", - pageY: "pageY", - screenX: "screenX", - screenY: "screenY", - shiftKey: "shiftKey", - }, - })), - ...[ - "pointerdown", - "pointermove", - "pointerup", - "pointercancel", - "gotpointercapture", - "lostpointercapture", - "pointerenter", - "pointerleave", - "pointerover", - "pointerout", - ].map((eventType) => ({ - eventType, - case: "pointer", - output: { - pointerId: "pointerId", - width: "width", - height: "height", - pressure: "pressure", - tiltX: "tiltX", - tiltY: "tiltY", - pointerType: "pointerType", - altKey: "altKey", - button: "button", - buttons: "buttons", - clientX: "clientX", - clientY: "clientY", - ctrlKey: "ctrlKey", - metaKey: "metaKey", - pageX: "pageX", - pageY: "pageY", - screenX: "screenX", - screenY: "screenY", - shiftKey: "shiftKey", - isPrimary: "isPrimary", - }, - })), - ...["touchcancel", "touchend", "touchmove", "touchstart"].map( - (eventType) => ({ - eventType, - case: "touch", - output: { - altKey: "altKey", - ctrlKey: "ctrlKey", - metaKey: "metaKey", - shiftKey: "shiftKey", - }, - }) - ), - { - eventType: "scroll", - case: "ui", - output: { - detail: "detail", - }, - }, - { - eventType: "wheel", - case: "wheel", - output: { - deltaMode: "deltaMode", - deltaX: "deltaX", - deltaY: "deltaY", - deltaZ: "deltaZ", - }, - }, - ...["animationstart", "animationend", "animationiteration"].map( - (eventType) => ({ - eventType, - case: "animation", - output: { - animationName: "animationName", - pseudoElement: "pseudoElement", - elapsedTime: "elapsedTime", - }, - }) - ), - { - eventType: "transitionend", - case: "transition", - output: { - propertyName: "propertyName", - pseudoElement: "pseudoElement", - elapsedTime: "elapsedTime", - }, - }, -].forEach((expectation) => { - test(`serializeEvent() adds ${expectation.case} attributes`, () => { - assertEqualSerializedEventData( - { ...allEventData, type: expectation.eventType }, - expectation.output - ); - }); -}); - -const mockElementsToSelect = ` -
-

START

-

MIDDLE

-

END

-
-`; - -test("serializeEvent() adds text of current selection", () => { - document.body.innerHTML = mockElementsToSelect; - const start = document.getElementById("start"); - const end = document.getElementById("end"); - window.getSelection().setBaseAndExtent(start, 0, end, 0); - assertEqualSerializedEventData( - { ...allEventData, type: "select" }, - { - selectedText: "START\nMIDDLE\n", - } - ); -}); - -test.run(); diff --git a/src/client/packages/client/tests/tooling/dom.js b/src/client/packages/client/tests/tooling/dom.js deleted file mode 100644 index e97eac844..000000000 --- a/src/client/packages/client/tests/tooling/dom.js +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from "react"; -import * as ReactTestUtils from "react-dom/test-utils.js"; - -export function render(Tag, props = {}) { - const container = window.document.querySelector("main"); - const component = React.h(Tag, props); - React.render(component, container); - return { container, component }; -} - -export async function fire(elem, event, details) { - await ReactTestUtils.act(() => { - let evt = new window.Event(event, details); - elem.dispatchEvent(evt); - }); -} diff --git a/src/client/packages/event-to-object/package.json b/src/client/packages/event-to-object/package.json new file mode 100644 index 000000000..caa871861 --- /dev/null +++ b/src/client/packages/event-to-object/package.json @@ -0,0 +1,34 @@ +{ + "author": "Ryan Morshead", + "license": "MIT", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "name": "event-to-object", + "description": "A client for ReactPy implemented in React", + "type": "module", + "version": "0.1.0", + "dependencies": { + "event-to-object": "file:packages/event-to-object", + "json-pointer": "^0.6.2" + }, + "devDependencies": { + "happy-dom": "^8.9.0", + "lodash": "^4.17.21", + "prettier": "^3.0.0-alpha.6", + "tsm": "^2.0.0", + "typescript": "^4.9.5", + "uvu": "^0.5.1" + }, + "repository": { + "type": "git", + "url": "https://github.com/reactive-python/reactpy" + }, + "scripts": { + "build": "tsc -b", + "format": "prettier --write .", + "test": "npm run check:tests", + "check:format": "prettier --check .", + "check:tests": "uvu -r tsm tests", + "check:types": "tsc --noEmit" + } +} diff --git a/src/client/packages/event-to-object/src/events.ts b/src/client/packages/event-to-object/src/events.ts new file mode 100644 index 000000000..bdc353501 --- /dev/null +++ b/src/client/packages/event-to-object/src/events.ts @@ -0,0 +1,263 @@ +// TODO +type FileListObject = any; +type DataTransferItemListObject = any; + +export type EventToObjectMap = { + event: [Event, EventObject]; + animation: [AnimationEvent, AnimationEventObject]; + clipboard: [ClipboardEvent, ClipboardEventObject]; + composition: [CompositionEvent, CompositionEventObject]; + devicemotion: [DeviceMotionEvent, DeviceMotionEventObject]; + deviceorientation: [DeviceOrientationEvent, DeviceOrientationEventObject]; + drag: [DragEvent, DragEventObject]; + focus: [FocusEvent, FocusEventObject]; + formdata: [FormDataEvent, FormDataEventObject]; + gamepad: [GamepadEvent, GamepadEventObject]; + input: [InputEvent, InputEventObject]; + keyboard: [KeyboardEvent, KeyboardEventObject]; + mouse: [MouseEvent, MouseEventObject]; + pointer: [PointerEvent, PointerEventObject]; + submit: [SubmitEvent, SubmitEventObject]; + touch: [TouchEvent, TouchEventObject]; + transition: [TransitionEvent, TransitionEventObject]; + ui: [UIEvent, UIEventObject]; + wheel: [WheelEvent, WheelEventObject]; +}; + +export interface EventObject { + bubbles: boolean; + composed: boolean; + currentTarget: ElementObject | null; + defaultPrevented: boolean; + eventPhase: number; + isTrusted: boolean; + target: ElementObject | null; + timeStamp: DOMHighResTimeStamp; + type: string; + selection: SelectionObject | null; +} + +export interface SubmitEventObject extends EventObject { + submitter: ElementObject; +} + +export interface InputEventObject extends UIEventObject { + data: string | null; + dataTransfer: DataTransferObject | null; + isComposing: boolean; + inputType: string; +} + +export interface GamepadEventObject extends EventObject { + gamepad: GamepadObject; +} + +export interface GamepadObject { + axes: number[]; + buttons: GamepadButtonObject[]; + connected: boolean; + hapticActuators: GamepadHapticActuatorObject[]; + id: string; + index: number; + mapping: GamepadMappingType; + timestamp: DOMHighResTimeStamp; +} + +export interface GamepadButtonObject { + pressed: boolean; + touched: boolean; + value: number; +} +export interface GamepadHapticActuatorObject { + type: string; +} + +export interface DragEventObject extends MouseEventObject { + /** Returns the DataTransfer object for the event. */ + readonly dataTransfer: DataTransferObject | null; +} + +export interface DeviceMotionEventObject extends EventObject { + acceleration: DeviceAccelerationObject | null; + accelerationIncludingGravity: DeviceAccelerationObject | null; + interval: number; + rotationRate: DeviceRotationRateObject | null; +} + +export interface DeviceAccelerationObject { + x: number | null; + y: number | null; + z: number | null; +} + +export interface DeviceRotationRateObject { + alpha: number | null; + beta: number | null; + gamma: number | null; +} + +export interface DeviceOrientationEventObject extends EventObject { + absolute: boolean; + alpha: number | null; + beta: number | null; + gamma: number | null; +} + +export interface MouseEventObject extends EventObject { + altKey: boolean; + button: number; + buttons: number; + clientX: number; + clientY: number; + ctrlKey: boolean; + metaKey: boolean; + movementX: number; + movementY: number; + offsetX: number; + offsetY: number; + pageX: number; + pageY: number; + relatedTarget: ElementObject | null; + screenX: number; + screenY: number; + shiftKey: boolean; + x: number; + y: number; +} + +export interface FormDataEventObject extends EventObject { + formData: FormDataObject; +} + +export type FormDataObject = [string, string | FileObject][]; + +export interface AnimationEventObject extends EventObject { + animationName: string; + elapsedTime: number; + pseudoElement: string; +} + +export interface ClipboardEventObject extends EventObject { + clipboardData: DataTransferObject | null; +} + +export interface UIEventObject extends EventObject { + detail: number; +} + +/** The DOM CompositionEvent represents events that occur due to the user indirectly + * entering text. */ +export interface CompositionEventObject extends UIEventObject { + data: string; +} + +export interface KeyboardEventObject extends UIEventObject { + altKey: boolean; + code: string; + ctrlKey: boolean; + isComposing: boolean; + key: string; + location: number; + metaKey: boolean; + repeat: boolean; + shiftKey: boolean; +} + +export interface FocusEventObject extends UIEventObject { + relatedTarget: ElementObject | null; +} + +export interface TouchEventObject extends UIEventObject { + altKey: boolean; + changedTouches: TouchObject[]; + ctrlKey: boolean; + metaKey: boolean; + shiftKey: boolean; + targetTouches: TouchObject[]; + touches: TouchObject[]; +} + +export interface PointerEventObject extends MouseEventObject { + height: number; + isPrimary: boolean; + pointerId: number; + pointerType: string; + pressure: number; + tangentialPressure: number; + tiltX: number; + tiltY: number; + twist: number; + width: number; +} + +export interface TransitionEventObject extends EventObject { + elapsedTime: number; + propertyName: string; + pseudoElement: string; +} + +export interface WheelEventObject extends MouseEventObject { + readonly deltaMode: number; + readonly deltaX: number; + readonly deltaY: number; + readonly deltaZ: number; +} + +export interface TouchObject { + clientX: number; + clientY: number; + force: number; + identifier: number; + pageX: number; + pageY: number; + radiusX: number; + radiusY: number; + rotationAngle: number; + screenX: number; + screenY: number; + target: ElementObject; +} + +export interface DataTransferObject { + dropEffect: "none" | "copy" | "link" | "move"; + effectAllowed: + | "none" + | "copy" + | "copyLink" + | "copyMove" + | "link" + | "linkMove" + | "move" + | "all" + | "uninitialized"; + files: FileListObject; + items: DataTransferItemListObject; + types: string[]; +} + +export interface SelectionObject { + anchorNode: ElementObject | null; + anchorOffset: number; + focusNode: ElementObject | null; + focusOffset: number; + isCollapsed: boolean; + rangeCount: number; + type: string; + selectedText: string; +} + +export interface ElementObject { + value?: string; + textContent?: string; +} + +export interface FileObject { + name: string; + size: number; + type: string; +} + +type NONE = 0; +type CAPTURING_PHASE = 1; +type AT_TARGET = 2; +type BUBBLING_PHASE = 3; diff --git a/src/client/packages/event-to-object/src/index.ts b/src/client/packages/event-to-object/src/index.ts new file mode 100644 index 000000000..9a40a2128 --- /dev/null +++ b/src/client/packages/event-to-object/src/index.ts @@ -0,0 +1,427 @@ +import * as e from "./events"; + +export default function convert( + event: E, +): + | { + [K in keyof e.EventToObjectMap]: e.EventToObjectMap[K] extends [ + E, + infer P, + ] + ? P + : never; + }[keyof e.EventToObjectMap] + | null { + return event.type in eventConverters + ? eventConverters[event.type](event) + : convertEvent(event); +} + +const convertEvent = (event: Event): e.EventObject => ({ + /** Returns true or false depending on how event was initialized. True if event goes + * through its target's ancestors in reverse tree order, and false otherwise. */ + bubbles: event.bubbles, + composed: event.composed, + currentTarget: convertElement(event.currentTarget), + defaultPrevented: event.defaultPrevented, + eventPhase: event.eventPhase, + isTrusted: event.isTrusted, + target: convertElement(event.target), + timeStamp: event.timeStamp, + type: event.type, + selection: convertSelection(window.getSelection()), +}); + +const convertClipboardEvent = ( + event: ClipboardEvent, +): e.ClipboardEventObject => ({ + ...convertEvent(event), + clipboardData: convertDataTransferObject(event.clipboardData), +}); + +const convertCompositionEvent = ( + event: CompositionEvent, +): e.CompositionEventObject => ({ + ...convertUiEvent(event), + data: event.data, +}); + +const convertInputEvent = (event: InputEvent): e.InputEventObject => ({ + ...convertUiEvent(event), + data: event.data, + inputType: event.inputType, + dataTransfer: convertDataTransferObject(event.dataTransfer), + isComposing: event.isComposing, +}); + +const convertKeyboardEvent = (event: KeyboardEvent): e.KeyboardEventObject => ({ + ...convertUiEvent(event), + code: event.code, + isComposing: event.isComposing, + altKey: event.altKey, + ctrlKey: event.ctrlKey, + key: event.key, + location: event.location, + metaKey: event.metaKey, + repeat: event.repeat, + shiftKey: event.shiftKey, +}); + +const convertMouseEvent = (event: MouseEvent): e.MouseEventObject => ({ + ...convertEvent(event), + altKey: event.altKey, + button: event.button, + buttons: event.buttons, + clientX: event.clientX, + clientY: event.clientY, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + pageX: event.pageX, + pageY: event.pageY, + screenX: event.screenX, + screenY: event.screenY, + shiftKey: event.shiftKey, + movementX: event.movementX, + movementY: event.movementY, + offsetX: event.offsetX, + offsetY: event.offsetY, + x: event.x, + y: event.y, + relatedTarget: convertElement(event.relatedTarget), +}); + +const convertTouchEvent = (event: TouchEvent): e.TouchEventObject => ({ + ...convertUiEvent(event), + altKey: event.altKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + shiftKey: event.shiftKey, + touches: Array.from(event.touches).map(convertTouch), + changedTouches: Array.from(event.changedTouches).map(convertTouch), + targetTouches: Array.from(event.targetTouches).map(convertTouch), +}); + +const convertUiEvent = (event: UIEvent): e.UIEventObject => ({ + ...convertEvent(event), + detail: event.detail, +}); + +const convertAnimationEvent = ( + event: AnimationEvent, +): e.AnimationEventObject => ({ + ...convertEvent(event), + animationName: event.animationName, + pseudoElement: event.pseudoElement, + elapsedTime: event.elapsedTime, +}); + +const convertTransitionEvent = ( + event: TransitionEvent, +): e.TransitionEventObject => ({ + ...convertEvent(event), + propertyName: event.propertyName, + pseudoElement: event.pseudoElement, + elapsedTime: event.elapsedTime, +}); + +const convertFocusEvent = (event: FocusEvent): e.FocusEventObject => ({ + ...convertUiEvent(event), + relatedTarget: convertElement(event.relatedTarget), +}); + +const convertDeviceOrientationEvent = ( + event: DeviceOrientationEvent, +): e.DeviceOrientationEventObject => ({ + ...convertEvent(event), + absolute: event.absolute, + alpha: event.alpha, + beta: event.beta, + gamma: event.gamma, +}); + +const convertDragEvent = (event: DragEvent): e.DragEventObject => ({ + ...convertMouseEvent(event), + dataTransfer: convertDataTransferObject(event.dataTransfer), +}); + +const convertGamepadEvent = (event: GamepadEvent): e.GamepadEventObject => ({ + ...convertEvent(event), + gamepad: convertGamepad(event.gamepad), +}); + +const convertPointerEvent = (event: PointerEvent): e.PointerEventObject => ({ + ...convertMouseEvent(event), + pointerId: event.pointerId, + width: event.width, + height: event.height, + pressure: event.pressure, + tiltX: event.tiltX, + tiltY: event.tiltY, + pointerType: event.pointerType, + isPrimary: event.isPrimary, + tangentialPressure: event.tangentialPressure, + twist: event.twist, +}); + +const convertWheelEvent = (event: WheelEvent): e.WheelEventObject => ({ + ...convertMouseEvent(event), + deltaMode: event.deltaMode, + deltaX: event.deltaX, + deltaY: event.deltaY, + deltaZ: event.deltaZ, +}); + +const convertSubmitEvent = (event: SubmitEvent): e.SubmitEventObject => ({ + ...convertEvent(event), + submitter: convertElement(event.submitter), +}); + +const eventConverters: { [key: string]: (event: any) => any } = { + // animation events + animationcancel: convertAnimationEvent, + animationend: convertAnimationEvent, + animationiteration: convertAnimationEvent, + animationstart: convertAnimationEvent, + // input events + beforeinput: convertInputEvent, + // composition events + compositionend: convertCompositionEvent, + compositionstart: convertCompositionEvent, + compositionupdate: convertCompositionEvent, + // clipboard events + copy: convertClipboardEvent, + cut: convertClipboardEvent, + paste: convertClipboardEvent, + // device orientation events + deviceorientation: convertDeviceOrientationEvent, + // drag events + drag: convertDragEvent, + dragend: convertDragEvent, + dragenter: convertDragEvent, + dragleave: convertDragEvent, + dragover: convertDragEvent, + dragstart: convertDragEvent, + drop: convertDragEvent, + // ui events + error: convertUiEvent, + // focus events + blur: convertFocusEvent, + focus: convertFocusEvent, + focusin: convertFocusEvent, + focusout: convertFocusEvent, + // gamepad events + gamepadconnected: convertGamepadEvent, + gamepaddisconnected: convertGamepadEvent, + // keyboard events + keydown: convertKeyboardEvent, + keypress: convertKeyboardEvent, + keyup: convertKeyboardEvent, + // mouse events + auxclick: convertMouseEvent, + click: convertMouseEvent, + dblclick: convertMouseEvent, + contextmenu: convertMouseEvent, + mousedown: convertMouseEvent, + mouseenter: convertMouseEvent, + mouseleave: convertMouseEvent, + mousemove: convertMouseEvent, + mouseout: convertMouseEvent, + mouseover: convertMouseEvent, + mouseup: convertMouseEvent, + scroll: convertMouseEvent, + // pointer events + gotpointercapture: convertPointerEvent, + lostpointercapture: convertPointerEvent, + pointercancel: convertPointerEvent, + pointerdown: convertPointerEvent, + pointerenter: convertPointerEvent, + pointerleave: convertPointerEvent, + pointerlockchange: convertPointerEvent, + pointerlockerror: convertPointerEvent, + pointermove: convertPointerEvent, + pointerout: convertPointerEvent, + pointerover: convertPointerEvent, + pointerup: convertPointerEvent, + // submit events + submit: convertSubmitEvent, + // touch events + touchcancel: convertTouchEvent, + touchend: convertTouchEvent, + touchmove: convertTouchEvent, + touchstart: convertTouchEvent, + // transition events + transitioncancel: convertTransitionEvent, + transitionend: convertTransitionEvent, + transitionrun: convertTransitionEvent, + transitionstart: convertTransitionEvent, + // wheel events + wheel: convertWheelEvent, +}; + +function convertElement(element: EventTarget | HTMLElement | null): any { + if (!element || !("tagName" in element)) { + return null; + } + + const htmlElement = element as HTMLElement; + + return { + ...convertGenericElement(htmlElement), + ...(htmlElement.tagName in elementConverters + ? elementConverters[htmlElement.tagName](htmlElement) + : {}), + }; +} + +const convertGenericElement = (element: HTMLElement) => ({ + tagName: element.tagName, + boundingClientRect: { ...element.getBoundingClientRect() }, +}); + +const convertMediaElement = (element: HTMLMediaElement) => ({ + currentTime: element.currentTime, + duration: element.duration, + ended: element.ended, + error: element.error, + seeking: element.seeking, + volume: element.volume, +}); + +const elementConverters: { [key: string]: (element: any) => any } = { + AUDIO: convertMediaElement, + BUTTON: (element: HTMLButtonElement) => ({ value: element.value }), + DATA: (element: HTMLDataElement) => ({ value: element.value }), + DATALIST: (element: HTMLDataListElement) => ({ + options: Array.from(element.options).map(elementConverters["OPTION"]), + }), + DIALOG: (element: HTMLDialogElement) => ({ + returnValue: element.returnValue, + }), + FIELDSET: (element: HTMLFieldSetElement) => ({ + elements: Array.from(element.elements).map(convertElement), + }), + FORM: (element: HTMLFormElement) => ({ + elements: Array.from(element.elements).map(convertElement), + }), + INPUT: (element: HTMLInputElement) => ({ value: element.value }), + METER: (element: HTMLMeterElement) => ({ value: element.value }), + OPTION: (element: HTMLOptionElement) => ({ value: element.value }), + OUTPUT: (element: HTMLOutputElement) => ({ value: element.value }), + PROGRESS: (element: HTMLProgressElement) => ({ value: element.value }), + SELECT: (element: HTMLSelectElement) => ({ value: element.value }), + TEXTAREA: (element: HTMLTextAreaElement) => ({ value: element.value }), + VIDEO: convertMediaElement, +}; + +const convertGamepad = (gamepad: Gamepad): e.GamepadObject => ({ + axes: Array.from(gamepad.axes), + buttons: Array.from(gamepad.buttons).map(convertGamepadButton), + connected: gamepad.connected, + id: gamepad.id, + index: gamepad.index, + mapping: gamepad.mapping, + timestamp: gamepad.timestamp, + hapticActuators: Array.from(gamepad.hapticActuators).map( + convertGamepadHapticActuator, + ), +}); + +const convertGamepadButton = ( + button: GamepadButton, +): e.GamepadButtonObject => ({ + pressed: button.pressed, + touched: button.touched, + value: button.value, +}); + +const convertGamepadHapticActuator = ( + actuator: GamepadHapticActuator, +): e.GamepadHapticActuatorObject => ({ + type: actuator.type, +}); + +const convertFile = (file: File) => ({ + lastModified: file.lastModified, + name: file.name, + size: file.size, + type: file.type, +}); + +function convertDataTransferObject( + dataTransfer: DataTransfer | null, +): e.DataTransferObject | null { + if (!dataTransfer) { + return null; + } + const { dropEffect, effectAllowed, files, items, types } = dataTransfer; + return { + dropEffect, + effectAllowed, + files: Array.from(files).map(convertFile), + items: Array.from(items).map((item) => ({ + kind: item.kind, + type: item.type, + })), + types: Array.from(types), + }; +} + +function convertSelection( + selection: Selection | null, +): e.SelectionObject | null { + if (!selection) { + return null; + } + const { + type, + anchorNode, + anchorOffset, + focusNode, + focusOffset, + isCollapsed, + rangeCount, + } = selection; + if (type === "None") { + return null; + } + return { + type, + anchorNode: convertElement(anchorNode), + anchorOffset, + focusNode: convertElement(focusNode), + focusOffset, + isCollapsed, + rangeCount, + selectedText: selection.toString(), + }; +} + +function convertTouch({ + identifier, + pageX, + pageY, + screenX, + screenY, + clientX, + clientY, + force, + radiusX, + radiusY, + rotationAngle, + target, +}: Touch): e.TouchObject { + return { + identifier, + pageX, + pageY, + screenX, + screenY, + clientX, + clientY, + force, + radiusX, + radiusY, + rotationAngle, + target: convertElement(target), + }; +} diff --git a/src/client/packages/event-to-object/tests/event-to-object.test.ts b/src/client/packages/event-to-object/tests/event-to-object.test.ts new file mode 100644 index 000000000..bad3c28aa --- /dev/null +++ b/src/client/packages/event-to-object/tests/event-to-object.test.ts @@ -0,0 +1,381 @@ +// @ts-ignore +import { window } from "./tooling/setup"; +import { test } from "uvu"; +import { Event } from "happy-dom"; +import { checkEventConversion } from "./tooling/check"; +import { + mockElementObject, + mockGamepad, + mockTouch, + mockTouchObject, +} from "./tooling/mock"; + +type SimpleTestCase = { + types: string[]; + description: string; + givenEventType: new (type: string) => E; + expectedConversion: any; + initGivenEvent?: (event: E) => void; +}; + +const simpleTestCases: SimpleTestCase[] = [ + { + types: [ + "animationcancel", + "animationend", + "animationiteration", + "animationstart", + ], + description: "animation event", + givenEventType: window.AnimationEvent, + expectedConversion: { + animationName: "", + pseudoElement: "", + elapsedTime: 0, + }, + }, + { + types: ["beforeinput"], + description: "event", + givenEventType: window.InputEvent, + expectedConversion: { + detail: 0, + data: "", + inputType: "", + dataTransfer: null, + isComposing: false, + }, + }, + { + types: ["compositionend", "compositionstart", "compositionupdate"], + description: "composition event", + givenEventType: window.CompositionEvent, + expectedConversion: { + data: undefined, + detail: undefined, + }, + }, + { + types: ["copy", "cut", "paste"], + description: "clipboad event", + givenEventType: window.ClipboardEvent, + expectedConversion: { clipboardData: null }, + }, + { + types: [ + "drag", + "dragend", + "dragenter", + "dragleave", + "dragover", + "dragstart", + "drop", + ], + description: "drag event", + givenEventType: window.DragEvent, + expectedConversion: { + altKey: undefined, + button: undefined, + buttons: undefined, + clientX: undefined, + clientY: undefined, + ctrlKey: undefined, + dataTransfer: null, + metaKey: undefined, + movementX: undefined, + movementY: undefined, + offsetX: undefined, + offsetY: undefined, + pageX: undefined, + pageY: undefined, + relatedTarget: null, + screenX: undefined, + screenY: undefined, + shiftKey: undefined, + x: undefined, + y: undefined, + }, + }, + { + types: ["error"], + description: "event", + givenEventType: window.ErrorEvent, + expectedConversion: { detail: 0 }, + }, + { + types: ["blur", "focus", "focusin", "focusout"], + description: "focus event", + givenEventType: window.FocusEvent, + expectedConversion: { + relatedTarget: null, + detail: 0, + }, + }, + { + types: ["gamepadconnected", "gamepaddisconnected"], + description: "gamepad event", + givenEventType: window.GamepadEvent, + expectedConversion: { gamepad: mockGamepad }, + initGivenEvent: (event) => { + event.gamepad = mockGamepad; + }, + }, + { + types: ["keydown", "keypress", "keyup"], + description: "keyboard event", + givenEventType: window.KeyboardEvent, + expectedConversion: { + altKey: false, + code: "", + ctrlKey: false, + isComposing: false, + key: "", + location: 0, + metaKey: false, + repeat: false, + shiftKey: false, + detail: 0, + }, + }, + { + types: [ + "click", + "auxclick", + "dblclick", + "mousedown", + "mouseenter", + "mouseleave", + "mousemove", + "mouseout", + "mouseover", + "mouseup", + "scroll", + ], + description: "mouse event", + givenEventType: window.MouseEvent, + expectedConversion: { + altKey: false, + button: 0, + buttons: 0, + clientX: 0, + clientY: 0, + ctrlKey: false, + metaKey: false, + movementX: 0, + movementY: 0, + offsetX: 0, + offsetY: 0, + pageX: 0, + pageY: 0, + relatedTarget: null, + screenX: 0, + screenY: 0, + shiftKey: false, + x: undefined, + y: undefined, + }, + }, + { + types: [ + "auxclick", + "click", + "contextmenu", + "dblclick", + "mousedown", + "mouseenter", + "mouseleave", + "mousemove", + "mouseout", + "mouseover", + "mouseup", + ], + description: "mouse event", + givenEventType: window.MouseEvent, + expectedConversion: { + altKey: false, + button: 0, + buttons: 0, + clientX: 0, + clientY: 0, + ctrlKey: false, + metaKey: false, + movementX: 0, + movementY: 0, + offsetX: 0, + offsetY: 0, + pageX: 0, + pageY: 0, + relatedTarget: null, + screenX: 0, + screenY: 0, + shiftKey: false, + x: undefined, + y: undefined, + }, + }, + { + types: [ + "gotpointercapture", + "lostpointercapture", + "pointercancel", + "pointerdown", + "pointerenter", + "pointerleave", + "pointerlockchange", + "pointerlockerror", + "pointermove", + "pointerout", + "pointerover", + "pointerup", + ], + description: "pointer event", + givenEventType: window.PointerEvent, + expectedConversion: { + altKey: false, + button: 0, + buttons: 0, + clientX: 0, + clientY: 0, + ctrlKey: false, + metaKey: false, + movementX: 0, + movementY: 0, + offsetX: 0, + offsetY: 0, + pageX: 0, + pageY: 0, + relatedTarget: null, + screenX: 0, + screenY: 0, + shiftKey: false, + x: undefined, + y: undefined, + pointerId: 0, + pointerType: "", + pressure: 0, + tiltX: 0, + tiltY: 0, + width: 0, + height: 0, + isPrimary: false, + twist: 0, + tangentialPressure: 0, + }, + }, + { + types: ["submit"], + description: "event", + givenEventType: window.Event, + expectedConversion: { submitter: null }, + initGivenEvent: (event) => { + event.submitter = null; + }, + }, + { + types: ["touchcancel", "touchend", "touchmove", "touchstart"], + description: "touch event", + givenEventType: window.TouchEvent, + expectedConversion: { + altKey: undefined, + changedTouches: [mockTouchObject], + ctrlKey: undefined, + metaKey: undefined, + targetTouches: [mockTouchObject], + touches: [mockTouchObject], + detail: undefined, + shiftKey: undefined, + }, + initGivenEvent: (event) => { + event.changedTouches = [mockTouch]; + event.targetTouches = [mockTouch]; + event.touches = [mockTouch]; + }, + }, + { + types: [ + "transitioncancel", + "transitionend", + "transitionrun", + "transitionstart", + ], + description: "transition event", + givenEventType: window.TransitionEvent, + expectedConversion: { + propertyName: undefined, + elapsedTime: undefined, + pseudoElement: undefined, + }, + }, + { + types: ["wheel"], + description: "wheel event", + givenEventType: window.WheelEvent, + expectedConversion: { + altKey: undefined, + button: undefined, + buttons: undefined, + clientX: undefined, + clientY: undefined, + ctrlKey: undefined, + deltaMode: 0, + deltaX: 0, + deltaY: 0, + deltaZ: 0, + metaKey: undefined, + movementX: undefined, + movementY: undefined, + offsetX: undefined, + offsetY: undefined, + pageX: 0, + pageY: 0, + relatedTarget: null, + screenX: undefined, + screenY: undefined, + shiftKey: undefined, + x: undefined, + y: undefined, + }, + }, +]; + +simpleTestCases.forEach((testCase) => { + testCase.types.forEach((type) => { + test(`converts ${type} ${testCase.description}`, () => { + const event = new testCase.givenEventType(type); + if (testCase.initGivenEvent) { + testCase.initGivenEvent(event); + } + checkEventConversion(event, testCase.expectedConversion); + }); + }); +}); + +test("adds text of current selection", () => { + document.body.innerHTML = ` +
+

START

+

MIDDLE

+

END

+
+ `; + const start = document.getElementById("start"); + const end = document.getElementById("end"); + window.getSelection()!.setBaseAndExtent(start!, 0, end!, 0); + checkEventConversion(new window.Event("fake"), { + type: "fake", + selection: { + type: "Range", + anchorNode: { ...mockElementObject, tagName: "P" }, + anchorOffset: 0, + focusNode: { ...mockElementObject, tagName: "P" }, + focusOffset: 0, + isCollapsed: false, + rangeCount: 1, + selectedText: "START\n MIDDLE\n ", + }, + eventPhase: undefined, + isTrusted: undefined, + }); +}); + +test.run(); diff --git a/src/client/packages/event-to-object/tests/tooling/check.ts b/src/client/packages/event-to-object/tests/tooling/check.ts new file mode 100644 index 000000000..42a77480b --- /dev/null +++ b/src/client/packages/event-to-object/tests/tooling/check.ts @@ -0,0 +1,47 @@ +import * as assert from "uvu/assert"; +import { Event } from "happy-dom"; +// @ts-ignore +import lodash from "lodash"; +import convert from "../../src/index"; +import { mockElementObject } from "./mock"; + +export function checkEventConversion( + givenEvent: Event, + expectedConversion: any, +): void { + const actualSerializedEvent = convert( + // @ts-ignore + givenEvent, + ); + + if (!actualSerializedEvent) { + assert.equal(actualSerializedEvent, expectedConversion); + return; + } + + // too hard to compare + assert.equal(typeof actualSerializedEvent.timeStamp, "number"); + + assert.equal( + actualSerializedEvent, + lodash.merge( + { timeStamp: actualSerializedEvent.timeStamp, type: givenEvent.type }, + expectedConversionDefaults, + expectedConversion, + ), + ); + + // verify result is JSON serializable + JSON.stringify(actualSerializedEvent); +} + +const expectedConversionDefaults = { + target: null, + currentTarget: null, + bubbles: false, + composed: false, + defaultPrevented: false, + eventPhase: undefined, + isTrusted: undefined, + selection: null, +}; diff --git a/src/client/packages/event-to-object/tests/tooling/mock.ts b/src/client/packages/event-to-object/tests/tooling/mock.ts new file mode 100644 index 000000000..81e506500 --- /dev/null +++ b/src/client/packages/event-to-object/tests/tooling/mock.ts @@ -0,0 +1,61 @@ +export const mockBoundingRect = { + left: 0, + top: 0, + right: 0, + bottom: 0, + x: 0, + y: 0, + height: 0, + width: 0, +}; + +export const mockElementObject = { + tagName: null, + boundingClientRect: mockBoundingRect, +}; + +export const mockElement = { + tagName: null, + getBoundingClientRect: () => mockBoundingRect, +}; + +export const mockGamepad = { + id: "test", + index: 0, + connected: true, + mapping: "standard", + axes: [], + buttons: [ + { + pressed: false, + touched: false, + value: 0, + }, + ], + hapticActuators: [ + { + type: "vibration", + }, + ], + timestamp: undefined, +}; + +export const mockTouch = { + identifier: 0, + pageX: 0, + pageY: 0, + screenX: 0, + screenY: 0, + clientX: 0, + clientY: 0, + force: 0, + radiusX: 0, + radiusY: 0, + rotationAngle: 0, + target: mockElement, +}; + +export const mockTouchObject = { + ...mockTouch, + target: mockElementObject, +}; diff --git a/src/client/packages/client/tests/tooling/setup.js b/src/client/packages/event-to-object/tests/tooling/setup.js similarity index 79% rename from src/client/packages/client/tests/tooling/setup.js rename to src/client/packages/event-to-object/tests/tooling/setup.js index 86f50ed14..213578046 100644 --- a/src/client/packages/client/tests/tooling/setup.js +++ b/src/client/packages/event-to-object/tests/tooling/setup.js @@ -1,7 +1,7 @@ import { test } from "uvu"; -import { JSDOM } from "jsdom"; +import { Window } from "happy-dom"; -const { window } = new JSDOM("
"); +export const window = new Window(); export function setup() { global.window = window; @@ -15,6 +15,7 @@ export function reset() { window.document.title = ""; window.document.head.innerHTML = ""; window.document.body.innerHTML = "
"; + window.getSelection().removeAllRanges(); } test.before(setup); diff --git a/src/client/packages/event-to-object/tsconfig.json b/src/client/packages/event-to-object/tsconfig.json new file mode 100644 index 000000000..b9a031fa9 --- /dev/null +++ b/src/client/packages/event-to-object/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.package.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "composite": true + }, + "include": ["src"] +} diff --git a/src/client/packages/event-to-object/tsconfig.tests.json b/src/client/packages/event-to-object/tsconfig.tests.json new file mode 100644 index 000000000..33be69a56 --- /dev/null +++ b/src/client/packages/event-to-object/tsconfig.tests.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "esnext", + "allowJs": false, + "skipLibCheck": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + } +} diff --git a/src/client/tsconfig.package.json b/src/client/tsconfig.package.json new file mode 100644 index 000000000..79454a834 --- /dev/null +++ b/src/client/tsconfig.package.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "allowJs": false, + "allowSyntheticDefaultImports": true, + "declaration": true, + "declarationMap": true, + "esModuleInterop": false, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react", + "lib": ["DOM", "DOM.Iterable", "esnext"], + "module": "esnext", + "moduleResolution": "node", + "noEmit": false, + "resolveJsonModule": true, + "skipLibCheck": false, + "strict": true, + "target": "esnext" + } +} diff --git a/tests/test_backend/test_utils.py b/tests/test_backend/test_utils.py index 34f7e4024..2b36966f5 100644 --- a/tests/test_backend/test_utils.py +++ b/tests/test_backend/test_utils.py @@ -24,7 +24,7 @@ def test_find_available_port(): find_available_port("localhost", port_min=0, port_max=0) -async def test_run(page: Page, exit_stack: ExitStack): +async def test_run(page: Page): host = "127.0.0.1" port = find_available_port(host) url = f"http://{host}:{port}" diff --git a/tests/test_sample.py b/tests/test_sample.py index e7a281765..b92e89789 100644 --- a/tests/test_sample.py +++ b/tests/test_sample.py @@ -4,6 +4,5 @@ async def test_sample_app(display: DisplayFixture): await display.show(SampleApp) - h1 = await display.page.wait_for_selector("h1") assert (await h1.text_content()) == "Sample Application"