Compare commits
239 Commits
v0.0.32
...
4f2e0245d3
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f2e0245d3 | |||
| eecdbf6852 | |||
| ddc4603f13 | |||
| 759b522cd1 | |||
| 7ecb4a192d | |||
| d84626ac31 | |||
| 9c36e0db7b | |||
| fcd26bac1c | |||
| e8e7c98705 | |||
| b5af5cc223 | |||
| ba8253fa30 | |||
| f5bd389183 | |||
| 0c34a38e15 | |||
| 7c7857a6cd | |||
| 716bce2bb0 | |||
| 33fb96b120 | |||
| 28a4accabf | |||
| 31c7394c17 | |||
| e2974d34e2 | |||
| 4a06c84511 | |||
| 4960a1d9d6 | |||
| 75dd8889e9 | |||
| 111a6c3c6e | |||
| 775fdafa63 | |||
| dae38bbd83 | |||
| 35f374047a | |||
| aea4a14a62 | |||
| 98f7504a4c | |||
| bb52cdd7c2 | |||
| 07b660a0d6 | |||
| 2b9d712d48 | |||
| 3c1f60b62d | |||
| bb75edfd42 | |||
| c2b61cec2c | |||
| 05c3107b27 | |||
| bb67df7846 | |||
| 89ec523ea2 | |||
| f30458d953 | |||
| 42df0d830e | |||
| 50b2c0c7f4 | |||
| 0edb76b678 | |||
| 2d71af3243 | |||
| b571cd213b | |||
| b52c79ac4e | |||
| 63c6a5ab07 | |||
| 4447ea63e2 | |||
| 61200c4a7d | |||
| 62dc9d6cc0 | |||
| a28d41e1ee | |||
| 6a05e3770b | |||
| 53a93e510c | |||
| 1cb3ecf1ea | |||
| 687665cd6b | |||
| 7879ab1d50 | |||
| 24f0cdb398 | |||
| 6d5555e596 | |||
| 4052e3235f | |||
| 13302ad1c7 | |||
| 0f8687e473 | |||
| 9399ccd684 | |||
| b3604039fa | |||
| 732089da2c | |||
| b3e7e4b196 | |||
| 09a0cfd349 | |||
| 5bf7346321 | |||
| dd558c57e0 | |||
| 5647196924 | |||
| 49b1834bc6 | |||
| d111647ea8 | |||
| d7580dab9b | |||
| 28db8a8d5f | |||
| e64d5617e7 | |||
| acd114650a | |||
| 7a47ffaa61 | |||
| 42f7f66f35 | |||
| b2b4ffeeae | |||
| 26de1f7daa | |||
| 07605933dc | |||
| 4bdc7ec616 | |||
| 8ca64550e5 | |||
| 25dbac804c | |||
| 6ab3fd168b | |||
| 94858e2371 | |||
| 6d13502e94 | |||
| 77001e595c | |||
| 6fad20ffa3 | |||
| 00fb6c9839 | |||
| 97fcf72d63 | |||
| 5d8d02515d | |||
| 859fe1feb0 | |||
| 8f61d83f41 | |||
| 6423b3e479 | |||
| 2bc8cec8a2 | |||
| b49a6cd685 | |||
| 2885380f40 | |||
| 2ec3b6a249 | |||
| 3ef795452d | |||
| 479d87c8b8 | |||
| a56077dcc7 | |||
| d3f4587c3b | |||
| 623705b7a1 | |||
| 8f87f4751d | |||
| 2ac6dfde9d | |||
| 81ade7a400 | |||
| 63f7ff9f27 | |||
| 8a0fa17a79 | |||
| 0ead5ed967 | |||
| 53261a6fbc | |||
| c60ff86a4d | |||
| 83a0b017c5 | |||
| 3746622a11 | |||
| ccd50cf59f | |||
| 93680eb43d | |||
| 3ae4b7086a | |||
| 446b1f8600 | |||
| 00fd208a2c | |||
| e574d03716 | |||
| c1f3116c9d | |||
| 3aec7e6c14 | |||
| 9f0020dec8 | |||
| 6e78ad9729 | |||
| 44d84a9b2a | |||
| ac7809415c | |||
| 675cecaa20 | |||
| 5d179cc088 | |||
| d905618590 | |||
| 3fd9bc0b18 | |||
| 39abee7f73 | |||
| b770619111 | |||
| 1c44857da4 | |||
| bca4440867 | |||
| 4855543961 | |||
| cb3d6a98b9 | |||
| ada67a13d3 | |||
| f4c928f26e | |||
| 91fd515d39 | |||
| be6e841d3d | |||
| af6afa6903 | |||
| 6ab5d2a28d | |||
| 4be033f288 | |||
| c550f92003 | |||
| ed836b3ee0 | |||
| ac7a43abf4 | |||
| 49f19fce91 | |||
| b2197eb8e9 | |||
| 5fbc2cae1c | |||
| 730abb49ce | |||
| edccab054a | |||
| e8210c6fdd | |||
| 55d69d7c13 | |||
| 50fb18d4ff | |||
| 77b1ea1fc8 | |||
| 61501a9b64 | |||
| c1507adac5 | |||
| 45fb9eda1c | |||
| 982a61f4bf | |||
| 18e5b41663 | |||
| 910c39cbd0 | |||
| 9952dfd49d | |||
| 00f75d5382 | |||
| d78828554b | |||
| b84b561109 | |||
| a618815500 | |||
| e1f3dc6ae4 | |||
| f378db6c6f | |||
| 7cec0f7d61 | |||
| f902d0374c | |||
| b5f0a0c4f7 | |||
| 00623cea09 | |||
| ed4f1d6f2c | |||
| 73f4a3407f | |||
| 6f11318e84 | |||
| e88ee91f0e | |||
| 3f8daf257c | |||
| dc387acadc | |||
| 68aa41ab96 | |||
| 85b23437b3 | |||
| c59fba817d | |||
| c3415ab75c | |||
| f1d0151d71 | |||
| 3c5c1756d1 | |||
| 6a6b65d1b3 | |||
| 81bd54dbe6 | |||
| 6a1bb0d3bc | |||
| 705e8b553f | |||
| e4729b22f2 | |||
| 662112551a | |||
| 38fe88aab8 | |||
| 578c51faa0 | |||
| a3ccc73b81 | |||
| 7312f4d43a | |||
| 8b546c7e02 | |||
| c0b6ff2e64 | |||
| 638b7cc1e5 | |||
| 05e54e1be0 | |||
| 4c3299ead0 | |||
| 1ef56b35ad | |||
| 061e79c295 | |||
| 5edfe732b1 | |||
| a8f9b67f71 | |||
| de7fbf1eb7 | |||
| a51a3d7e43 | |||
| 433b3b1003 | |||
| 6703c5b584 | |||
| 5f729efabe | |||
| b2085b3f28 | |||
| 2f893494b0 | |||
| e26af21f63 | |||
| 7e1d738f8d | |||
| 199448e11e | |||
| fdaabab807 | |||
| ca4560c5c9 | |||
| 2478f3064d | |||
| e9b8b43e7c | |||
| 951155f1b6 | |||
| 1b678175ef | |||
| 8eb1f40eec | |||
| 235887b3bf | |||
| 0b3d66dd48 | |||
| beb9ef3754 | |||
| 9f6a480736 | |||
| b3bac2927d | |||
| ef389f2ba2 | |||
| ef21dc6ae8 | |||
| 6e55b6b49e | |||
| db115ef1bd | |||
| 678838dbd5 | |||
| 586f87625d | |||
| 1542370f9b | |||
| 1f7d5968c7 | |||
| 39e51f7790 | |||
| 052663efbe | |||
| 8f84ff2611 | |||
| 37e1c5d97b | |||
| cef526bcf3 | |||
| 6af36cafa9 | |||
| fca859d93d | |||
| 2178300d8d | |||
| 636bdcce6b |
@@ -48,7 +48,7 @@ jobs:
|
|||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
run: |
|
run: |
|
||||||
mkdir -p out/html/ ~/.ssh/
|
mkdir -p out/html/ ~/.ssh/
|
||||||
make docs
|
make -j`nproc` docs
|
||||||
echo 'pildefriends ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKD3Kde5vDO0TrMBDK0IGGeNGe/XinWAZkSQ/rXxwUjt' >> ~/.ssh/known_hosts
|
echo 'pildefriends ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKD3Kde5vDO0TrMBDK0IGGeNGe/XinWAZkSQ/rXxwUjt' >> ~/.ssh/known_hosts
|
||||||
rsync -avP --delete -e "ssh -i /opt/keys/ssh.ed25519" out/html/ tfdocs@pildefriends:docs/html/
|
rsync -avP --delete -e "ssh -i /opt/keys/ssh.ed25519" out/html/ tfdocs@pildefriends:docs/html/
|
||||||
- name: Setup JDK
|
- name: Setup JDK
|
||||||
@@ -59,11 +59,11 @@ jobs:
|
|||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
uses: android-actions/setup-android@v3
|
uses: android-actions/setup-android@v3
|
||||||
with:
|
with:
|
||||||
packages: 'tools platform-tools build-tools;34.0.0 platforms;android-34 ndk;26.3.11579264'
|
packages: 'tools platform-tools build-tools;35.0.0 platforms;android-35 ndk;27.2.12479018'
|
||||||
- name: Docker build
|
- name: Docker build
|
||||||
run: DOCKER_BUILDKIT=1 docker build .
|
run: DOCKER_BUILDKIT=1 docker build .
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all dist docs
|
run: ANDROID_SDK=$HOME/.android/sdk make -j`nproc` all dist
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
4
.gitmodules
vendored
@@ -19,10 +19,6 @@
|
|||||||
[submodule "deps/picohttpparser"]
|
[submodule "deps/picohttpparser"]
|
||||||
path = deps/picohttpparser
|
path = deps/picohttpparser
|
||||||
url = https://github.com/h2o/picohttpparser.git
|
url = https://github.com/h2o/picohttpparser.git
|
||||||
[submodule "deps/openssl_src"]
|
|
||||||
path = deps/openssl_src
|
|
||||||
url = https://github.com/openssl/openssl.git
|
|
||||||
shallow = true
|
|
||||||
[submodule "deps/c-ares"]
|
[submodule "deps/c-ares"]
|
||||||
path = deps/c-ares
|
path = deps/c-ares
|
||||||
url = https://github.com/c-ares/c-ares.git
|
url = https://github.com/c-ares/c-ares.git
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ src
|
|||||||
deps
|
deps
|
||||||
.clang-format
|
.clang-format
|
||||||
flake.lock
|
flake.lock
|
||||||
|
apps/trace/speedscope/**
|
||||||
|
|
||||||
# Minified files
|
# Minified files
|
||||||
**/*.min.css
|
**/*.min.css
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ RUN apt-get update && \
|
|||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
gcc \
|
gcc \
|
||||||
libc6-dev \
|
libc6-dev \
|
||||||
perl \
|
|
||||||
make
|
make
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|||||||
364
Doxyfile
@@ -1,4 +1,4 @@
|
|||||||
# Doxyfile 1.9.8
|
# Doxyfile 1.9.4
|
||||||
|
|
||||||
# This file describes the settings to be used by the documentation system
|
# This file describes the settings to be used by the documentation system
|
||||||
# doxygen (www.doxygen.org) for a project.
|
# doxygen (www.doxygen.org) for a project.
|
||||||
@@ -19,8 +19,7 @@
|
|||||||
# configuration file:
|
# configuration file:
|
||||||
# doxygen -x [configFile]
|
# doxygen -x [configFile]
|
||||||
# Use doxygen to compare the used configuration file with the template
|
# Use doxygen to compare the used configuration file with the template
|
||||||
# configuration file without replacing the environment variables or CMake type
|
# configuration file without replacing the environment variables:
|
||||||
# replacement variables:
|
|
||||||
# doxygen -x_noenv [configFile]
|
# doxygen -x_noenv [configFile]
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -86,7 +85,7 @@ CREATE_SUBDIRS = NO
|
|||||||
# level increment doubles the number of directories, resulting in 4096
|
# level increment doubles the number of directories, resulting in 4096
|
||||||
# directories at level 8 which is the default and also the maximum value. The
|
# directories at level 8 which is the default and also the maximum value. The
|
||||||
# sub-directories are organized in 2 levels, the first level always has a fixed
|
# sub-directories are organized in 2 levels, the first level always has a fixed
|
||||||
# number of 16 directories.
|
# numer of 16 directories.
|
||||||
# Minimum value: 0, maximum value: 8, default value: 8.
|
# Minimum value: 0, maximum value: 8, default value: 8.
|
||||||
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
||||||
|
|
||||||
@@ -342,7 +341,7 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
|||||||
#
|
#
|
||||||
# Note see also the list of default file extension mappings.
|
# Note see also the list of default file extension mappings.
|
||||||
|
|
||||||
EXTENSION_MAPPING =
|
EXTENSION_MAPPING = js=javascript
|
||||||
|
|
||||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||||
# according to the Markdown format, which allows for more readable
|
# according to the Markdown format, which allows for more readable
|
||||||
@@ -363,17 +362,6 @@ MARKDOWN_SUPPORT = YES
|
|||||||
|
|
||||||
TOC_INCLUDE_HEADINGS = 5
|
TOC_INCLUDE_HEADINGS = 5
|
||||||
|
|
||||||
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
|
|
||||||
# generate identifiers for the Markdown headings. Note: Every identifier is
|
|
||||||
# unique.
|
|
||||||
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
|
|
||||||
# sequence number starting at 0 and GITHUB use the lower case version of title
|
|
||||||
# with any whitespace replaced by '-' and punctuation characters removed.
|
|
||||||
# The default value is: DOXYGEN.
|
|
||||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
|
||||||
|
|
||||||
MARKDOWN_ID_STYLE = DOXYGEN
|
|
||||||
|
|
||||||
# When enabled doxygen tries to link words that correspond to documented
|
# When enabled doxygen tries to link words that correspond to documented
|
||||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||||
# be prevented in individual cases by putting a % sign in front of the word or
|
# be prevented in individual cases by putting a % sign in front of the word or
|
||||||
@@ -498,14 +486,6 @@ LOOKUP_CACHE_SIZE = 0
|
|||||||
|
|
||||||
NUM_PROC_THREADS = 1
|
NUM_PROC_THREADS = 1
|
||||||
|
|
||||||
# If the TIMESTAMP tag is set different from NO then each generated page will
|
|
||||||
# contain the date or date and time when the page was generated. Setting this to
|
|
||||||
# NO can help when comparing the output of multiple runs.
|
|
||||||
# Possible values are: YES, NO, DATETIME and DATE.
|
|
||||||
# The default value is: NO.
|
|
||||||
|
|
||||||
TIMESTAMP = NO
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Build related configuration options
|
# Build related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -587,8 +567,7 @@ HIDE_UNDOC_MEMBERS = NO
|
|||||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
|
||||||
# undocumented classes that are normally visible in the class hierarchy. If set
|
# undocumented classes that are normally visible in the class hierarchy. If set
|
||||||
# to NO, these classes will be included in the various overviews. This option
|
# to NO, these classes will be included in the various overviews. This option
|
||||||
# will also hide undocumented C++ concepts if enabled. This option has no effect
|
# has no effect if EXTRACT_ALL is enabled.
|
||||||
# if EXTRACT_ALL is enabled.
|
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
HIDE_UNDOC_CLASSES = NO
|
HIDE_UNDOC_CLASSES = NO
|
||||||
@@ -626,8 +605,7 @@ INTERNAL_DOCS = NO
|
|||||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||||
# YES.
|
# YES.
|
||||||
# Possible values are: SYSTEM, NO and YES.
|
# The default value is: system dependent.
|
||||||
# The default value is: SYSTEM.
|
|
||||||
|
|
||||||
CASE_SENSE_NAMES = YES
|
CASE_SENSE_NAMES = YES
|
||||||
|
|
||||||
@@ -879,26 +857,11 @@ WARN_IF_INCOMPLETE_DOC = YES
|
|||||||
|
|
||||||
WARN_NO_PARAMDOC = NO
|
WARN_NO_PARAMDOC = NO
|
||||||
|
|
||||||
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
|
|
||||||
# undocumented enumeration values. If set to NO, doxygen will accept
|
|
||||||
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
|
|
||||||
# will automatically be disabled.
|
|
||||||
# The default value is: NO.
|
|
||||||
|
|
||||||
WARN_IF_UNDOC_ENUM_VAL = NO
|
|
||||||
|
|
||||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||||
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
|
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||||
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
|
|
||||||
# write the warning messages in between other messages but write them at the end
|
|
||||||
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
|
|
||||||
# besides being in the defined file also be shown at the end of a run, unless
|
|
||||||
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
|
|
||||||
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
|
|
||||||
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
|
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
WARN_AS_ERROR = NO
|
WARN_AS_ERROR = NO
|
||||||
@@ -944,6 +907,10 @@ WARN_LOGFILE =
|
|||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = README.md \
|
INPUT = README.md \
|
||||||
|
core/app.js \
|
||||||
|
core/client.js \
|
||||||
|
core/core.js \
|
||||||
|
core/tfrpc.js \
|
||||||
docs/ \
|
docs/ \
|
||||||
src/
|
src/
|
||||||
|
|
||||||
@@ -952,21 +919,10 @@ INPUT = README.md \
|
|||||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||||
# documentation (see:
|
# documentation (see:
|
||||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||||
# See also: INPUT_FILE_ENCODING
|
|
||||||
# The default value is: UTF-8.
|
# The default value is: UTF-8.
|
||||||
|
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
|
||||||
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
|
|
||||||
# character encoding on a per file pattern basis. Doxygen will compare the file
|
|
||||||
# name with each pattern and apply the encoding instead of the default
|
|
||||||
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
|
|
||||||
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
|
|
||||||
# "INPUT_ENCODING" for further information on supported encodings.
|
|
||||||
|
|
||||||
INPUT_FILE_ENCODING =
|
|
||||||
|
|
||||||
# If the value of the INPUT tag contains directories, you can use the
|
# If the value of the INPUT tag contains directories, you can use the
|
||||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
|
||||||
# *.h) to filter out the source-files in the directories.
|
# *.h) to filter out the source-files in the directories.
|
||||||
@@ -978,14 +934,15 @@ INPUT_FILE_ENCODING =
|
|||||||
# Note the list of default checked file patterns might differ from the list of
|
# Note the list of default checked file patterns might differ from the list of
|
||||||
# default file extension mappings.
|
# default file extension mappings.
|
||||||
#
|
#
|
||||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
|
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||||
# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl,
|
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||||
# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php,
|
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
|
||||||
# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be
|
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
|
||||||
# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
||||||
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
# *.vhdl, *.ucf, *.qsf and *.ice.
|
||||||
|
|
||||||
FILE_PATTERNS = *.h \
|
FILE_PATTERNS = *.h \
|
||||||
|
*.js \
|
||||||
*.md
|
*.md
|
||||||
|
|
||||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||||
@@ -1024,6 +981,9 @@ EXCLUDE_PATTERNS =
|
|||||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||||
# ANamespace::AClass, ANamespace::*Test
|
# ANamespace::AClass, ANamespace::*Test
|
||||||
|
#
|
||||||
|
# Note that the wildcards are matched against the file with absolute path, so to
|
||||||
|
# exclude all test directories use the pattern */test/*
|
||||||
|
|
||||||
EXCLUDE_SYMBOLS =
|
EXCLUDE_SYMBOLS =
|
||||||
|
|
||||||
@@ -1068,11 +1028,6 @@ IMAGE_PATH = docs/images/
|
|||||||
# code is scanned, but not when the output code is generated. If lines are added
|
# code is scanned, but not when the output code is generated. If lines are added
|
||||||
# or removed, the anchors will not be placed correctly.
|
# or removed, the anchors will not be placed correctly.
|
||||||
#
|
#
|
||||||
# Note that doxygen will use the data processed and written to standard output
|
|
||||||
# for further processing, therefore nothing else, like debug statements or used
|
|
||||||
# commands (so in case of a Windows batch file always use @echo OFF), should be
|
|
||||||
# written to standard output.
|
|
||||||
#
|
|
||||||
# Note that for custom extensions or not directly supported extensions you also
|
# Note that for custom extensions or not directly supported extensions you also
|
||||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||||
# properly processed by doxygen.
|
# properly processed by doxygen.
|
||||||
@@ -1114,15 +1069,6 @@ FILTER_SOURCE_PATTERNS =
|
|||||||
|
|
||||||
USE_MDFILE_AS_MAINPAGE = README.md
|
USE_MDFILE_AS_MAINPAGE = README.md
|
||||||
|
|
||||||
# The Fortran standard specifies that for fixed formatted Fortran code all
|
|
||||||
# characters from position 72 are to be considered as comment. A common
|
|
||||||
# extension is to allow longer lines before the automatic comment starts. The
|
|
||||||
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
|
|
||||||
# be processed before the automatic comment starts.
|
|
||||||
# Minimum value: 7, maximum value: 10000, default value: 72.
|
|
||||||
|
|
||||||
FORTRAN_COMMENT_AFTER = 72
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to source browsing
|
# Configuration options related to source browsing
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -1260,11 +1206,10 @@ CLANG_DATABASE_PATH =
|
|||||||
|
|
||||||
ALPHABETICAL_INDEX = YES
|
ALPHABETICAL_INDEX = YES
|
||||||
|
|
||||||
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
|
# In case all classes in a project start with a common prefix, all classes will
|
||||||
# that should be ignored while generating the index headers. The IGNORE_PREFIX
|
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||||
# tag works for classes, function and member names. The entity will be placed in
|
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||||
# the alphabetical list under the first letter of the entity name that remains
|
# while generating the index headers.
|
||||||
# after removing the prefix.
|
|
||||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||||
|
|
||||||
IGNORE_PREFIX =
|
IGNORE_PREFIX =
|
||||||
@@ -1343,12 +1288,7 @@ HTML_STYLESHEET =
|
|||||||
# Doxygen will copy the style sheet files to the output directory.
|
# Doxygen will copy the style sheet files to the output directory.
|
||||||
# Note: The order of the extra style sheet files is of importance (e.g. the last
|
# Note: The order of the extra style sheet files is of importance (e.g. the last
|
||||||
# style sheet in the list overrules the setting of the previous ones in the
|
# style sheet in the list overrules the setting of the previous ones in the
|
||||||
# list).
|
# list). For an example see the documentation.
|
||||||
# Note: Since the styling of scrollbars can currently not be overruled in
|
|
||||||
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
|
|
||||||
# one or more extra stylesheets have been specified. So if scrollbar
|
|
||||||
# customization is desired it has to be added explicitly. For an example see the
|
|
||||||
# documentation.
|
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
HTML_EXTRA_STYLESHEET =
|
HTML_EXTRA_STYLESHEET =
|
||||||
@@ -1363,19 +1303,6 @@ HTML_EXTRA_STYLESHEET =
|
|||||||
|
|
||||||
HTML_EXTRA_FILES =
|
HTML_EXTRA_FILES =
|
||||||
|
|
||||||
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
|
|
||||||
# should be rendered with a dark or light theme.
|
|
||||||
# Possible values are: LIGHT always generate light mode output, DARK always
|
|
||||||
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
|
|
||||||
# the user preference, use light mode if no preference is set (the default),
|
|
||||||
# AUTO_DARK automatically set the mode according to the user preference, use
|
|
||||||
# dark mode if no preference is set and TOGGLE allow to user to switch between
|
|
||||||
# light and dark mode via a button.
|
|
||||||
# The default value is: AUTO_LIGHT.
|
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
|
||||||
|
|
||||||
HTML_COLORSTYLE = AUTO_LIGHT
|
|
||||||
|
|
||||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||||
# will adjust the colors in the style sheet and background images according to
|
# will adjust the colors in the style sheet and background images according to
|
||||||
# this color. Hue is specified as an angle on a color-wheel, see
|
# this color. Hue is specified as an angle on a color-wheel, see
|
||||||
@@ -1406,6 +1333,15 @@ HTML_COLORSTYLE_SAT = 100
|
|||||||
|
|
||||||
HTML_COLORSTYLE_GAMMA = 80
|
HTML_COLORSTYLE_GAMMA = 80
|
||||||
|
|
||||||
|
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
|
||||||
|
# page will contain the date and time when the page was generated. Setting this
|
||||||
|
# to YES can help to show when doxygen was last run and thus if the
|
||||||
|
# documentation is up to date.
|
||||||
|
# The default value is: NO.
|
||||||
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
|
#HTML_TIMESTAMP = NO
|
||||||
|
|
||||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||||
# documentation will contain a main index with vertical navigation menus that
|
# documentation will contain a main index with vertical navigation menus that
|
||||||
# are dynamically created via JavaScript. If disabled, the navigation index will
|
# are dynamically created via JavaScript. If disabled, the navigation index will
|
||||||
@@ -1425,13 +1361,6 @@ HTML_DYNAMIC_MENUS = YES
|
|||||||
|
|
||||||
HTML_DYNAMIC_SECTIONS = NO
|
HTML_DYNAMIC_SECTIONS = NO
|
||||||
|
|
||||||
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
|
|
||||||
# dynamically folded and expanded in the generated HTML source code.
|
|
||||||
# The default value is: YES.
|
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
|
||||||
|
|
||||||
HTML_CODE_FOLDING = YES
|
|
||||||
|
|
||||||
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
|
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
|
||||||
# shown in the various tree structured indices initially; the user can expand
|
# shown in the various tree structured indices initially; the user can expand
|
||||||
# and collapse entries dynamically later on. Doxygen will expand the tree to
|
# and collapse entries dynamically later on. Doxygen will expand the tree to
|
||||||
@@ -1562,16 +1491,6 @@ BINARY_TOC = NO
|
|||||||
|
|
||||||
TOC_EXPAND = NO
|
TOC_EXPAND = NO
|
||||||
|
|
||||||
# The SITEMAP_URL tag is used to specify the full URL of the place where the
|
|
||||||
# generated documentation will be placed on the server by the user during the
|
|
||||||
# deployment of the documentation. The generated sitemap is called sitemap.xml
|
|
||||||
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
|
|
||||||
# is specified no sitemap is generated. For information about the sitemap
|
|
||||||
# protocol see https://www.sitemaps.org
|
|
||||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
|
||||||
|
|
||||||
SITEMAP_URL =
|
|
||||||
|
|
||||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
||||||
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
|
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
|
||||||
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
|
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
|
||||||
@@ -1747,6 +1666,17 @@ HTML_FORMULA_FORMAT = png
|
|||||||
|
|
||||||
FORMULA_FONTSIZE = 10
|
FORMULA_FONTSIZE = 10
|
||||||
|
|
||||||
|
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
|
||||||
|
# generated for formulas are transparent PNGs. Transparent PNGs are not
|
||||||
|
# supported properly for IE 6.0, but are supported on all modern browsers.
|
||||||
|
#
|
||||||
|
# Note that when changing this option you need to delete any form_*.png files in
|
||||||
|
# the HTML output directory before the changes have effect.
|
||||||
|
# The default value is: YES.
|
||||||
|
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||||
|
|
||||||
|
#FORMULA_TRANSPARENT = YES
|
||||||
|
|
||||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
||||||
# to create new LaTeX commands to be used in formulas as building blocks. See
|
# to create new LaTeX commands to be used in formulas as building blocks. See
|
||||||
# the section "Including formulas" for details.
|
# the section "Including formulas" for details.
|
||||||
@@ -1808,8 +1738,8 @@ MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
|
|||||||
|
|
||||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||||
# extension names that should be enabled during MathJax rendering. For example
|
# extension names that should be enabled during MathJax rendering. For example
|
||||||
# for MathJax version 2 (see
|
# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html
|
||||||
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
|
# #tex-and-latex-extensions):
|
||||||
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
||||||
# For example for MathJax version 3 (see
|
# For example for MathJax version 3 (see
|
||||||
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
||||||
@@ -2060,16 +1990,9 @@ PDF_HYPERLINKS = YES
|
|||||||
|
|
||||||
USE_PDFLATEX = YES
|
USE_PDFLATEX = YES
|
||||||
|
|
||||||
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
|
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
||||||
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
|
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
||||||
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
|
# if errors occur, instead of asking the user for help.
|
||||||
# hit at every error; missing files that TeX tries to input or request from
|
|
||||||
# keyboard input (\read on a not open input stream) cause the job to abort,
|
|
||||||
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
|
|
||||||
# but there is no possibility of user interaction just like in batch mode,
|
|
||||||
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
|
|
||||||
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
|
|
||||||
# each error, asking for user intervention.
|
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
@@ -2090,6 +2013,14 @@ LATEX_HIDE_INDICES = NO
|
|||||||
|
|
||||||
LATEX_BIB_STYLE = plain
|
LATEX_BIB_STYLE = plain
|
||||||
|
|
||||||
|
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
|
||||||
|
# page will contain the date and time when the page was generated. Setting this
|
||||||
|
# to NO can help when comparing the output of multiple runs.
|
||||||
|
# The default value is: NO.
|
||||||
|
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||||
|
|
||||||
|
#LATEX_TIMESTAMP = NO
|
||||||
|
|
||||||
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
||||||
# path from which the emoji images will be read. If a relative path is entered,
|
# path from which the emoji images will be read. If a relative path is entered,
|
||||||
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
||||||
@@ -2255,39 +2186,13 @@ DOCBOOK_OUTPUT = docbook
|
|||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
||||||
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
|
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
|
||||||
# the structure of the code including all documentation. Note that this feature
|
# the structure of the code including all documentation. Note that this feature
|
||||||
# is still experimental and incomplete at the moment.
|
# is still experimental and incomplete at the moment.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
GENERATE_AUTOGEN_DEF = NO
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
# Configuration options related to Sqlite3 output
|
|
||||||
#---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
|
|
||||||
# database with symbols found by doxygen stored in tables.
|
|
||||||
# The default value is: NO.
|
|
||||||
|
|
||||||
#GENERATE_SQLITE3 = NO
|
|
||||||
|
|
||||||
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
|
|
||||||
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
|
|
||||||
# in front of it.
|
|
||||||
# The default directory is: sqlite3.
|
|
||||||
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
|
|
||||||
|
|
||||||
#SQLITE3_OUTPUT = sqlite3
|
|
||||||
|
|
||||||
# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db
|
|
||||||
# database file will be recreated with each doxygen run. If set to NO, doxygen
|
|
||||||
# will warn if an a database file is already found and not modify it.
|
|
||||||
# The default value is: YES.
|
|
||||||
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
|
|
||||||
|
|
||||||
#SQLITE3_RECREATE_DB = YES
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the Perl module output
|
# Configuration options related to the Perl module output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@@ -2430,15 +2335,15 @@ TAGFILES =
|
|||||||
|
|
||||||
GENERATE_TAGFILE =
|
GENERATE_TAGFILE =
|
||||||
|
|
||||||
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
|
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
|
||||||
# will be listed in the class and namespace index. If set to NO, only the
|
# the class index. If set to NO, only the inherited external classes will be
|
||||||
# inherited external classes will be listed.
|
# listed.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
ALLEXTERNALS = NO
|
ALLEXTERNALS = NO
|
||||||
|
|
||||||
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
|
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
|
||||||
# in the topic index. If set to NO, only the current project's groups will be
|
# in the modules index. If set to NO, only the current project's groups will be
|
||||||
# listed.
|
# listed.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
@@ -2452,9 +2357,16 @@ EXTERNAL_GROUPS = YES
|
|||||||
EXTERNAL_PAGES = YES
|
EXTERNAL_PAGES = YES
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to diagram generator tools
|
# Configuration options related to the dot tool
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||||
|
# then run dia to produce the diagram and insert it in the documentation. The
|
||||||
|
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||||
|
# If left empty dia is assumed to be found in the default search path.
|
||||||
|
|
||||||
|
DIA_PATH =
|
||||||
|
|
||||||
# If set to YES the inheritance and collaboration graphs will hide inheritance
|
# If set to YES the inheritance and collaboration graphs will hide inheritance
|
||||||
# and usage relations if the target is undocumented or is not a class.
|
# and usage relations if the target is undocumented or is not a class.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
@@ -2463,10 +2375,10 @@ HIDE_UNDOC_RELATIONS = YES
|
|||||||
|
|
||||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||||
# available from the path. This tool is part of Graphviz (see:
|
# available from the path. This tool is part of Graphviz (see:
|
||||||
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||||
# Bell Labs. The other options in this section have no effect if this option is
|
# Bell Labs. The other options in this section have no effect if this option is
|
||||||
# set to NO
|
# set to NO
|
||||||
# The default value is: YES.
|
# The default value is: NO.
|
||||||
|
|
||||||
HAVE_DOT = YES
|
HAVE_DOT = YES
|
||||||
|
|
||||||
@@ -2480,51 +2392,37 @@ HAVE_DOT = YES
|
|||||||
|
|
||||||
DOT_NUM_THREADS = 0
|
DOT_NUM_THREADS = 0
|
||||||
|
|
||||||
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
|
# When you want a differently looking font in the dot files that doxygen
|
||||||
# subgraphs. When you want a differently looking font in the dot files that
|
# generates you can specify the font name using DOT_FONTNAME. You need to make
|
||||||
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
|
# sure dot is able to find the font, which can be done by putting it in a
|
||||||
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
|
# standard location or by setting the DOTFONTPATH environment variable or by
|
||||||
# Edge and Graph Attributes specification</a> You need to make sure dot is able
|
# setting DOT_FONTPATH to the directory containing the font.
|
||||||
# to find the font, which can be done by putting it in a standard location or by
|
# The default value is: Helvetica.
|
||||||
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
|
|
||||||
# directory containing the font. Default graphviz fontsize is 14.
|
|
||||||
# The default value is: fontname=Helvetica,fontsize=10.
|
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
|
#DOT_FONTNAME = Helvetica
|
||||||
|
|
||||||
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
|
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
|
||||||
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
|
# dot graphs.
|
||||||
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
|
# Minimum value: 4, maximum value: 24, default value: 10.
|
||||||
# arrows shapes.</a>
|
|
||||||
# The default value is: labelfontname=Helvetica,labelfontsize=10.
|
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
|
#DOT_FONTSIZE = 10
|
||||||
|
|
||||||
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
|
# By default doxygen will tell dot to use the default font as specified with
|
||||||
# around nodes set 'shape=plain' or 'shape=plaintext' <a
|
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
|
||||||
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
|
# the path where dot can find it using this tag.
|
||||||
# The default value is: shape=box,height=0.2,width=0.4.
|
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
|
#DOT_FONTPATH =
|
||||||
|
|
||||||
# You can set the path where dot can find font specified with fontname in
|
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
||||||
# DOT_COMMON_ATTR and others dot attributes.
|
# graph for each documented class showing the direct and indirect inheritance
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
||||||
|
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
||||||
DOT_FONTPATH =
|
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
||||||
|
# links.
|
||||||
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
|
# Possible values are: NO, YES, TEXT and GRAPH.
|
||||||
# generate a graph for each documented class showing the direct and indirect
|
|
||||||
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
|
|
||||||
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
|
|
||||||
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
|
|
||||||
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
|
|
||||||
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
|
|
||||||
# relations will be shown as texts / links.
|
|
||||||
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
|
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
CLASS_GRAPH = YES
|
CLASS_GRAPH = YES
|
||||||
@@ -2532,21 +2430,15 @@ CLASS_GRAPH = YES
|
|||||||
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
|
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
|
||||||
# graph for each documented class showing the direct and indirect implementation
|
# graph for each documented class showing the direct and indirect implementation
|
||||||
# dependencies (inheritance, containment, and class references variables) of the
|
# dependencies (inheritance, containment, and class references variables) of the
|
||||||
# class with other documented classes. Explicit enabling a collaboration graph,
|
# class with other documented classes.
|
||||||
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
|
|
||||||
# command \collaborationgraph. Disabling a collaboration graph can be
|
|
||||||
# accomplished by means of the command \hidecollaborationgraph.
|
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
COLLABORATION_GRAPH = YES
|
COLLABORATION_GRAPH = YES
|
||||||
|
|
||||||
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
||||||
# groups, showing the direct groups dependencies. Explicit enabling a group
|
# groups, showing the direct groups dependencies. See also the chapter Grouping
|
||||||
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
|
# in the manual.
|
||||||
# of the command \groupgraph. Disabling a directory graph can be accomplished by
|
|
||||||
# means of the command \hidegroupgraph. See also the chapter Grouping in the
|
|
||||||
# manual.
|
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2606,9 +2498,7 @@ TEMPLATE_RELATIONS = NO
|
|||||||
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
|
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
|
||||||
# YES then doxygen will generate a graph for each documented file showing the
|
# YES then doxygen will generate a graph for each documented file showing the
|
||||||
# direct and indirect include dependencies of the file with other documented
|
# direct and indirect include dependencies of the file with other documented
|
||||||
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
|
# files.
|
||||||
# can be accomplished by means of the command \includegraph. Disabling an
|
|
||||||
# include graph can be accomplished by means of the command \hideincludegraph.
|
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2617,10 +2507,7 @@ INCLUDE_GRAPH = YES
|
|||||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
|
||||||
# set to YES then doxygen will generate a graph for each documented file showing
|
# set to YES then doxygen will generate a graph for each documented file showing
|
||||||
# the direct and indirect include dependencies of the file with other documented
|
# the direct and indirect include dependencies of the file with other documented
|
||||||
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
|
# files.
|
||||||
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
|
|
||||||
# an included by graph can be accomplished by means of the command
|
|
||||||
# \hideincludedbygraph.
|
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2660,10 +2547,7 @@ GRAPHICAL_HIERARCHY = YES
|
|||||||
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
|
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
|
||||||
# dependencies a directory has on other directories in a graphical way. The
|
# dependencies a directory has on other directories in a graphical way. The
|
||||||
# dependency relations are determined by the #include relations between the
|
# dependency relations are determined by the #include relations between the
|
||||||
# files in the directories. Explicit enabling a directory graph, when
|
# files in the directories.
|
||||||
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
|
|
||||||
# \directorygraph. Disabling a directory graph can be accomplished by means of
|
|
||||||
# the command \hidedirectorygraph.
|
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
@@ -2679,13 +2563,12 @@ DIR_GRAPH_MAX_DEPTH = 1
|
|||||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||||
# generated by dot. For an explanation of the image formats see the section
|
# generated by dot. For an explanation of the image formats see the section
|
||||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||||
# https://www.graphviz.org/)).
|
# http://www.graphviz.org/)).
|
||||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||||
# requirement).
|
# requirement).
|
||||||
# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,
|
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
|
||||||
# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,
|
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||||
# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
|
||||||
# png:gdiplus:gdiplus.
|
# png:gdiplus:gdiplus.
|
||||||
# The default value is: png.
|
# The default value is: png.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
@@ -2717,12 +2600,11 @@ DOT_PATH =
|
|||||||
|
|
||||||
DOTFILE_DIRS =
|
DOTFILE_DIRS =
|
||||||
|
|
||||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
||||||
# then run dia to produce the diagram and insert it in the documentation. The
|
# contain msc files that are included in the documentation (see the \mscfile
|
||||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
# command).
|
||||||
# If left empty dia is assumed to be found in the default search path.
|
|
||||||
|
|
||||||
DIA_PATH =
|
MSCFILE_DIRS =
|
||||||
|
|
||||||
# The DIAFILE_DIRS tag can be used to specify one or more directories that
|
# The DIAFILE_DIRS tag can be used to specify one or more directories that
|
||||||
# contain dia files that are included in the documentation (see the \diafile
|
# contain dia files that are included in the documentation (see the \diafile
|
||||||
@@ -2772,6 +2654,18 @@ DOT_GRAPH_MAX_NODES = 50
|
|||||||
|
|
||||||
MAX_DOT_GRAPH_DEPTH = 0
|
MAX_DOT_GRAPH_DEPTH = 0
|
||||||
|
|
||||||
|
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
|
||||||
|
# background. This is disabled by default, because dot on Windows does not seem
|
||||||
|
# to support this out of the box.
|
||||||
|
#
|
||||||
|
# Warning: Depending on the platform used, enabling this option may lead to
|
||||||
|
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
|
||||||
|
# read).
|
||||||
|
# The default value is: NO.
|
||||||
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
|
#DOT_TRANSPARENT = NO
|
||||||
|
|
||||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||||
@@ -2799,19 +2693,3 @@ GENERATE_LEGEND = YES
|
|||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
DOT_CLEANUP = YES
|
DOT_CLEANUP = YES
|
||||||
|
|
||||||
# You can define message sequence charts within doxygen comments using the \msc
|
|
||||||
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
|
|
||||||
# use a built-in version of mscgen tool to produce the charts. Alternatively,
|
|
||||||
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
|
|
||||||
# specifying prog as the value, doxygen will call the tool as prog -T
|
|
||||||
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
|
|
||||||
# output file formats "png", "eps", "svg", and "ismap".
|
|
||||||
|
|
||||||
MSCGEN_TOOL =
|
|
||||||
|
|
||||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
|
||||||
# contain msc files that are included in the documentation (see the \mscfile
|
|
||||||
# command).
|
|
||||||
|
|
||||||
MSCFILE_DIRS =
|
|
||||||
|
|||||||
182
GNUmakefile
@@ -16,15 +16,15 @@ MAKEFLAGS += --no-builtin-rules
|
|||||||
## LD := Linker.
|
## LD := Linker.
|
||||||
## ANDROID_SDK := Path to the Android SDK.
|
## ANDROID_SDK := Path to the Android SDK.
|
||||||
|
|
||||||
VERSION_CODE := 38
|
VERSION_CODE := 49
|
||||||
VERSION_CODE_IOS := 14
|
VERSION_CODE_IOS := 27
|
||||||
VERSION_NUMBER := 0.0.32
|
VERSION_NUMBER := 0.2025.12-wip
|
||||||
VERSION_NAME := This program kills fascists.
|
VERSION_NAME := This program kills fascists.
|
||||||
|
|
||||||
IPHONEOS_VERSION_MIN=14.0
|
IPHONEOS_VERSION_MIN=14.5
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3500100.zip
|
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3510000.zip
|
||||||
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.18.2/bundletool-all-1.18.2.jar
|
||||||
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||||
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
||||||
|
|
||||||
@@ -38,7 +38,6 @@ BUNDLETOOL = out/bundletool.jar
|
|||||||
|
|
||||||
HAVE_WIN :=
|
HAVE_WIN :=
|
||||||
HAVE_CROSS_AARCH64 :=
|
HAVE_CROSS_AARCH64 :=
|
||||||
USE_SYSTEM_SSL :=
|
|
||||||
|
|
||||||
export SOURCE_DATE_EPOCH=1
|
export SOURCE_DATE_EPOCH=1
|
||||||
export TZ=UTC
|
export TZ=UTC
|
||||||
@@ -65,7 +64,6 @@ LDFLAGS += \
|
|||||||
-lbsd \
|
-lbsd \
|
||||||
-lnetwork \
|
-lnetwork \
|
||||||
-Wno-stringop-overflow
|
-Wno-stringop-overflow
|
||||||
USE_SYSTEM_SSL := 1
|
|
||||||
HAVE_ANDROID = 0
|
HAVE_ANDROID = 0
|
||||||
HAVE_LINUX_IOS = 0
|
HAVE_LINUX_IOS = 0
|
||||||
HAVE_LINUX_MACOS = 0
|
HAVE_LINUX_MACOS = 0
|
||||||
@@ -80,13 +78,12 @@ LDFLAGS += \
|
|||||||
HAVE_ANDROID :=
|
HAVE_ANDROID :=
|
||||||
HAVE_LINUX_IOS :=
|
HAVE_LINUX_IOS :=
|
||||||
HAVE_LINUX_MACOS :=
|
HAVE_LINUX_MACOS :=
|
||||||
USE_SYSTEM_SSL := 1
|
|
||||||
else
|
else
|
||||||
$(error Unexpected host platform $(UNAME_S).)
|
$(error Unexpected host platform $(UNAME_S).)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Everything is set above.
|
# Everything is set above.
|
||||||
$(info Building Tilde Friends $(VERSION_NUMBER) android=$(if $(HAVE_ANDROID),1,0) win=$(if $(HAVE_WIN),1,0) cross_aarch64=$(if $(HAVE_CROSS_AARCH64),1,0) cross_ios=$(if $(HAVE_LINUX_IOS),1,0) cross_macos=$(if $(HAVE_LINUX_MACOS),1,0) system_ssl=$(if $(USE_SYSTEM_SSL),1,0))
|
$(info Building Tilde Friends $(VERSION_NUMBER) android=$(if $(HAVE_ANDROID),1,0) win=$(if $(HAVE_WIN),1,0) cross_aarch64=$(if $(HAVE_CROSS_AARCH64),1,0) cross_ios=$(if $(HAVE_LINUX_IOS),1,0) cross_macos=$(if $(HAVE_LINUX_MACOS),1,0))
|
||||||
|
|
||||||
CFLAGS += \
|
CFLAGS += \
|
||||||
-std=gnu11 \
|
-std=gnu11 \
|
||||||
@@ -106,10 +103,10 @@ LDFLAGS += \
|
|||||||
-Wno-aggressive-loop-optimizations
|
-Wno-aggressive-loop-optimizations
|
||||||
|
|
||||||
ANDROID_MIN_SDK_VERSION := 24
|
ANDROID_MIN_SDK_VERSION := 24
|
||||||
ANDROID_TARGET_SDK_VERSION := 34
|
ANDROID_TARGET_SDK_VERSION := 35
|
||||||
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/34.0.0
|
ANDROID_BUILD_TOOLS := $(ANDROID_SDK)/build-tools/35.0.0
|
||||||
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
|
ANDROID_PLATFORM := $(ANDROID_SDK)/platforms/android-$(ANDROID_TARGET_SDK_VERSION)
|
||||||
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/26.3.11579264
|
ANDROID_NDK ?= $(ANDROID_SDK)/ndk/27.2.12479018
|
||||||
|
|
||||||
ANDROID_ARMV7A_TARGETS := \
|
ANDROID_ARMV7A_TARGETS := \
|
||||||
out/androiddebug-armv7a/tildefriends \
|
out/androiddebug-armv7a/tildefriends \
|
||||||
@@ -253,7 +250,10 @@ $(ANDROID_TARGETS): CFLAGS += \
|
|||||||
-fno-asynchronous-unwind-tables \
|
-fno-asynchronous-unwind-tables \
|
||||||
-funwind-tables \
|
-funwind-tables \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
$(ANDROID_TARGETS): LDFLAGS += \
|
||||||
|
--sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
|
||||||
|
-Wl,-z,max-page-size=16384 \
|
||||||
|
-fPIC
|
||||||
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
||||||
$(DEBUG_TARGETS): LDFLAGS += -Og
|
$(DEBUG_TARGETS): LDFLAGS += -Og
|
||||||
$(RELEASE_TARGETS): CFLAGS += \
|
$(RELEASE_TARGETS): CFLAGS += \
|
||||||
@@ -267,16 +267,12 @@ $(WINDOWS_TARGETS): AS = $(CC)
|
|||||||
$(WINDOWS_TARGETS): CFLAGS += \
|
$(WINDOWS_TARGETS): CFLAGS += \
|
||||||
-D_WIN32_WINNT=0x0A00 \
|
-D_WIN32_WINNT=0x0A00 \
|
||||||
-DWINVER=0x0A00 \
|
-DWINVER=0x0A00 \
|
||||||
-DNTDDI_VERSION=NTDDI_WIN10 \
|
-DNTDDI_VERSION=NTDDI_WIN10
|
||||||
-Iout/openssl/$(UNAME_S)/mingw64/usr/local/include
|
|
||||||
$(WINDOWS_TARGETS): LDFLAGS += \
|
$(WINDOWS_TARGETS): LDFLAGS += \
|
||||||
-static \
|
-static \
|
||||||
-lm \
|
-lm
|
||||||
-Lout/openssl/$(UNAME_S)/mingw64/usr/local/lib
|
|
||||||
$(AARCH64_TARGETS): CC = aarch64-linux-gnu-gcc
|
$(AARCH64_TARGETS): CC = aarch64-linux-gnu-gcc
|
||||||
$(AARCH64_TARGETS): AS = $(CC)
|
$(AARCH64_TARGETS): AS = $(CC)
|
||||||
$(AARCH64_TARGETS): CFLAGS += -Iout/openssl/Linux/aarch64/usr/local/include
|
|
||||||
$(AARCH64_TARGETS): LDFLAGS += -Lout/openssl/Linux/aarch64/usr/local/lib
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
ifeq ($(UNAME_S),Darwin)
|
||||||
$(HOST_TARGETS): CC = xcrun clang
|
$(HOST_TARGETS): CC = xcrun clang
|
||||||
$(IOS_TARGETS): IOS_SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path)
|
$(IOS_TARGETS): IOS_SYSROOT := $(shell xcrun --sdk iphoneos --show-sdk-path)
|
||||||
@@ -301,39 +297,12 @@ $(ANDROID_TARGETS): AS = $(CC)
|
|||||||
$(ANDROID_TARGETS): CFLAGS += \
|
$(ANDROID_TARGETS): CFLAGS += \
|
||||||
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
$(ANDROID_ARMV7A_TARGETS): CFLAGS += -Iout/openssl/android/armeabi-v7a/usr/local/include
|
|
||||||
$(ANDROID_ARMV7A_TARGETS): LDFLAGS += -Lout/openssl/android/armeabi-v7a/usr/local/lib
|
|
||||||
$(ANDROID_ARM64_TARGETS): CFLAGS += -Iout/openssl/android/arm64-v8a/usr/local/include
|
|
||||||
$(ANDROID_ARM64_TARGETS): LDFLAGS += -Lout/openssl/android/arm64-v8a/usr/local/lib
|
|
||||||
$(ANDROID_X86_TARGETS): CFLAGS += -Iout/openssl/android/x86/usr/local/include
|
|
||||||
$(ANDROID_X86_TARGETS): CFLAGS += -Wno-atomic-alignment
|
$(ANDROID_X86_TARGETS): CFLAGS += -Wno-atomic-alignment
|
||||||
$(ANDROID_X86_TARGETS): LDFLAGS += -Lout/openssl/android/x86/usr/local/lib
|
|
||||||
$(ANDROID_X86_64_TARGETS): CFLAGS += -Iout/openssl/android/x86_64/usr/local/include
|
|
||||||
$(ANDROID_X86_64_TARGETS): LDFLAGS += -Lout/openssl/android/x86_64/usr/local/lib
|
|
||||||
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
|
$(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type
|
||||||
$(MACOS_TARGETS): LDFLAGS += -Wl,-dead_strip
|
$(MACOS_TARGETS): LDFLAGS += -Wl,-dead_strip
|
||||||
$(NONMACOS_TARGETS): LDFLAGS += -Wl,--gc-sections -Wl,--as-needed
|
$(NONMACOS_TARGETS): LDFLAGS += -Wl,--gc-sections -Wl,--as-needed
|
||||||
$(IOS_TARGETS): CFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
$(IOS_TARGETS): CFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
||||||
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
$(IOS_TARGETS): LDFLAGS += -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
$(IOS_TARGETS): CFLAGS += -Iout/openssl/ios/ios64-xcrun/usr/local/include
|
|
||||||
$(IOS_TARGETS): LDFLAGS += -Lout/openssl/ios/ios64-xcrun/usr/local/lib
|
|
||||||
else
|
|
||||||
$(IOS_TARGETS): CFLAGS += -Iout/openssl/$(UNAME_S)/ios64-cross/usr/local/include
|
|
||||||
$(IOS_TARGETS): LDFLAGS += -Lout/openssl/$(UNAME_S)/ios64-cross/usr/local/lib
|
|
||||||
$(filter $(BUILD_DIR)/macosdebug-x86_64/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-x86_64/usr/local/include
|
|
||||||
$(filter $(BUILD_DIR)/macosdebug-arm/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-arm/usr/local/include
|
|
||||||
$(filter $(BUILD_DIR)/macosdebug-x86_64/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-x86_64/usr/local/lib
|
|
||||||
$(filter $(BUILD_DIR)/macosdebug-arm/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-arm/usr/local/lib
|
|
||||||
$(filter $(BUILD_DIR)/macosrelease-x86_64/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-x86_64/usr/local/include
|
|
||||||
$(filter $(BUILD_DIR)/macosrelease-arm/%,$(ALL_TARGETS)): CFLAGS += -Iout/openssl/$(UNAME_S)/macos-arm/usr/local/include
|
|
||||||
$(filter $(BUILD_DIR)/macosrelease-x86_64/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-x86_64/usr/local/lib
|
|
||||||
$(filter $(BUILD_DIR)/macosrelease-arm/%,$(ALL_TARGETS)): LDFLAGS += -Lout/openssl/$(UNAME_S)/macos-arm/usr/local/lib
|
|
||||||
endif
|
|
||||||
$(IOSSIM_TARGETS): CFLAGS += -Iout/openssl/ios/iossimulator-xcrun/usr/local/include
|
|
||||||
$(IOSSIM_TARGETS): LDFLAGS += -Lout/openssl/ios/iossimulator-xcrun/usr/local/lib
|
|
||||||
$(HOST_TARGETS): CFLAGS += -Iout/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/include
|
|
||||||
$(HOST_TARGETS): LDFLAGS += -Lout/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib
|
|
||||||
|
|
||||||
ifeq ($(UNAME_M),x86_64)
|
ifeq ($(UNAME_M),x86_64)
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
@@ -650,6 +619,7 @@ SODIUM_SOURCES := \
|
|||||||
deps/libsodium/src/libsodium/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c \
|
deps/libsodium/src/libsodium/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c \
|
||||||
deps/libsodium/src/libsodium/crypto_core/salsa/ref/core_salsa_ref.c \
|
deps/libsodium/src/libsodium/crypto_core/salsa/ref/core_salsa_ref.c \
|
||||||
deps/libsodium/src/libsodium/crypto_core/softaes/softaes.c \
|
deps/libsodium/src/libsodium/crypto_core/softaes/softaes.c \
|
||||||
|
deps/libsodium/src/libsodium/crypto_generichash/crypto_generichash.c \
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c \
|
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c \
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c \
|
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c \
|
||||||
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c \
|
deps/libsodium/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c \
|
||||||
@@ -820,9 +790,6 @@ $(MINIUNZIP_OBJS): CFLAGS += \
|
|||||||
LDFLAGS += \
|
LDFLAGS += \
|
||||||
-pthread \
|
-pthread \
|
||||||
-lm
|
-lm
|
||||||
$(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS) $(AARCH64_TARGETS) $(filter-out $(HOST_TARGETS),$(MACOS_TARGETS)): LDFLAGS += \
|
|
||||||
-lssl \
|
|
||||||
-lcrypto
|
|
||||||
ifneq ($(UNAME_S),Haiku)
|
ifneq ($(UNAME_S),Haiku)
|
||||||
ifneq ($(UNAME_S),OpenBSD)
|
ifneq ($(UNAME_S),OpenBSD)
|
||||||
$(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
$(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
||||||
@@ -830,8 +797,6 @@ $(HOST_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
$(WINDOWS_TARGETS): LDFLAGS += \
|
$(WINDOWS_TARGETS): LDFLAGS += \
|
||||||
-lssl \
|
|
||||||
-lcrypto \
|
|
||||||
-lcrypt32 \
|
-lcrypt32 \
|
||||||
-ldbghelp \
|
-ldbghelp \
|
||||||
-liphlpapi \
|
-liphlpapi \
|
||||||
@@ -844,15 +809,15 @@ $(WINDOWS_TARGETS): LDFLAGS += \
|
|||||||
$(ANDROID_TARGETS): LDFLAGS += \
|
$(ANDROID_TARGETS): LDFLAGS += \
|
||||||
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
-target $(ANDROID_NDK_TARGET_TRIPLE)$(ANDROID_MIN_SDK_VERSION) \
|
||||||
-ldl \
|
-ldl \
|
||||||
-llog \
|
-llog
|
||||||
-lssl \
|
|
||||||
-lcrypto
|
|
||||||
$(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): CFLAGS += \
|
$(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): CFLAGS += \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
$(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
$(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
||||||
-framework Foundation \
|
-framework Foundation \
|
||||||
-framework CoreFoundation \
|
-framework CoreFoundation \
|
||||||
|
-framework CoreSpotlight \
|
||||||
-framework UIKit \
|
-framework UIKit \
|
||||||
|
-framework UniformTypeIdentifiers \
|
||||||
-framework WebKit
|
-framework WebKit
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -994,8 +959,7 @@ PACKAGE_DIRS := \
|
|||||||
core \
|
core \
|
||||||
deps/codemirror \
|
deps/codemirror \
|
||||||
deps/prettier \
|
deps/prettier \
|
||||||
deps/lit \
|
deps/lit
|
||||||
deps/speedscope
|
|
||||||
|
|
||||||
RAW_FILES := $(sort $(filter-out apps/blog% apps/issues% apps/welcome% apps/journal% %.map, $(shell find $(PACKAGE_DIRS) -type f -not -name '.*')))
|
RAW_FILES := $(sort $(filter-out apps/blog% apps/issues% apps/welcome% apps/journal% %.map, $(shell find $(PACKAGE_DIRS) -type f -not -name '.*')))
|
||||||
|
|
||||||
@@ -1054,7 +1018,7 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
|
|||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86_64/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86_64/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym
|
||||||
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym
|
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-x86/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym
|
||||||
@cd out/aab/staging; zip -u ../../../$@ BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym; cd ../../../
|
@cd out/aab/staging; zip -u ../../../$@ BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64/libtildefriends.so.sym BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86/libtildefriends.so.sym; cd ../../../
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign -ks .keys/android.jks --ks-key-alias androidKey -ks-pass pass:android --min-sdk-version=$(ANDROID_MIN_SDK_VERSION) $@
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign -ks .keys/android.jks --ks-key-alias androidKey -ks-pass pass:android --min-sdk-version=$(ANDROID_MIN_SDK_VERSION) --alignment-preserved $@
|
||||||
|
|
||||||
aab: out/TildeFriends.aab ## Build an Android App Bundle.
|
aab: out/TildeFriends.aab ## Build an Android App Bundle.
|
||||||
.PHONY: aab
|
.PHONY: aab
|
||||||
@@ -1116,12 +1080,12 @@ out/apk/TildeFriends-%.fdroid.unsigned.apk:
|
|||||||
|
|
||||||
out/%.apk: out/apk/%.unsigned.apk
|
out/%.apk: out/apk/%.unsigned.apk
|
||||||
@echo "[apksigner] $(notdir $@)"
|
@echo "[apksigner] $(notdir $@)"
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $<
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ --alignment-preserved $<
|
||||||
|
|
||||||
out/%.zopfli.apk: out/%.apk
|
out/%.zopfli.apk: out/%.apk
|
||||||
@echo "[zopfli] $(notdir $@)"
|
@echo "[zopfli] $(notdir $@)"
|
||||||
$(ANDROID_BUILD_TOOLS)/zipalign -f -z 4 $< $@.zopfli
|
$(ANDROID_BUILD_TOOLS)/zipalign -f -z 4 $< $@.zopfli
|
||||||
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ $@.zopfli
|
@$(ANDROID_BUILD_TOOLS)/apksigner sign --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android --key-pass pass:android --min-sdk-version $(ANDROID_MIN_SDK_VERSION) --out $@ --alignment-preserved $@.zopfli
|
||||||
|
|
||||||
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk ## Build an Android release APK.
|
release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk ## Build an Android release APK.
|
||||||
.PHONY: release-apk
|
.PHONY: release-apk
|
||||||
@@ -1139,6 +1103,11 @@ releaseapkgo: out/TildeFriends-arm-release.apk ## Build, install, and run a rele
|
|||||||
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
.PHONY: releaseapkgo
|
.PHONY: releaseapkgo
|
||||||
|
|
||||||
|
x86releaseapkgo: out/TildeFriends-x86-release.apk ## Build, install, and run an x86 release Android APK.
|
||||||
|
@adb install -r $<
|
||||||
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
|
.PHONY: x86releaseapkgo
|
||||||
|
|
||||||
apklog: ## Display Android log output.
|
apklog: ## Display Android log output.
|
||||||
@adb logcat *:S tildefriends
|
@adb logcat *:S tildefriends
|
||||||
.PHONY: apklog
|
.PHONY: apklog
|
||||||
@@ -1184,6 +1153,7 @@ out/tildefriends-%.ipa: out/tildefriends-ios%.app/tildefriends
|
|||||||
@echo "[ipa] $@"
|
@echo "[ipa] $@"
|
||||||
@rm -rf $@.tmp $@
|
@rm -rf $@.tmp $@
|
||||||
@mkdir -p $@.tmp/Payload/tildefriends.app/
|
@mkdir -p $@.tmp/Payload/tildefriends.app/
|
||||||
|
@cp src/ios/tildefriends512.png $@.tmp/iTunesArtwork
|
||||||
@cp -R $(dir $<)/* $@.tmp/Payload/tildefriends.app/
|
@cp -R $(dir $<)/* $@.tmp/Payload/tildefriends.app/
|
||||||
@cd $@.tmp/ && zip -u ../../$@ -q -9 -r ./
|
@cd $@.tmp/ && zip -u ../../$@ -q -9 -r ./
|
||||||
@rm -rf $@.tmp/
|
@rm -rf $@.tmp/
|
||||||
@@ -1211,98 +1181,11 @@ ios%go: out/tildefriends-ios%.app/tildefriends
|
|||||||
ideviceinstaller -i $(realpath $(dir $<))
|
ideviceinstaller -i $(realpath $(dir $<))
|
||||||
|
|
||||||
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends ## Build, install, and run an iOS debug build.
|
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends ## Build, install, and run an iOS debug build.
|
||||||
|
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/tildefriends-iossimdebug.app
|
||||||
xcrun simctl install booted out/tildefriends-iossimdebug.app/
|
xcrun simctl install booted out/tildefriends-iossimdebug.app/
|
||||||
xcrun simctl launch booted com.unprompted.tildefriends
|
xcrun simctl launch --console booted com.unprompted.tildefriends
|
||||||
.PHONY: iossimdebuggo
|
.PHONY: iossimdebuggo
|
||||||
|
|
||||||
ANDROID_DEPS := out/openssl/android/arm64-v8a/usr/local/lib/libssl.a
|
|
||||||
$(ANDROID_DEPS):
|
|
||||||
+@export ANDROID_NDK_ROOT=$(ANDROID_NDK)
|
|
||||||
+@export BUILD_PLATFORM=android
|
|
||||||
+@export TOOLCHAIN=$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64
|
|
||||||
+@PATH="$$TOOLCHAIN/x86_64-linux-android/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=x86_64 SSL_TARGET=android-x86_64 OPTIONS="-D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
|
||||||
+@PATH="$$TOOLCHAIN/i686-linux-android/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=x86 SSL_TARGET=android-x86 OPTIONS="-D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
|
||||||
+@PATH="$$TOOLCHAIN/arm-linux-androideabi/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=armeabi-v7a SSL_TARGET=android-arm OPTIONS="--target=armv7a-linux-androideabi -Wl,--fix-cortex-a8 -D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
|
||||||
+@PATH="$$TOOLCHAIN/aarch64-linux-android/bin:$$TOOLCHAIN/bin:$$PATH" BUILD_TARGET=arm64-v8a SSL_TARGET=android-arm64 OPTIONS="-D__ANDROID_API__=$(ANDROID_MIN_SDK_VERSION) -Wno-macro-redefined" tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/android%,$(APP_OBJS)): | $(ANDROID_DEPS)
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Linux)
|
|
||||||
ifneq ($(USE_SYSTEM_SSL),1)
|
|
||||||
LOCAL_DEPS := out/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib/libssl.a
|
|
||||||
$(LOCAL_DEPS):
|
|
||||||
+@tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/debug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/release/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(HAVE_CROSS_AARCH64),1)
|
|
||||||
LOCAL_DEPS := out/openssl/$(UNAME_S)/aarch64/usr/local/lib/libssl.a
|
|
||||||
$(LOCAL_DEPS):
|
|
||||||
+@OPTIONS="--cross-compile-prefix=aarch64-linux-gnu-" BUILD_TARGET=aarch64 SSL_TARGET=linux-aarch64 tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/armdebug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/armrelease/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(HAVE_LINUX_IOS),1)
|
|
||||||
LOCAL_DEPS := out/openssl/$(UNAME_S)/ios64-cross/usr/local/lib/libssl.a
|
|
||||||
$(LOCAL_DEPS):
|
|
||||||
+@PATH=deps/ios_toolchain/target/bin:$$PATH \
|
|
||||||
BUILD_TARGET=ios64-cross \
|
|
||||||
SSL_TARGET=ios64-cross \
|
|
||||||
CROSS_COMPILE=../../deps/ios_toolchain/target/bin/arm-apple-darwin11- \
|
|
||||||
CROSS_TOP=../../deps/ios_toolchain/target \
|
|
||||||
CROSS_SDK=iPhoneOS18.2.sdk \
|
|
||||||
CC=clang \
|
|
||||||
OPTIONS=-miphoneos-version-min=$(IPHONEOS_VERSION_MIN) \
|
|
||||||
tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(HAVE_LINUX_MACOS),1)
|
|
||||||
LOCAL_DEPS := out/openssl/$(UNAME_S)/macos-arm/usr/local/lib/libssl.a
|
|
||||||
$(LOCAL_DEPS):
|
|
||||||
+@PATH=../../deps/macos_toolchain/bin:$$PATH \
|
|
||||||
BUILD_TARGET=macos-arm \
|
|
||||||
SSL_TARGET=darwin64-arm64 \
|
|
||||||
CC=../../deps/macos_toolchain/bin/oa64-clang \
|
|
||||||
RANLIB=../../deps/macos_toolchain/bin/x86_64-apple-darwin24-ranlib \
|
|
||||||
AR=../../deps/macos_toolchain/bin/arm64-apple-darwin24-ar \
|
|
||||||
tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/macosrelease-arm/% $(BUILD_DIR)/macosdebug-arm/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
|
||||||
|
|
||||||
LOCAL_DEPS := out/openssl/$(UNAME_S)/macos-x86_64/usr/local/lib/libssl.a
|
|
||||||
$(LOCAL_DEPS):
|
|
||||||
+@PATH=../../deps/macos_toolchain/bin:$$PATH \
|
|
||||||
BUILD_TARGET=macos-x86_64 \
|
|
||||||
SSL_TARGET=darwin64-x86_64 \
|
|
||||||
CC=../../deps/macos_toolchain/bin/o64-clang \
|
|
||||||
RANLIB=../../deps/macos_toolchain/bin/x86_64-apple-darwin24-ranlib \
|
|
||||||
AR=../../deps/macos_toolchain/bin/x86_64-apple-darwin24-ar \
|
|
||||||
tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/macosrelease-x86_64/% $(BUILD_DIR)/macosdebug-x86_64/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
LOCAL_DEPS := out/openssl/$(UNAME_S)/$(UNAME_M)/usr/local/lib/libssl.a
|
|
||||||
$(LOCAL_DEPS):
|
|
||||||
+@tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/debug/%,$(APP_OBJS)) $(filter $(BUILD_DIR)/release/%,$(APP_OBJS)): | $(LOCAL_DEPS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(HAVE_WIN),1)
|
|
||||||
WINDOWS_DEPS := out/openssl/$(UNAME_S)/mingw64/usr/local/lib/libssl.a
|
|
||||||
$(WINDOWS_DEPS):
|
|
||||||
+@BUILD_TARGET=mingw64 SSL_TARGET=mingw64 OPTIONS="--cross-compile-prefix=x86_64-w64-mingw32-" tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/win%,$(APP_OBJS)): | $(WINDOWS_DEPS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
IOS_DEPS := out/openssl/ios/ios64-xcrun/usr/local/lib/libssl.a
|
|
||||||
$(IOS_DEPS):
|
|
||||||
+@BUILD_PLATFORM=ios BUILD_TARGET=ios64-xcrun SSL_TARGET=ios64-xcrun OPTIONS="-fPIC -Wno-macro-redefined -miphoneos-version-min=$(IPHONEOS_VERSION_MIN)" tools/ssl-local
|
|
||||||
+@BUILD_PLATFORM=ios BUILD_TARGET=iossimulator-xcrun SSL_TARGET=iossimulator-xcrun OPTIONS="-fPIC -Wno-macro-redefined" tools/ssl-local
|
|
||||||
$(filter $(BUILD_DIR)/ios%,$(APP_OBJS)): | $(IOS_DEPS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
out/macos%/tildefriends: out/macos%-arm/tildefriends out/macos%-x86_64/tildefriends
|
out/macos%/tildefriends: out/macos%-arm/tildefriends out/macos%-x86_64/tildefriends
|
||||||
@echo [lipo] $@
|
@echo [lipo] $@
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@@ -1376,7 +1259,6 @@ tarball: ## Build an all-inclusive source tarball (.tar.xz).
|
|||||||
--exclude=deps/libsodium/test \
|
--exclude=deps/libsodium/test \
|
||||||
--exclude=deps/libuv/docs \
|
--exclude=deps/libuv/docs \
|
||||||
--exclude=deps/libuv/test \
|
--exclude=deps/libuv/test \
|
||||||
--exclude=deps/speedscope/*.map \
|
|
||||||
--exclude=deps/sqlite/shell.c \
|
--exclude=deps/sqlite/shell.c \
|
||||||
--exclude=deps/zlib/contrib/vstudio \
|
--exclude=deps/zlib/contrib/vstudio \
|
||||||
--exclude=deps/zlib/doc \
|
--exclude=deps/zlib/doc \
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ dependencies in the right places.
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
System OpenSSL libraries are assumed to be available on Haiku and OpenBSD.
|
|
||||||
|
|
||||||
On MacOS, Xcode's command-line tools are expected to be available.
|
On MacOS, Xcode's command-line tools are expected to be available.
|
||||||
|
|
||||||
### Build Commands
|
### Build Commands
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "📜",
|
"emoji": "📜",
|
||||||
"previous": "&BEf0nraBdHk/+PWqx6tOSu5rheWVaxaL7orAOz3285M=.sha256"
|
"previous": "&sJqeyYjHys6Z8IqqtZ2ij2ZC1E2xieu/FU/u2hE+O1U=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ app.setDocument(`<head>
|
|||||||
</head>
|
</head>
|
||||||
<body style="color:#fff">
|
<body style="color:#fff">
|
||||||
${markdown(docs.docs.global)}
|
${markdown(docs.docs.global)}
|
||||||
|
<!--
|
||||||
|
${Object.keys(docs.docs).filter(x => [...treeify('', globalThis)].indexOf(x) == -1).map(x => `<p>STALE: ${x}</p>`).join('')}
|
||||||
|
-->
|
||||||
${[...treeify('', globalThis)].map(x => document(x)).join('\n')}
|
${[...treeify('', globalThis)].map(x => document(x)).join('\n')}
|
||||||
<a id="Database"></a>
|
<a id="Database"></a>
|
||||||
${markdown(docs.docs.database)}
|
${markdown(docs.docs.database)}
|
||||||
|
|||||||
@@ -195,51 +195,6 @@ Call a function after some delay.
|
|||||||
* *Number* **timeout** Number of milliseconds to wait before calling the callback function.
|
* *Number* **timeout** Number of milliseconds to wait before calling the callback function.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
docs['parseHttpRequest()'] = `
|
|
||||||
Parses an HTTP request.
|
|
||||||
### Parameters
|
|
||||||
* *Uint8Array* **request** The request data. Maybe be partial or contain extra data. The return value will
|
|
||||||
indicate when and where it is complete.
|
|
||||||
* *Number* **last_length** The length of the data passed on a previous attempt for the same request, or 0 initially.
|
|
||||||
### Returns
|
|
||||||
* *Integer* **-2** if the request is incomplete.
|
|
||||||
* *Integer* **-1** if the request could not be parsed.
|
|
||||||
* *Object* An object with **bytes_parsed**, **minor_version**, **path**, and **headers** fields on successful parse.
|
|
||||||
`;
|
|
||||||
|
|
||||||
docs['parseHttpResponse()'] = `
|
|
||||||
Parses an HTTP response.
|
|
||||||
### Parameters
|
|
||||||
* *Uint8Array* **response** The response data. Maybe be partial or contain extra data. The return value will
|
|
||||||
indicate when and where it is complete.
|
|
||||||
* *Number* **last_length** The length of the data passed on a previous attempt for the same response, or 0 initially.
|
|
||||||
### Returns
|
|
||||||
* *Integer* **-2** if the response is incomplete.
|
|
||||||
* *Integer* **-1** if the response could not be parsed.
|
|
||||||
* *Object* An object with **bytes_parsed**, **minor_version**, **status**, **message**, and **headers** fields on successful parse.
|
|
||||||
`;
|
|
||||||
|
|
||||||
docs['sha1Digest()'] = `
|
|
||||||
Calculates a SHA1 digest.
|
|
||||||
|
|
||||||
Completes synchronously.
|
|
||||||
### Parameters
|
|
||||||
* *String* **value** The value for which to calculate the digest.
|
|
||||||
### Returns
|
|
||||||
*String* The SHA1 digest of UTF-8 encoded \`value\`.
|
|
||||||
`;
|
|
||||||
|
|
||||||
docs['maskBytes()'] = `
|
|
||||||
Masks bytes for WebSocket communication.
|
|
||||||
|
|
||||||
Completes synchronously.
|
|
||||||
### Parameters
|
|
||||||
* *Uint8Array* **bytes** The byte array of data to mask.
|
|
||||||
* *Uint32* **mask** The mask to apply.
|
|
||||||
### Returns
|
|
||||||
*Uint32Array* The masked bytes.
|
|
||||||
`;
|
|
||||||
|
|
||||||
docs['exit()'] = `
|
docs['exit()'] = `
|
||||||
Exits the app. But why would you want to do that?
|
Exits the app. But why would you want to do that?
|
||||||
|
|
||||||
|
|||||||
8
apps/blog/lit-all.min.js
vendored
8
apps/issues/lit-all.min.js
vendored
8
apps/journal/lit-all.min.js
vendored
8
apps/sneaker/lit-all.min.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🦀",
|
"emoji": "🦀",
|
||||||
"previous": "&Rn4Eg5ev5qhrYRnwxPB0DiEwO7VdGMDGp7tL/W7bRZo=.sha256"
|
"previous": "&t4hk+Y6NB+TftzDLhJ9gUKLPU5YcFYvTEbJuTT2qPCQ=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import * as tfrpc from '/tfrpc.js';
|
|||||||
|
|
||||||
let g_database;
|
let g_database;
|
||||||
let g_hash;
|
let g_hash;
|
||||||
|
let g_sql_cache = {};
|
||||||
|
|
||||||
tfrpc.register(async function localStorageGet(key) {
|
tfrpc.register(async function localStorageGet(key) {
|
||||||
return app.localStorageGet(key);
|
return app.localStorageGet(key);
|
||||||
@@ -51,11 +52,38 @@ tfrpc.register(async function connect(token) {
|
|||||||
tfrpc.register(async function closeConnection(id) {
|
tfrpc.register(async function closeConnection(id) {
|
||||||
await ssb.closeConnection(id);
|
await ssb.closeConnection(id);
|
||||||
});
|
});
|
||||||
tfrpc.register(async function query(sql, args) {
|
tfrpc.register(async function query(sql, args, options) {
|
||||||
|
let start = new Date();
|
||||||
let result = [];
|
let result = [];
|
||||||
await ssb.sqlAsync(sql, args, function callback(row) {
|
let key = options?.cacheable ? JSON.stringify([sql, args]) : undefined;
|
||||||
result.push(row);
|
let entry = key ? g_sql_cache[key] : undefined;
|
||||||
});
|
const k_ideal_count = 64;
|
||||||
|
if (entry) {
|
||||||
|
result = entry.result;
|
||||||
|
} else {
|
||||||
|
await ssb.sqlAsync(sql, args, function callback(row) {
|
||||||
|
result.push(row);
|
||||||
|
});
|
||||||
|
if (key) {
|
||||||
|
g_sql_cache[key] = {
|
||||||
|
result: result,
|
||||||
|
time: new Date().valueOf(),
|
||||||
|
};
|
||||||
|
if (Object.keys(g_sql_cache).length > k_ideal_count * 2) {
|
||||||
|
let aged = Object.entries(g_sql_cache).map(([k, v]) => [v.time, k]);
|
||||||
|
aged.sort();
|
||||||
|
for (let i = 0; i < aged.length / 2; i++) {
|
||||||
|
delete g_sql_cache[aged[i][1]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let end = new Date();
|
||||||
|
print(
|
||||||
|
(end - start) / 1000,
|
||||||
|
entry ? 'from cache' : 'from db',
|
||||||
|
sql.replaceAll(/\s+/g, ' ').trim()
|
||||||
|
);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
tfrpc.register(async function appendMessage(id, message) {
|
tfrpc.register(async function appendMessage(id, message) {
|
||||||
@@ -76,6 +104,9 @@ tfrpc.register(function setHash(hash) {
|
|||||||
core.register('onMessage', async function (id) {
|
core.register('onMessage', async function (id) {
|
||||||
await tfrpc.rpc.notifyNewMessage(id);
|
await tfrpc.rpc.notifyNewMessage(id);
|
||||||
});
|
});
|
||||||
|
core.register('onBlob', async function (id) {
|
||||||
|
await tfrpc.rpc.notifyNewBlob(id);
|
||||||
|
});
|
||||||
tfrpc.register(async function store_blob(blob) {
|
tfrpc.register(async function store_blob(blob) {
|
||||||
if (Array.isArray(blob)) {
|
if (Array.isArray(blob)) {
|
||||||
blob = Uint8Array.from(blob);
|
blob = Uint8Array.from(blob);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {html, render} from './lit-all.min.js';
|
import {html, render} from './lit-all.min.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
let g_emojis;
|
let g_emojis;
|
||||||
|
|
||||||
@@ -140,6 +140,9 @@ export async function picker(callback, anchor, author, recent) {
|
|||||||
<style>
|
<style>
|
||||||
${styles}
|
${styles}
|
||||||
</style>
|
</style>
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
<div
|
<div
|
||||||
class="w3-modal"
|
class="w3-modal"
|
||||||
style="display: block; box-sizing: border-box; z-index: 10"
|
style="display: block; box-sizing: border-box; z-index: 10"
|
||||||
|
|||||||
8
apps/ssb/lit-all.min.js
vendored
@@ -12,12 +12,14 @@ import * as tf_tab_news from './tf-tab-news.js';
|
|||||||
import * as tf_tab_news_feed from './tf-tab-news-feed.js';
|
import * as tf_tab_news_feed from './tf-tab-news-feed.js';
|
||||||
import * as tf_tab_search from './tf-tab-search.js';
|
import * as tf_tab_search from './tf-tab-search.js';
|
||||||
import * as tf_tab_connections from './tf-tab-connections.js';
|
import * as tf_tab_connections from './tf-tab-connections.js';
|
||||||
import * as tf_tab_query from './tf-tab-query.js';
|
|
||||||
import * as tf_tag from './tf-tag.js';
|
import * as tf_tag from './tf-tag.js';
|
||||||
import * as tf_styles from './tf-styles.js';
|
import * as tf_styles from './tf-styles.js';
|
||||||
|
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
let style = document.createElement('style');
|
let style = document.createElement('style');
|
||||||
style.innerText = tf_styles.styles;
|
style.innerText = tf_styles.styles;
|
||||||
|
Promise.resolve(tf_styles.generate_theme()).then(function (x) {
|
||||||
|
style.innerText += x;
|
||||||
|
});
|
||||||
document.body.appendChild(style);
|
document.body.appendChild(style);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html, css, guard, until} from './lit-all.min.js';
|
import {LitElement, html, css, guard, until} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfElement extends LitElement {
|
class TfElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -21,8 +21,13 @@ class TfElement extends LitElement {
|
|||||||
channels_latest: {type: Object},
|
channels_latest: {type: Object},
|
||||||
guest: {type: Boolean},
|
guest: {type: Boolean},
|
||||||
url: {type: String},
|
url: {type: String},
|
||||||
|
private_closed: {type: Object},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
grouped_private_messages: {type: Object},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
|
is_administrator: {type: Boolean},
|
||||||
|
stay_connected: {type: Boolean},
|
||||||
|
progress: {type: Number},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +50,7 @@ class TfElement extends LitElement {
|
|||||||
this.loading_latest = 0;
|
this.loading_latest = 0;
|
||||||
this.loading_latest_scheduled = 0;
|
this.loading_latest_scheduled = 0;
|
||||||
this.recent_reactions = [];
|
this.recent_reactions = [];
|
||||||
|
this.private_closed = {};
|
||||||
tfrpc.rpc.getBroadcasts().then((b) => {
|
tfrpc.rpc.getBroadcasts().then((b) => {
|
||||||
self.broadcasts = b || [];
|
self.broadcasts = b || [];
|
||||||
});
|
});
|
||||||
@@ -54,10 +60,22 @@ class TfElement extends LitElement {
|
|||||||
tfrpc.rpc.getHash().then((hash) => self.set_hash(hash));
|
tfrpc.rpc.getHash().then((hash) => self.set_hash(hash));
|
||||||
tfrpc.register(function hashChanged(hash) {
|
tfrpc.register(function hashChanged(hash) {
|
||||||
self.set_hash(hash);
|
self.set_hash(hash);
|
||||||
|
self.reset_progress();
|
||||||
});
|
});
|
||||||
tfrpc.register(async function notifyNewMessage(id) {
|
tfrpc.register(async function notifyNewMessage(id) {
|
||||||
await self.fetch_new_message(id);
|
await self.fetch_new_message(id);
|
||||||
});
|
});
|
||||||
|
tfrpc.register(async function notifyNewBlob(id) {
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent('blob-stored', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: {
|
||||||
|
id: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
tfrpc.register(function set(name, value) {
|
tfrpc.register(function set(name, value) {
|
||||||
if (name === 'broadcasts') {
|
if (name === 'broadcasts') {
|
||||||
self.broadcasts = value;
|
self.broadcasts = value;
|
||||||
@@ -73,13 +91,30 @@ class TfElement extends LitElement {
|
|||||||
async initial_load() {
|
async initial_load() {
|
||||||
let whoami = await tfrpc.rpc.getActiveIdentity();
|
let whoami = await tfrpc.rpc.getActiveIdentity();
|
||||||
let ids = (await tfrpc.rpc.getIdentities()) || [];
|
let ids = (await tfrpc.rpc.getIdentities()) || [];
|
||||||
|
this.is_administrator = await tfrpc.rpc.isAdministrator();
|
||||||
|
this.stay_connected =
|
||||||
|
this.is_administrator &&
|
||||||
|
(await tfrpc.rpc.globalSettingsGet('stay_connected'));
|
||||||
this.url = await tfrpc.rpc.url();
|
this.url = await tfrpc.rpc.url();
|
||||||
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
|
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
|
||||||
this.guest = !this.whoami?.length;
|
this.guest = !this.whoami?.length;
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
|
let private_closed =
|
||||||
|
(await tfrpc.rpc.databaseGet('private_closed')) ?? '{}';
|
||||||
|
this.private_closed = JSON.parse(private_closed);
|
||||||
await this.load_channels();
|
await this.load_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async close_private_chat(event) {
|
||||||
|
let update = {};
|
||||||
|
update[event.detail.key] = true;
|
||||||
|
this.private_closed = Object.assign(update, this.private_closed);
|
||||||
|
await tfrpc.rpc.databaseSet(
|
||||||
|
'private_closed',
|
||||||
|
JSON.stringify(this.private_closed)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async load_channels() {
|
async load_channels() {
|
||||||
let channels = await tfrpc.rpc.query(
|
let channels = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
@@ -127,12 +162,33 @@ class TfElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visible_private() {
|
||||||
|
if (!this.grouped_private_messages || !this.private_closed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let self = this;
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(this.grouped_private_messages).filter(([key, value]) => {
|
||||||
|
let channel = '🔐' + [...new Set(JSON.parse(key))].sort().join(',');
|
||||||
|
let grouped_latest = Math.max(...value.map((x) => x.rowid));
|
||||||
|
return (
|
||||||
|
!self.private_closed[key] ||
|
||||||
|
self.channels_unread[channel] === undefined ||
|
||||||
|
grouped_latest > self.channels_unread[channel]
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
next_channel(delta) {
|
next_channel(delta) {
|
||||||
let channel_names = [
|
let channel_names = [
|
||||||
'',
|
'',
|
||||||
'@',
|
'@',
|
||||||
'🔐',
|
|
||||||
'👍',
|
'👍',
|
||||||
|
'🚩',
|
||||||
|
...Object.keys(this.visible_private())
|
||||||
|
.sort()
|
||||||
|
.map((x) => '🔐' + JSON.parse(x).join(',')),
|
||||||
...this.channels.map((x) => '#' + x),
|
...this.channels.map((x) => '#' + x),
|
||||||
];
|
];
|
||||||
let index = channel_names.indexOf(this.hash.substring(1));
|
let index = channel_names.indexOf(this.hash.substring(1));
|
||||||
@@ -151,8 +207,6 @@ class TfElement extends LitElement {
|
|||||||
this.tab = 'search';
|
this.tab = 'search';
|
||||||
} else if (this.hash === '#connections') {
|
} else if (this.hash === '#connections') {
|
||||||
this.tab = 'connections';
|
this.tab = 'connections';
|
||||||
} else if (this.hash.startsWith('#sql=')) {
|
|
||||||
this.tab = 'query';
|
|
||||||
} else {
|
} else {
|
||||||
this.tab = 'news';
|
this.tab = 'news';
|
||||||
}
|
}
|
||||||
@@ -350,12 +404,34 @@ class TfElement extends LitElement {
|
|||||||
return [cache.latest, cache.messages];
|
return [cache.latest, cache.messages];
|
||||||
}
|
}
|
||||||
|
|
||||||
async query_timed(sql, args) {
|
async group_private_messages(messages) {
|
||||||
let start = new Date();
|
let groups = {};
|
||||||
let result = await tfrpc.rpc.query(sql, args);
|
let result = await this.decrypt(
|
||||||
let end = new Date();
|
await tfrpc.rpc.query(
|
||||||
console.log((end - start) / 1000, sql);
|
`
|
||||||
return result;
|
SELECT messages.rowid, messages.id, author, timestamp, json(content) AS content
|
||||||
|
FROM messages
|
||||||
|
JOIN json_each(?) AS ids
|
||||||
|
WHERE messages.id = ids.value
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
`,
|
||||||
|
[JSON.stringify(messages)]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (let message of result) {
|
||||||
|
let key = JSON.stringify(
|
||||||
|
[
|
||||||
|
...new Set(
|
||||||
|
message?.decrypted?.recps?.filter((x) => x != this.whoami)
|
||||||
|
),
|
||||||
|
].sort() ?? []
|
||||||
|
);
|
||||||
|
if (!groups[key]) {
|
||||||
|
groups[key] = [];
|
||||||
|
}
|
||||||
|
groups[key].push(message);
|
||||||
|
}
|
||||||
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
async load_channels_latest(following) {
|
async load_channels_latest(following) {
|
||||||
@@ -369,7 +445,7 @@ class TfElement extends LitElement {
|
|||||||
];
|
];
|
||||||
let channels = (
|
let channels = (
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.query_timed(
|
tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||||
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
|
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
|
||||||
@@ -382,7 +458,7 @@ class TfElement extends LitElement {
|
|||||||
`,
|
`,
|
||||||
k_args
|
k_args
|
||||||
),
|
),
|
||||||
this.query_timed(
|
tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||||
JOIN messages_refs ON messages.id = messages_refs.message
|
JOIN messages_refs ON messages.id = messages_refs.message
|
||||||
@@ -396,7 +472,7 @@ class TfElement extends LitElement {
|
|||||||
`,
|
`,
|
||||||
k_args
|
k_args
|
||||||
),
|
),
|
||||||
this.query_timed(
|
tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||||
@@ -407,7 +483,7 @@ class TfElement extends LitElement {
|
|||||||
`,
|
`,
|
||||||
k_args
|
k_args
|
||||||
),
|
),
|
||||||
this.query_timed(
|
tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
|
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
|
||||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||||
@@ -416,19 +492,16 @@ class TfElement extends LitElement {
|
|||||||
`,
|
`,
|
||||||
k_args
|
k_args
|
||||||
),
|
),
|
||||||
this.query_timed(
|
tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT '👍' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
SELECT '🚩' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
WHERE messages.content ->> 'type' = 'flag'
|
||||||
WHERE
|
|
||||||
messages.content ->> 'type' = 'vote' AND
|
|
||||||
messages.author != ?4
|
|
||||||
`,
|
`,
|
||||||
k_args
|
k_args
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
).flat();
|
).flat();
|
||||||
let latest = {};
|
let latest = {'🔐': undefined};
|
||||||
for (let row of channels) {
|
for (let row of channels) {
|
||||||
if (!latest[row.channel]) {
|
if (!latest[row.channel]) {
|
||||||
latest[row.channel] = row.rowid;
|
latest[row.channel] = row.rowid;
|
||||||
@@ -440,12 +513,14 @@ class TfElement extends LitElement {
|
|||||||
console.log('channels took', (new Date() - start_time) / 1000.0);
|
console.log('channels took', (new Date() - start_time) / 1000.0);
|
||||||
let self = this;
|
let self = this;
|
||||||
start_time = new Date();
|
start_time = new Date();
|
||||||
latest_private.then(function (latest) {
|
latest_private.then(async function (latest) {
|
||||||
|
let grouped = await self.group_private_messages(latest[1]);
|
||||||
self.channels_latest = Object.assign({}, self.channels_latest, {
|
self.channels_latest = Object.assign({}, self.channels_latest, {
|
||||||
'🔐': latest[0],
|
'🔐': latest[0],
|
||||||
});
|
});
|
||||||
console.log('private took', (new Date() - start_time) / 1000.0);
|
|
||||||
self.private_messages = latest[1];
|
self.private_messages = latest[1];
|
||||||
|
self.grouped_private_messages = grouped;
|
||||||
|
console.log('private took', (new Date() - start_time) / 1000.0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +529,28 @@ class TfElement extends LitElement {
|
|||||||
this.schedule_load_latest();
|
this.schedule_load_latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset_progress() {
|
||||||
|
if (this.progress === undefined) {
|
||||||
|
this._progress_start = new Date();
|
||||||
|
requestAnimationFrame(this.update_progress.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_progress() {
|
||||||
|
if (
|
||||||
|
!this.loading_latest &&
|
||||||
|
!this.loading_latest_scheduled &&
|
||||||
|
!this.shadowRoot.getElementById('tf-tab-news')?.is_loading()
|
||||||
|
) {
|
||||||
|
this.progress = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.progress = (new Date() - this._progress_start).valueOf();
|
||||||
|
requestAnimationFrame(this.update_progress.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
schedule_load_latest() {
|
schedule_load_latest() {
|
||||||
|
this.reset_progress();
|
||||||
if (!this.loading_latest) {
|
if (!this.loading_latest) {
|
||||||
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
|
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
|
||||||
this.load();
|
this.load();
|
||||||
@@ -499,6 +595,7 @@ class TfElement extends LitElement {
|
|||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.loading_latest = true;
|
this.loading_latest = true;
|
||||||
|
this.reset_progress();
|
||||||
try {
|
try {
|
||||||
let start_time = new Date();
|
let start_time = new Date();
|
||||||
let whoami = this.whoami;
|
let whoami = this.whoami;
|
||||||
@@ -605,9 +702,17 @@ class TfElement extends LitElement {
|
|||||||
.channels_latest=${this.channels_latest}
|
.channels_latest=${this.channels_latest}
|
||||||
.channels_unread=${this.channels_unread}
|
.channels_unread=${this.channels_unread}
|
||||||
@channelsetunread=${this.channel_set_unread}
|
@channelsetunread=${this.channel_set_unread}
|
||||||
|
@refresh=${this.refresh}
|
||||||
|
@toggle_stay_connected=${this.toggle_stay_connected}
|
||||||
|
@loadmessages=${this.reset_progress}
|
||||||
|
@closeprivatechat=${this.close_private_chat}
|
||||||
.connections=${this.connections}
|
.connections=${this.connections}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
|
.visible_private_messages=${this.visible_private()}
|
||||||
|
.grouped_private_messages=${this.grouped_private_messages}
|
||||||
.recent_reactions=${this.recent_reactions}
|
.recent_reactions=${this.recent_reactions}
|
||||||
|
?is_administrator=${this.is_administrator}
|
||||||
|
?stay_connected=${this.stay_connected}
|
||||||
></tf-tab-news>
|
></tf-tab-news>
|
||||||
`;
|
`;
|
||||||
} else if (this.tab === 'connections') {
|
} else if (this.tab === 'connections') {
|
||||||
@@ -629,28 +734,16 @@ class TfElement extends LitElement {
|
|||||||
: null}
|
: null}
|
||||||
></tf-tab-search>
|
></tf-tab-search>
|
||||||
`;
|
`;
|
||||||
} else if (this.tab === 'query') {
|
|
||||||
return html`
|
|
||||||
<tf-tab-query
|
|
||||||
.following=${this.following}
|
|
||||||
whoami=${this.whoami}
|
|
||||||
.users=${this.users}
|
|
||||||
query=${this.hash?.startsWith('#sql=')
|
|
||||||
? decodeURIComponent(this.hash.substring(5))
|
|
||||||
: null}
|
|
||||||
></tf-tab-query>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async set_tab(tab) {
|
async set_tab(tab) {
|
||||||
this.tab = tab;
|
this.tab = tab;
|
||||||
if (tab === 'news') {
|
if (tab === 'news') {
|
||||||
|
this.schedule_load_latest();
|
||||||
await tfrpc.rpc.setHash('#');
|
await tfrpc.rpc.setHash('#');
|
||||||
} else if (tab === 'connections') {
|
} else if (tab === 'connections') {
|
||||||
await tfrpc.rpc.setHash('#connections');
|
await tfrpc.rpc.setHash('#connections');
|
||||||
} else if (tab === 'query') {
|
|
||||||
await tfrpc.rpc.setHash('#sql=');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,6 +751,29 @@ class TfElement extends LitElement {
|
|||||||
tfrpc.rpc.sync();
|
tfrpc.rpc.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggle_stay_connected() {
|
||||||
|
let stay_connected = await tfrpc.rpc.globalSettingsGet('stay_connected');
|
||||||
|
let new_stay_connected = !this.stay_connected;
|
||||||
|
try {
|
||||||
|
if (new_stay_connected != stay_connected) {
|
||||||
|
await tfrpc.rpc.globalSettingsSet('stay_connected', new_stay_connected);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.stay_connected = await tfrpc.rpc.globalSettingsGet('stay_connected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async pick_color() {
|
||||||
|
let input = document.createElement('input');
|
||||||
|
input.type = 'color';
|
||||||
|
input.value = (await tfrpc.rpc.localStorageGet('color')) ?? '#ff0000';
|
||||||
|
input.addEventListener('change', async function () {
|
||||||
|
await tfrpc.rpc.localStorageSet('color', input.value);
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
@@ -672,7 +788,6 @@ class TfElement extends LitElement {
|
|||||||
'📰': 'news',
|
'📰': 'news',
|
||||||
'📡': 'connections',
|
'📡': 'connections',
|
||||||
'🔍': 'search',
|
'🔍': 'search',
|
||||||
'👩💻': 'query',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let tabs = html`
|
let tabs = html`
|
||||||
@@ -680,14 +795,25 @@ class TfElement extends LitElement {
|
|||||||
class="w3-bar w3-theme-l1"
|
class="w3-bar w3-theme-l1"
|
||||||
style="position: static; top: 0; z-index: 10"
|
style="position: static; top: 0; z-index: 10"
|
||||||
>
|
>
|
||||||
<button
|
${this.is_administrator
|
||||||
class=${'w3-bar-item w3-button w3-circle w3-ripple' +
|
? html`
|
||||||
(this.connections?.some((x) => x.flags.one_shot) ? ' w3-spin' : '')}
|
<button
|
||||||
style="width: 1.5em; height: 1.5em; padding: 8px"
|
class=${'w3-bar-item w3-button w3-circle w3-ripple' +
|
||||||
@click=${this.refresh}
|
(this.connections?.some((x) => x.flags.one_shot)
|
||||||
>
|
? ' w3-spin'
|
||||||
↻
|
: '')}
|
||||||
</button>
|
@click=${this.refresh}
|
||||||
|
>
|
||||||
|
↻
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="w3-bar-item w3-button w3-ripple"
|
||||||
|
@click=${this.toggle_stay_connected}
|
||||||
|
>
|
||||||
|
${this.stay_connected ? '🔗' : '⛓️💥'}
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
: undefined}
|
||||||
${Object.entries(k_tabs).map(
|
${Object.entries(k_tabs).map(
|
||||||
([k, v]) => html`
|
([k, v]) => html`
|
||||||
<button
|
<button
|
||||||
@@ -704,6 +830,12 @@ class TfElement extends LitElement {
|
|||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
|
<button
|
||||||
|
class="w3-bar-item w3-button w3-right"
|
||||||
|
@click=${this.pick_color}
|
||||||
|
>
|
||||||
|
🎨<span class="w3-hide-small">Color</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
let contents = this.guest
|
let contents = this.guest
|
||||||
@@ -727,11 +859,26 @@ class TfElement extends LitElement {
|
|||||||
Loading...
|
Loading...
|
||||||
</div>`
|
</div>`
|
||||||
: this.render_tab();
|
: this.render_tab();
|
||||||
|
let progress =
|
||||||
|
this.progress !== undefined
|
||||||
|
? html`
|
||||||
|
<div style="position: absolute; width: 100%" id="progress">
|
||||||
|
<div
|
||||||
|
class="w3-theme-l3"
|
||||||
|
style=${`height: 4px; position: absolute; right: ${Math.cos(this.progress / 250) > 0 ? 'auto' : '0'}; width: ${50 * Math.sin(this.progress / 250) + 50}%`}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: undefined;
|
||||||
return html`
|
return html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
<div
|
<div
|
||||||
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
|
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
|
||||||
class="w3-theme-dark"
|
class="w3-theme-dark"
|
||||||
>
|
>
|
||||||
|
${progress}
|
||||||
<div style="flex: 0 0">${tabs}</div>
|
<div style="flex: 0 0">${tabs}</div>
|
||||||
<div style="flex: 1 1; overflow: auto; contain: layout">
|
<div style="flex: 1 1; overflow: auto; contain: layout">
|
||||||
${contents}
|
${contents}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {LitElement, html, unsafeHTML, live} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML, live} from './lit-all.min.js';
|
||||||
import * as tfutils from './tf-utils.js';
|
import * as tfutils from './tf-utils.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
import Tribute from './tribute.esm.js';
|
import Tribute from './tribute.esm.js';
|
||||||
|
|
||||||
class TfComposeElement extends LitElement {
|
class TfComposeElement extends LitElement {
|
||||||
@@ -16,6 +16,7 @@ class TfComposeElement extends LitElement {
|
|||||||
author: {type: String},
|
author: {type: String},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
new_thread: {type: Boolean},
|
new_thread: {type: Boolean},
|
||||||
|
recipients: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +92,9 @@ class TfComposeElement extends LitElement {
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
detail: {
|
detail: {
|
||||||
id: this.branch,
|
id:
|
||||||
|
this.branch ??
|
||||||
|
(this.recipients ? this.recipients.join(',') : undefined),
|
||||||
draft: draft,
|
draft: draft,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -291,7 +294,7 @@ class TfComposeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
get_values() {
|
||||||
let values = Object.entries(this.users).map((x) => ({
|
let values = Object.entries(this.users).map((x) => ({
|
||||||
key: x[1].name ?? x[0],
|
key: x[1].name ?? x[0],
|
||||||
value: x[0],
|
value: x[0],
|
||||||
@@ -307,11 +310,15 @@ class TfComposeElement extends LitElement {
|
|||||||
values
|
values
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
let tribute = new Tribute({
|
let tribute = new Tribute({
|
||||||
iframe: this.shadowRoot,
|
iframe: this.shadowRoot,
|
||||||
collection: [
|
collection: [
|
||||||
{
|
{
|
||||||
values: values,
|
values: this.get_values(),
|
||||||
selectTemplate: function (item) {
|
selectTemplate: function (item) {
|
||||||
return item
|
return item
|
||||||
? `[@${item.original.key}](${item.original.value})`
|
? `[@${item.original.key}](${item.original.value})`
|
||||||
@@ -330,6 +337,7 @@ class TfComposeElement extends LitElement {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
tribute.attach(this.renderRoot.getElementById('edit'));
|
tribute.attach(this.renderRoot.getElementById('edit'));
|
||||||
|
this._tribute = tribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
@@ -340,6 +348,7 @@ class TfComposeElement extends LitElement {
|
|||||||
preview.innerHTML = this.process_text(edit.innerText);
|
preview.innerHTML = this.process_text(edit.innerText);
|
||||||
this.last_updated_text = edit.innerText;
|
this.last_updated_text = edit.innerText;
|
||||||
}
|
}
|
||||||
|
this._tribute.collection[0].values = this.get_values();
|
||||||
let encrypt = this.renderRoot.getElementById('encrypt_to');
|
let encrypt = this.renderRoot.getElementById('encrypt_to');
|
||||||
if (encrypt) {
|
if (encrypt) {
|
||||||
let tribute = new Tribute({
|
let tribute = new Tribute({
|
||||||
@@ -496,7 +505,17 @@ class TfComposeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_draft() {
|
get_draft() {
|
||||||
return this.drafts[this.branch || ''] || {};
|
let key =
|
||||||
|
this.branch ||
|
||||||
|
(this.recipients ? this.recipients.join(',') : undefined) ||
|
||||||
|
'';
|
||||||
|
let draft = this.drafts[key] || {};
|
||||||
|
if (this.recipients && !draft.encrypt_to?.length) {
|
||||||
|
draft.encrypt_to = [
|
||||||
|
...new Set(this.recipients).union(new Set(draft.encrypt_to ?? [])),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return draft;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_encrypt(event) {
|
update_encrypt(event) {
|
||||||
@@ -581,9 +600,12 @@ class TfComposeElement extends LitElement {
|
|||||||
class="w3-button w3-bar-item w3-theme-d1"
|
class="w3-button w3-bar-item w3-theme-d1"
|
||||||
@click=${() => this.set_encrypt([])}
|
@click=${() => this.set_encrypt([])}
|
||||||
>
|
>
|
||||||
🔐
|
🔐 Encrypt
|
||||||
</button>`;
|
</button>`;
|
||||||
let result = html`
|
let result = html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
<style>
|
<style>
|
||||||
.w3-input:empty::before {
|
.w3-input:empty::before {
|
||||||
content: attr(placeholder);
|
content: attr(placeholder);
|
||||||
@@ -602,11 +624,11 @@ class TfComposeElement extends LitElement {
|
|||||||
: undefined}
|
: undefined}
|
||||||
${this.render_encrypt()}
|
${this.render_encrypt()}
|
||||||
</header>
|
</header>
|
||||||
<div class="w3-container w3-padding-small">
|
<div class="w3-container" style="padding: 0 0 16px 0">
|
||||||
<div class="w3-half">
|
<div class="w3-half">
|
||||||
<span
|
<span
|
||||||
class="w3-input w3-theme-d1 w3-border"
|
class="w3-input w3-theme-d1 w3-border"
|
||||||
style="resize: vertical; width: 100%; overflow: hidden; white-space: pre-wrap"
|
style="resize: vertical; width: 100%; white-space: pre-wrap"
|
||||||
placeholder="Write a post here."
|
placeholder="Write a post here."
|
||||||
id="edit"
|
id="edit"
|
||||||
@input=${this.input}
|
@input=${this.input}
|
||||||
@@ -623,7 +645,7 @@ class TfComposeElement extends LitElement {
|
|||||||
${Object.values(draft.mentions || {}).map((x) =>
|
${Object.values(draft.mentions || {}).map((x) =>
|
||||||
self.render_mention(x)
|
self.render_mention(x)
|
||||||
)}
|
)}
|
||||||
<footer class="w3-container">
|
<footer>
|
||||||
${this.render_attach_app()} ${this.render_content_warning()}
|
${this.render_attach_app()} ${this.render_content_warning()}
|
||||||
${this.render_new_thread()}
|
${this.render_new_thread()}
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import {
|
|||||||
html,
|
html,
|
||||||
repeat,
|
repeat,
|
||||||
render,
|
render,
|
||||||
|
unsafeCSS,
|
||||||
unsafeHTML,
|
unsafeHTML,
|
||||||
|
until,
|
||||||
} from './lit-all.min.js';
|
} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import * as tfutils from './tf-utils.js';
|
import * as tfutils from './tf-utils.js';
|
||||||
import * as emojis from './emojis.js';
|
import * as emojis from './emojis.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfMessageElement extends LitElement {
|
class TfMessageElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -24,6 +26,7 @@ class TfMessageElement extends LitElement {
|
|||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
channel_unread: {type: Number},
|
channel_unread: {type: Number},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
|
depth: {type: Number},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,16 +43,20 @@ class TfMessageElement extends LitElement {
|
|||||||
this.expanded = {};
|
this.expanded = {};
|
||||||
this.channel_unread = -1;
|
this.channel_unread = -1;
|
||||||
this.recent_reactions = [];
|
this.recent_reactions = [];
|
||||||
|
this.depth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._click_callback = this.document_click.bind(this);
|
this._click_callback = this.document_click.bind(this);
|
||||||
|
this._blob_stored = this.blob_stored.bind(this);
|
||||||
document.body.addEventListener('mouseup', this._click_callback);
|
document.body.addEventListener('mouseup', this._click_callback);
|
||||||
|
window.addEventListener('blob-stored', this._blob_stored);
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
|
window.removeEventListener('blob-stored', this._blob_stored);
|
||||||
document.body.removeEventListener('mouseup', this._click_callback);
|
document.body.removeEventListener('mouseup', this._click_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +68,16 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blob_stored(event) {
|
||||||
|
let search = `/${event.detail.id}/view`;
|
||||||
|
for (let img of this.shadowRoot.querySelectorAll('img')) {
|
||||||
|
if (img.src.indexOf(search) != -1) {
|
||||||
|
let src = img.src.split('?')[0];
|
||||||
|
img.src = `${src}?${new Date().valueOf()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
show_reply() {
|
show_reply() {
|
||||||
let event = new CustomEvent('tf-draft', {
|
let event = new CustomEvent('tf-draft', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
@@ -179,6 +196,26 @@ class TfMessageElement extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flag(event) {
|
||||||
|
let reason = prompt(
|
||||||
|
'What is the reason for reporting this content (spam, nsfw, ...)?',
|
||||||
|
'offensive'
|
||||||
|
);
|
||||||
|
if (reason !== undefined) {
|
||||||
|
tfrpc.rpc
|
||||||
|
.appendMessage(this.whoami, {
|
||||||
|
type: 'flag',
|
||||||
|
flag: {
|
||||||
|
link: this.message.id,
|
||||||
|
reason: reason.length ? reason : undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
alert(error?.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
show_image(link) {
|
show_image(link) {
|
||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
div.style.left = 0;
|
div.style.left = 0;
|
||||||
@@ -191,12 +228,12 @@ class TfMessageElement extends LitElement {
|
|||||||
div.style.display = 'grid';
|
div.style.display = 'grid';
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.src = link;
|
img.src = link;
|
||||||
img.style.maxWidth = '100%';
|
img.style.maxWidth = '100vw';
|
||||||
img.style.maxHeight = '100%';
|
img.style.maxHeight = '100vh';
|
||||||
img.style.display = 'block';
|
img.style.display = 'block';
|
||||||
img.style.margin = 'auto';
|
img.style.margin = 'auto';
|
||||||
img.style.objectFit = 'contain';
|
img.style.objectFit = 'contain';
|
||||||
img.style.width = '100%';
|
img.style.width = '100vw';
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
function image_close(event) {
|
function image_close(event) {
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(div);
|
||||||
@@ -311,7 +348,9 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expanded_key() {
|
expanded_key() {
|
||||||
return this.message?.id || this.messages?.map((x) => x.id).join(':');
|
return (
|
||||||
|
this.message?.id || this.message?.messages?.map((x) => x.id).join(':')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_expanded(expanded, tag) {
|
set_expanded(expanded, tag) {
|
||||||
@@ -349,12 +388,13 @@ class TfMessageElement extends LitElement {
|
|||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
return html` <div class="w3-container w3-margin-bottom">
|
return html` <ul class="w3-container w3-margin-bottom w3-ul w3-card-4">
|
||||||
${repeat(
|
${repeat(
|
||||||
this.message.child_messages || [],
|
this.message.child_messages || [],
|
||||||
(x) => x.id,
|
(x) => x.id,
|
||||||
(x) =>
|
(x) =>
|
||||||
html`<tf-message
|
html`<li style="padding: 0">
|
||||||
|
<tf-message
|
||||||
.message=${x}
|
.message=${x}
|
||||||
whoami=${this.whoami}
|
whoami=${this.whoami}
|
||||||
.users=${this.users}
|
.users=${this.users}
|
||||||
@@ -363,16 +403,20 @@ class TfMessageElement extends LitElement {
|
|||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
.recent_reactions=${this.recent_reactions}
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-message>`
|
depth=${this.depth + 1}
|
||||||
)}
|
></tf-message>
|
||||||
</div>
|
</li>`
|
||||||
<button
|
)}
|
||||||
class="w3-button w3-theme-d1 w3-block w3-bar"
|
<li style="padding: 0" class="w3-margin-bottom">
|
||||||
style="box-sizing: border-box"
|
<button
|
||||||
@click=${() => self.set_expanded(false)}
|
class="w3-button w3-theme-d1 w3-block w3-bar"
|
||||||
>
|
style="box-sizing: border-box"
|
||||||
Collapse
|
@click=${() => self.set_expanded(false)}
|
||||||
</button>`;
|
>
|
||||||
|
Collapse
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -475,11 +519,14 @@ class TfMessageElement extends LitElement {
|
|||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
: undefined}
|
: undefined}
|
||||||
|
<button class="w3-button w3-bar-item" @click=${this.react}>
|
||||||
|
👍 React
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
class="w3-button w3-bar-item w3-border-bottom"
|
class="w3-button w3-bar-item w3-border-bottom"
|
||||||
@click=${this.react}
|
@click=${this.flag}
|
||||||
>
|
>
|
||||||
👍 React
|
⚠️ Flag
|
||||||
</button>
|
</button>
|
||||||
${formats.map(
|
${formats.map(
|
||||||
([format, name]) => html`
|
([format, name]) => html`
|
||||||
@@ -536,8 +583,11 @@ class TfMessageElement extends LitElement {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<div
|
||||||
class="w3-card-4 ${this.class_background()} w3-border-theme w3-margin-top"
|
class="w3-card-4 ${this.class_background()} w3-border-theme ${this
|
||||||
style="overflow: auto; overflow-wrap: anywhere; display: block; max-width: 100%"
|
.depth == 0
|
||||||
|
? 'w3-margin-top'
|
||||||
|
: ''}"
|
||||||
|
style="overflow-wrap: anywhere; display: block; max-width: 100%"
|
||||||
>
|
>
|
||||||
${inner}
|
${inner}
|
||||||
</div>
|
</div>
|
||||||
@@ -563,6 +613,7 @@ class TfMessageElement extends LitElement {
|
|||||||
channel=${self.channel}
|
channel=${self.channel}
|
||||||
channel_unread=${self.channel_unread}
|
channel_unread=${self.channel_unread}
|
||||||
.recent_reactions=${self.recent_reactions}
|
.recent_reactions=${self.recent_reactions}
|
||||||
|
depth=${self.depth + 1}
|
||||||
></tf-message>
|
></tf-message>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@@ -598,15 +649,17 @@ class TfMessageElement extends LitElement {
|
|||||||
let sorted = this.message.messages
|
let sorted = this.message.messages
|
||||||
.map((x) => [
|
.map((x) => [
|
||||||
x.author,
|
x.author,
|
||||||
x.content.blocking !== undefined
|
x.content.following && x.content.blocking
|
||||||
? x.content.blocking
|
? 'is following and blocking'
|
||||||
? 'is blocking'
|
: x.content.following
|
||||||
: 'is no longer blocking'
|
? 'is following'
|
||||||
: x.content.following !== undefined
|
: x.content.blocking
|
||||||
? x.content.following
|
? 'is blocking'
|
||||||
? 'is following'
|
: x.content.blocking !== undefined
|
||||||
: 'is no longer following'
|
? 'is no longer blocking'
|
||||||
: '',
|
: x.content.following !== undefined
|
||||||
|
? 'is no longer following'
|
||||||
|
: '',
|
||||||
x.content.contact,
|
x.content.contact,
|
||||||
x,
|
x,
|
||||||
])
|
])
|
||||||
@@ -631,6 +684,35 @@ class TfMessageElement extends LitElement {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel_group_by_author() {
|
||||||
|
let sorted = this.message.messages
|
||||||
|
.map((x) => [
|
||||||
|
x.author,
|
||||||
|
x.content.subscribed ? 'subscribed to' : 'unsubscribed from',
|
||||||
|
x.content.channel,
|
||||||
|
x,
|
||||||
|
])
|
||||||
|
.sort();
|
||||||
|
let result = [];
|
||||||
|
let last;
|
||||||
|
let group;
|
||||||
|
for (let row of sorted) {
|
||||||
|
if (last && last[0] == row[0] && last[1] == row[1]) {
|
||||||
|
group.push(row[2]);
|
||||||
|
} else {
|
||||||
|
if (group) {
|
||||||
|
result.push({author: last[0], action: last[1], channels: group});
|
||||||
|
}
|
||||||
|
last = row;
|
||||||
|
group = [row[2]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (group) {
|
||||||
|
result.push({author: last[0], action: last[1], channels: group});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
allow_unread() {
|
allow_unread() {
|
||||||
return (
|
return (
|
||||||
this.channel == '@' ||
|
this.channel == '@' ||
|
||||||
@@ -644,7 +726,7 @@ class TfMessageElement extends LitElement {
|
|||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
_render() {
|
||||||
let content = this.message?.content;
|
let content = this.message?.content;
|
||||||
if (this.message?.decrypted?.type == 'post') {
|
if (this.message?.decrypted?.type == 'post') {
|
||||||
content = this.message.decrypted;
|
content = this.message.decrypted;
|
||||||
@@ -665,6 +747,7 @@ class TfMessageElement extends LitElement {
|
|||||||
.expanded=${this.expanded}
|
.expanded=${this.expanded}
|
||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
|
depth=${this.depth + 1}
|
||||||
></tf-message>`
|
></tf-message>`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -686,7 +769,11 @@ class TfMessageElement extends LitElement {
|
|||||||
${x.action}
|
${x.action}
|
||||||
${x.users.map(
|
${x.users.map(
|
||||||
(y) => html`
|
(y) => html`
|
||||||
<tf-user id=${y} .users=${this.users}></tf-user>
|
<tf-user
|
||||||
|
id=${y}
|
||||||
|
.users=${this.users}
|
||||||
|
icon_only="true"
|
||||||
|
></tf-user>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -702,6 +789,56 @@ class TfMessageElement extends LitElement {
|
|||||||
</button>
|
</button>
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
} else if (this.message?.type === 'channel_group') {
|
||||||
|
if (this.expanded[this.expanded_key()]) {
|
||||||
|
return this.render_frame(html`
|
||||||
|
<div class="w3-padding">
|
||||||
|
${this.message.messages.map(
|
||||||
|
(x) =>
|
||||||
|
html`<tf-message
|
||||||
|
.message=${x}
|
||||||
|
whoami=${this.whoami}
|
||||||
|
.users=${this.users}
|
||||||
|
.drafts=${this.drafts}
|
||||||
|
.expanded=${this.expanded}
|
||||||
|
channel=${this.channel}
|
||||||
|
channel_unread=${this.channel_unread}
|
||||||
|
depth=${this.depth + 1}
|
||||||
|
></tf-message>`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="w3-button w3-theme-d1 w3-block w3-bar"
|
||||||
|
style="box-sizing: border-box"
|
||||||
|
@click=${() => self.set_expanded(false)}
|
||||||
|
>
|
||||||
|
Collapse
|
||||||
|
</button>
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
return this.render_frame(html`
|
||||||
|
<div class="w3-padding">
|
||||||
|
${this.channel_group_by_author().map(
|
||||||
|
(x) => html`
|
||||||
|
<div>
|
||||||
|
<tf-user id=${x.author} .users=${this.users}></tf-user>
|
||||||
|
${x.action}
|
||||||
|
${x.channels.map(
|
||||||
|
(y) => html` <tf-tag tag=${'#' + y}></tf-tag> `
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="w3-button w3-theme-d1 w3-block w3-bar"
|
||||||
|
style="box-sizing: border-box"
|
||||||
|
@click=${() => self.set_expanded(true)}
|
||||||
|
>
|
||||||
|
Expand
|
||||||
|
</button>
|
||||||
|
`);
|
||||||
|
}
|
||||||
} else if (this.message.placeholder) {
|
} else if (this.message.placeholder) {
|
||||||
return this.render_frame(
|
return this.render_frame(
|
||||||
html`<div>
|
html`<div>
|
||||||
@@ -747,6 +884,7 @@ class TfMessageElement extends LitElement {
|
|||||||
.expanded=${this.expanded}
|
.expanded=${this.expanded}
|
||||||
channel=${this.channel}
|
channel=${this.channel}
|
||||||
channel_unread=${this.channel_unread}
|
channel_unread=${this.channel_unread}
|
||||||
|
depth=${this.depth + 1}
|
||||||
></tf-message>
|
></tf-message>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
@@ -785,60 +923,45 @@ class TfMessageElement extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
} else if (content.type == 'contact') {
|
} else if (content.type == 'contact') {
|
||||||
return this.render_frame(html`
|
switch (this.format) {
|
||||||
<div class="w3-bar">
|
case 'message':
|
||||||
<div class="w3-bar-item">
|
default:
|
||||||
<tf-user id=${this.message.author} .users=${this.users}></tf-user>
|
return this.render_frame(html`
|
||||||
is
|
<div class="w3-bar">
|
||||||
${content.blocking === true
|
<div class="w3-bar-item">
|
||||||
? 'blocking'
|
<tf-user
|
||||||
: content.blocking === false
|
id=${this.message.author}
|
||||||
? 'no longer blocking'
|
.users=${this.users}
|
||||||
: content.following === true
|
></tf-user>
|
||||||
? 'following'
|
is
|
||||||
: content.following === false
|
${content.blocking === true
|
||||||
? 'no longer following'
|
? 'blocking'
|
||||||
: '?'}
|
: content.blocking === false
|
||||||
<tf-user
|
? 'no longer blocking'
|
||||||
id=${this.message.content.contact}
|
: content.following === true
|
||||||
.users=${this.users}
|
? 'following'
|
||||||
></tf-user>
|
: content.following === false
|
||||||
</div>
|
? 'no longer following'
|
||||||
<div class="w3-bar-item w3-right">
|
: '?'}
|
||||||
<button class="w3-button w3-theme-d1" @click=${this.toggle_menu}>
|
<tf-user
|
||||||
%
|
id=${this.message.content.contact}
|
||||||
</button>
|
.users=${this.users}
|
||||||
<div
|
></tf-user>
|
||||||
class="w3-dropdown-content w3-bar-block w3-card-4 w3-theme-l1"
|
</div>
|
||||||
style="right: 48px"
|
${this.render_menu()} ${this.render_votes()}
|
||||||
>
|
${this.render_actions()}
|
||||||
<a
|
|
||||||
target="_top"
|
|
||||||
class="w3-button w3-bar-item"
|
|
||||||
href=${'#' + encodeURIComponent(this.message?.id)}
|
|
||||||
>View Message</a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-border-bottom"
|
|
||||||
@click=${this.copy_id}
|
|
||||||
>
|
|
||||||
Copy ID
|
|
||||||
</button>
|
|
||||||
${this.drafts[this.message?.id] === undefined
|
|
||||||
? html`
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item"
|
|
||||||
@click=${this.show_reply}
|
|
||||||
>
|
|
||||||
↩️ Reply
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: undefined}
|
|
||||||
</div>
|
</div>
|
||||||
|
`);
|
||||||
|
break;
|
||||||
|
case 'raw':
|
||||||
|
return this.render_frame(html`
|
||||||
|
${this.render_header()}
|
||||||
|
<div class="w3-container">${this.render_raw()}</div>
|
||||||
|
${this.render_votes()} ${this.render_actions()}
|
||||||
</div>
|
</div>
|
||||||
${this.render_votes()} ${this.render_actions()}
|
`);
|
||||||
</div>
|
break;
|
||||||
`);
|
}
|
||||||
} else if (content.type == 'post') {
|
} else if (content.type == 'post') {
|
||||||
let self = this;
|
let self = this;
|
||||||
let body;
|
let body;
|
||||||
@@ -865,7 +988,11 @@ class TfMessageElement extends LitElement {
|
|||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
@click=${(x) => this.toggle_expanded(':cw')}
|
@click=${(x) => this.toggle_expanded(':cw')}
|
||||||
>
|
>
|
||||||
<p>${content.contentWarning}</p>
|
<p>
|
||||||
|
${this.message.flags
|
||||||
|
? `Caution: This message has been flagged ${this.message.flags.length} time${this.message.flags.length == 1 ? '' : 's'}.`
|
||||||
|
: content.contentWarning}
|
||||||
|
</p>
|
||||||
<p class="w3-small">
|
<p class="w3-small">
|
||||||
${this.is_expanded(':cw') ? 'Show less' : 'Show more'}
|
${this.is_expanded(':cw') ? 'Show less' : 'Show more'}
|
||||||
</p>
|
</p>
|
||||||
@@ -876,11 +1003,12 @@ class TfMessageElement extends LitElement {
|
|||||||
<div @click=${this.body_click}>${body}</div>
|
<div @click=${this.body_click}>${body}</div>
|
||||||
${this.render_mentions()}
|
${this.render_mentions()}
|
||||||
`;
|
`;
|
||||||
let payload = content.contentWarning
|
let payload =
|
||||||
? self.expanded[(this.message.id || '') + ':cw']
|
this.message.flags || content.contentWarning
|
||||||
? html` ${content_warning} ${content_html} `
|
? self.expanded[(this.message.id || '') + ':cw']
|
||||||
: content_warning
|
? html` ${content_warning} ${content_html} `
|
||||||
: content_html;
|
: content_warning
|
||||||
|
: content_html;
|
||||||
return this.render_frame(html`
|
return this.render_frame(html`
|
||||||
${this.render_header()}
|
${this.render_header()}
|
||||||
<div class="w3-container">${payload}</div>
|
<div class="w3-container">${payload}</div>
|
||||||
@@ -997,6 +1125,15 @@ class TfMessageElement extends LitElement {
|
|||||||
return this.render_small_frame(this.render_raw());
|
return this.render_small_frame(this.render_raw());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
|
${this._render()}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('tf-message', TfMessageElement);
|
customElements.define('tf-message', TfMessageElement);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfNewsElement extends LitElement {
|
class TfNewsElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -66,6 +66,16 @@ class TfNewsElement extends LitElement {
|
|||||||
}
|
}
|
||||||
parent.votes.push(message);
|
parent.votes.push(message);
|
||||||
message.parent_message = message.content.vote.link;
|
message.parent_message = message.content.vote.link;
|
||||||
|
} else if (message.content.type == 'flag') {
|
||||||
|
let parent = ensure_message(message.content.flag.link, message.rowid);
|
||||||
|
if (!parent.flags) {
|
||||||
|
parent.flags = [];
|
||||||
|
}
|
||||||
|
parent.flags.push(message);
|
||||||
|
parent.flags = Object.values(
|
||||||
|
Object.fromEntries(parent.flags.map((x) => [x.id, x]))
|
||||||
|
);
|
||||||
|
message.parent_message = message.content.flag.link;
|
||||||
} else if (message.content.type == 'post') {
|
} else if (message.content.type == 'post') {
|
||||||
if (message.content.root) {
|
if (message.content.root) {
|
||||||
if (typeof message.content.root === 'string') {
|
if (typeof message.content.root === 'string') {
|
||||||
@@ -106,6 +116,7 @@ class TfNewsElement extends LitElement {
|
|||||||
message.parent_message = placeholder.parent_message;
|
message.parent_message = placeholder.parent_message;
|
||||||
message.child_messages = placeholder.child_messages;
|
message.child_messages = placeholder.child_messages;
|
||||||
message.votes = placeholder.votes;
|
message.votes = placeholder.votes;
|
||||||
|
message.flags = placeholder.flags;
|
||||||
if (
|
if (
|
||||||
placeholder.parent_message &&
|
placeholder.parent_message &&
|
||||||
messages_by_id[placeholder.parent_message]
|
messages_by_id[placeholder.parent_message]
|
||||||
@@ -160,11 +171,29 @@ class TfNewsElement extends LitElement {
|
|||||||
return recursive_sort(roots, true);
|
return recursive_sort(roots, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
group_following(messages) {
|
group_messages(messages) {
|
||||||
let result = [];
|
let result = [];
|
||||||
let group = [];
|
let group = [];
|
||||||
|
let type = undefined;
|
||||||
for (let message of messages) {
|
for (let message of messages) {
|
||||||
if (message?.content?.type === 'contact') {
|
if (
|
||||||
|
message?.content?.type === 'contact' ||
|
||||||
|
message?.content?.type === 'channel'
|
||||||
|
) {
|
||||||
|
if (type && message.content.type !== type) {
|
||||||
|
if (group.length == 1) {
|
||||||
|
result.push(group[0]);
|
||||||
|
group = [];
|
||||||
|
} else if (group.length > 1) {
|
||||||
|
result.push({
|
||||||
|
rowid: Math.max(...group.map((x) => x.rowid)),
|
||||||
|
type: `${type}_group`,
|
||||||
|
messages: group,
|
||||||
|
});
|
||||||
|
group = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type = message.content.type;
|
||||||
group.push(message);
|
group.push(message);
|
||||||
} else {
|
} else {
|
||||||
if (group.length == 1) {
|
if (group.length == 1) {
|
||||||
@@ -173,12 +202,13 @@ class TfNewsElement extends LitElement {
|
|||||||
} else if (group.length > 1) {
|
} else if (group.length > 1) {
|
||||||
result.push({
|
result.push({
|
||||||
rowid: Math.max(...group.map((x) => x.rowid)),
|
rowid: Math.max(...group.map((x) => x.rowid)),
|
||||||
type: 'contact_group',
|
type: `${type}_group`,
|
||||||
messages: group,
|
messages: group,
|
||||||
});
|
});
|
||||||
group = [];
|
group = [];
|
||||||
}
|
}
|
||||||
result.push(message);
|
result.push(message);
|
||||||
|
type = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (group.length == 1) {
|
if (group.length == 1) {
|
||||||
@@ -187,7 +217,7 @@ class TfNewsElement extends LitElement {
|
|||||||
} else if (group.length > 1) {
|
} else if (group.length > 1) {
|
||||||
result.push({
|
result.push({
|
||||||
rowid: Math.max(...group.map((x) => x.rowid)),
|
rowid: Math.max(...group.map((x) => x.rowid)),
|
||||||
type: 'contact_group',
|
type: `${type}_group`,
|
||||||
messages: group,
|
messages: group,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -200,7 +230,7 @@ class TfNewsElement extends LitElement {
|
|||||||
|
|
||||||
load_and_render(messages) {
|
load_and_render(messages) {
|
||||||
let messages_by_id = this.process_messages(messages);
|
let messages_by_id = this.process_messages(messages);
|
||||||
let final_messages = this.group_following(
|
let final_messages = this.group_messages(
|
||||||
this.finalize_messages(messages_by_id)
|
this.finalize_messages(messages_by_id)
|
||||||
);
|
);
|
||||||
let unread_rowid = -1;
|
let unread_rowid = -1;
|
||||||
@@ -212,6 +242,9 @@ class TfNewsElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
<div>
|
<div>
|
||||||
${repeat(
|
${repeat(
|
||||||
final_messages,
|
final_messages,
|
||||||
@@ -233,7 +266,19 @@ class TfNewsElement extends LitElement {
|
|||||||
<div
|
<div
|
||||||
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
||||||
></div>
|
></div>
|
||||||
<div style="color: #f00; padding: 8px">unread</div>
|
<button
|
||||||
|
style="color: #f00; padding: 8px"
|
||||||
|
class="w3-button"
|
||||||
|
@click=${() =>
|
||||||
|
this.dispatchEvent(
|
||||||
|
new Event('mark_all_read', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
unread
|
||||||
|
</button>
|
||||||
<div
|
<div
|
||||||
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px"
|
||||||
></div>
|
></div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {LitElement, html, until, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, until, unsafeHTML} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import * as tfutils from './tf-utils.js';
|
import * as tfutils from './tf-utils.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfProfileElement extends LitElement {
|
class TfProfileElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -14,6 +14,7 @@ class TfProfileElement extends LitElement {
|
|||||||
sequence: {type: Number},
|
sequence: {type: Number},
|
||||||
following: {type: Boolean},
|
following: {type: Boolean},
|
||||||
blocking: {type: Boolean},
|
blocking: {type: Boolean},
|
||||||
|
show_followed: {type: Boolean},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,16 +37,22 @@ class TfProfileElement extends LitElement {
|
|||||||
this.following = undefined;
|
this.following = undefined;
|
||||||
this.blocking = undefined;
|
this.blocking = undefined;
|
||||||
|
|
||||||
|
let latest = (
|
||||||
|
await tfrpc.rpc.query('SELECT MAX(rowid) AS latest FROM messages')
|
||||||
|
)[0].latest;
|
||||||
|
|
||||||
let result = await tfrpc.rpc.query(
|
let result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT json_extract(content, '$.following') AS following
|
SELECT json_extract(content, '$.following') AS following
|
||||||
FROM messages WHERE author = ? AND
|
FROM messages WHERE author = ? AND
|
||||||
json_extract(content, '$.type') = 'contact' AND
|
json_extract(content, '$.type') = 'contact' AND
|
||||||
json_extract(content, '$.contact') = ? AND
|
json_extract(content, '$.contact') = ? AND
|
||||||
following IS NOT NULL
|
following IS NOT NULL AND
|
||||||
|
messages.rowid <= ?
|
||||||
ORDER BY sequence DESC LIMIT 1
|
ORDER BY sequence DESC LIMIT 1
|
||||||
`,
|
`,
|
||||||
[this.whoami, this.id]
|
[this.whoami, this.id, latest],
|
||||||
|
{cacheable: true}
|
||||||
);
|
);
|
||||||
this.following = result?.[0]?.following ?? false;
|
this.following = result?.[0]?.following ?? false;
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
@@ -54,10 +61,12 @@ class TfProfileElement extends LitElement {
|
|||||||
FROM messages WHERE author = ? AND
|
FROM messages WHERE author = ? AND
|
||||||
json_extract(content, '$.type') = 'contact' AND
|
json_extract(content, '$.type') = 'contact' AND
|
||||||
json_extract(content, '$.contact') = ? AND
|
json_extract(content, '$.contact') = ? AND
|
||||||
blocking IS NOT NULL
|
blocking IS NOT NULL AND
|
||||||
|
messages.rowid <= ?
|
||||||
ORDER BY sequence DESC LIMIT 1
|
ORDER BY sequence DESC LIMIT 1
|
||||||
`,
|
`,
|
||||||
[this.whoami, this.id]
|
[this.whoami, this.id, latest],
|
||||||
|
{cacheable: true}
|
||||||
);
|
);
|
||||||
this.blocking = result?.[0]?.blocking ?? false;
|
this.blocking = result?.[0]?.blocking ?? false;
|
||||||
}
|
}
|
||||||
@@ -178,12 +187,12 @@ class TfProfileElement extends LitElement {
|
|||||||
div.style.display = 'grid';
|
div.style.display = 'grid';
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
img.src = link;
|
img.src = link;
|
||||||
img.style.maxWidth = '100%';
|
img.style.maxWidth = '100vw';
|
||||||
img.style.maxHeight = '100%';
|
img.style.maxHeight = '100vh';
|
||||||
img.style.display = 'block';
|
img.style.display = 'block';
|
||||||
img.style.margin = 'auto';
|
img.style.margin = 'auto';
|
||||||
img.style.objectFit = 'contain';
|
img.style.objectFit = 'contain';
|
||||||
img.style.width = '100%';
|
img.style.width = '100vw';
|
||||||
div.appendChild(img);
|
div.appendChild(img);
|
||||||
function image_close(event) {
|
function image_close(event) {
|
||||||
document.body.removeChild(div);
|
document.body.removeChild(div);
|
||||||
@@ -202,11 +211,7 @@ class TfProfileElement extends LitElement {
|
|||||||
|
|
||||||
toggle_account_list(event) {
|
toggle_account_list(event) {
|
||||||
let content = event.srcElement.nextElementSibling;
|
let content = event.srcElement.nextElementSibling;
|
||||||
if (content.classList.toggle('w3-hide')) {
|
this.show_followed = !this.show_followed;
|
||||||
event.srcElement.innerText = 'Show Followed Accounts';
|
|
||||||
} else {
|
|
||||||
event.srcElement.innerText = 'Hide Followed Accounts';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async load_follows() {
|
async load_follows() {
|
||||||
@@ -214,12 +219,13 @@ class TfProfileElement extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="w3-container">
|
<div class="w3-container">
|
||||||
<button
|
<button
|
||||||
class="w3-button w3-block w3-theme-d1"
|
class="w3-button w3-block w3-theme-d1 followed_accounts"
|
||||||
@click=${this.toggle_account_list}
|
@click=${this.toggle_account_list}
|
||||||
>
|
>
|
||||||
Show Followed Accounts
|
${this.show_followed ? 'Hide' : 'Show'} Followed Accounts
|
||||||
|
(${Object.keys(accounts).length})
|
||||||
</button>
|
</button>
|
||||||
<div class="w3-hide w3-card">
|
<div class=${'w3-card' + (this.show_followed ? '' : ' w3-hide')}>
|
||||||
<ul class="w3-ul w3-theme-d4 w3-border-theme">
|
<ul class="w3-ul w3-theme-d4 w3-border-theme">
|
||||||
${Object.keys(accounts).map(
|
${Object.keys(accounts).map(
|
||||||
(x) => html`
|
(x) => html`
|
||||||
@@ -240,7 +246,7 @@ class TfProfileElement extends LitElement {
|
|||||||
let profile = this.users[this.id] || {};
|
let profile = this.users[this.id] || {};
|
||||||
tfrpc.rpc
|
tfrpc.rpc
|
||||||
.query(
|
.query(
|
||||||
`SELECT SUM(LENGTH(content)) AS size, MAX(sequence) AS sequence FROM messages WHERE author = ?`,
|
`SELECT size AS size, max_sequence AS sequence FROM messages_stats WHERE author = ?`,
|
||||||
[this.id]
|
[this.id]
|
||||||
)
|
)
|
||||||
.then(function (result) {
|
.then(function (result) {
|
||||||
@@ -318,7 +324,9 @@ class TfProfileElement extends LitElement {
|
|||||||
}
|
}
|
||||||
image = this.editing?.image ?? image;
|
image = this.editing?.image ?? image;
|
||||||
let description = this.editing?.description ?? profile.description;
|
let description = this.editing?.description ?? profile.description;
|
||||||
return html`<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box">
|
return html`
|
||||||
|
<style>${generate_theme()}</style>
|
||||||
|
<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box">
|
||||||
<header class="w3-container">
|
<header class="w3-container">
|
||||||
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)} in ${this.sequence} messages)</p>
|
<p><tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)} in ${this.sequence} messages)</p>
|
||||||
</header>
|
</header>
|
||||||
@@ -329,7 +337,7 @@ class TfProfileElement extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<div style="display: flex; flex-direction: row; gap: 1em">
|
<div style="display: flex; flex-direction: row; gap: 1em">
|
||||||
${edit_profile}
|
${edit_profile}
|
||||||
<div style="flex: 1 0 50%">
|
<div style="flex: 1 0 50%; contain: layout; overflow: auto; word-wrap: normal; word-break: normal">
|
||||||
${
|
${
|
||||||
image
|
image
|
||||||
? html`<div><img src=${'/' + image + '/view'} style="width: 256px; height: auto"></img></div>`
|
? html`<div><img src=${'/' + image + '/view'} style="width: 256px; height: auto"></img></div>`
|
||||||
@@ -351,6 +359,9 @@ class TfProfileElement extends LitElement {
|
|||||||
${until(this.load_follows(), html`<p>Loading accounts followed...</p>`)}
|
${until(this.load_follows(), html`<p>Loading accounts followed...</p>`)}
|
||||||
<footer class="w3-container">
|
<footer class="w3-container">
|
||||||
<p>
|
<p>
|
||||||
|
<a class="w3-button w3-theme-d1" href=${'#🔐' + (this.id != this.whoami ? this.id : '')}>
|
||||||
|
Open Private Chat
|
||||||
|
</a>
|
||||||
${edit}
|
${edit}
|
||||||
${follow}
|
${follow}
|
||||||
${block}
|
${block}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfReactionsModalElement extends LitElement {
|
class TfReactionsModalElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -24,50 +24,57 @@ class TfReactionsModalElement extends LitElement {
|
|||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
return this.votes?.length
|
return this.votes?.length
|
||||||
? html` <div
|
? html` <style>
|
||||||
class="w3-modal w3-animate-opacity"
|
${generate_theme()}
|
||||||
style="display: block; box-sizing: border-box; z-index: 10"
|
</style>
|
||||||
@click=${this.clear}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="w3-modal-content w3-card-4 w3-theme-d1"
|
class="w3-modal w3-animate-opacity"
|
||||||
onclick="event.stopPropagation()"
|
style="display: block; box-sizing: border-box; z-index: 10"
|
||||||
|
@click=${this.clear}
|
||||||
>
|
>
|
||||||
<div class="w3-container w3-padding">
|
<div
|
||||||
<header class="w3-container">
|
class="w3-modal-content w3-card-4 w3-theme-d1"
|
||||||
<h2>Reactions</h2>
|
onclick="event.stopPropagation()"
|
||||||
<span class="w3-button w3-display-topright" @click=${this.clear}
|
>
|
||||||
>×</span
|
<div class="w3-container w3-padding">
|
||||||
>
|
<header class="w3-container">
|
||||||
</header>
|
<h2>Reactions</h2>
|
||||||
<ul class="w3-theme-dark w3-container w3-ul">
|
<span
|
||||||
${this.votes
|
class="w3-button w3-display-topright"
|
||||||
.sort((x, y) => y.timestamp - x.timestamp)
|
@click=${this.clear}
|
||||||
.map(
|
>×</span
|
||||||
(x) => html`
|
>
|
||||||
<li style="display: flex; flex-direction: row; gap: 4px">
|
</header>
|
||||||
<span style="flex-basis: 3em"
|
<ul class="w3-theme-dark w3-container w3-ul">
|
||||||
>${x?.content?.vote?.expression}</span
|
${this.votes
|
||||||
|
.sort((x, y) => y.timestamp - x.timestamp)
|
||||||
|
.map(
|
||||||
|
(x) => html`
|
||||||
|
<li
|
||||||
|
style="display: flex; flex-direction: row; gap: 4px"
|
||||||
>
|
>
|
||||||
<tf-user
|
<span style="flex-basis: 3em"
|
||||||
style="flex: 1 1"
|
>${x?.content?.vote?.expression}</span
|
||||||
id=${x.author}
|
>
|
||||||
.users=${this.users}
|
<tf-user
|
||||||
></tf-user>
|
style="flex: 1 1; overflow: hidden"
|
||||||
<span
|
id=${x.author}
|
||||||
style="flex-shrink: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
|
.users=${this.users}
|
||||||
>${new Date(x?.timestamp).toLocaleString()}</span
|
></tf-user>
|
||||||
>
|
<span
|
||||||
</li>
|
style="flex-shrink: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis"
|
||||||
`
|
>${new Date(x?.timestamp).toLocaleString()}</span
|
||||||
)}
|
>
|
||||||
</ul>
|
</li>
|
||||||
<footer class="w3-container w3-padding">
|
`
|
||||||
<button class="w3-button" @click=${this.clear}>Close</button>
|
)}
|
||||||
</footer>
|
</ul>
|
||||||
|
<footer class="w3-container w3-padding">
|
||||||
|
<button class="w3-button" @click=${this.clear}>Close</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>`
|
||||||
</div>`
|
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {css, unsafeCSS} from './lit-all.min.js';
|
import {css, unsafeCSS, until} from './lit-all.min.js';
|
||||||
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
|
|
||||||
const tf = css`
|
const tf = css`
|
||||||
img {
|
img {
|
||||||
@@ -43,6 +44,8 @@ const tf = css`
|
|||||||
border-left: 4px solid #fff;
|
border-left: 4px solid #fff;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -406,16 +409,8 @@ function is_dark(hex, value) {
|
|||||||
return (r * 299 + g * 587 + b * 114) / 1000 < value;
|
return (r * 299 + g * 587 + b * 114) / 1000 < value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generated() {
|
export function generate(color) {
|
||||||
let now = new Date();
|
let [r, g, b] = hex_to_rgb(color);
|
||||||
let k_color = rgb_to_hex([
|
|
||||||
(now.getDay() * 128) / 6,
|
|
||||||
(now.getHours() * 128) / 23,
|
|
||||||
(now.getSeconds() * 128) / 59,
|
|
||||||
]);
|
|
||||||
//let k_color = '#034f84';
|
|
||||||
//let k_color = rgb_to_hex([Math.random() * 256, Math.random() * 256, Math.random() * 256]);
|
|
||||||
let [r, g, b] = hex_to_rgb(k_color);
|
|
||||||
let [h, s, l] = rgb_to_hsl(r, g, b);
|
let [h, s, l] = rgb_to_hsl(r, g, b);
|
||||||
|
|
||||||
let theme1 = {
|
let theme1 = {
|
||||||
@@ -459,4 +454,28 @@ function generated() {
|
|||||||
return unsafeCSS(result);
|
return unsafeCSS(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
export let styles = [tf, w3, generated()];
|
let g_theme;
|
||||||
|
export function generate_theme() {
|
||||||
|
return g_theme
|
||||||
|
? g_theme
|
||||||
|
: until(
|
||||||
|
tfrpc.rpc.localStorageGet('color').then(function (value) {
|
||||||
|
g_theme = generate(value ?? '#034f84');
|
||||||
|
return g_theme;
|
||||||
|
}),
|
||||||
|
generated_now()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generated_now() {
|
||||||
|
let now = new Date();
|
||||||
|
return generate(
|
||||||
|
rgb_to_hex([
|
||||||
|
(now.getDay() * 128) / 6,
|
||||||
|
(now.getHours() * 128) / 23,
|
||||||
|
(now.getSeconds() * 128) / 59,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export let styles = [tf, w3];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
import {LitElement, html} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabConnectionsElement extends LitElement {
|
class TfTabConnectionsElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -15,6 +15,7 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
connect_attempt: {type: Object},
|
connect_attempt: {type: Object},
|
||||||
connect_message: {type: String},
|
connect_message: {type: String},
|
||||||
connect_success: {type: Boolean},
|
connect_success: {type: Boolean},
|
||||||
|
peer_exchange: {type: Boolean},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +48,20 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
tfrpc.rpc.getServerIdentity().then(function (identity) {
|
tfrpc.rpc.getServerIdentity().then(function (identity) {
|
||||||
self.server_identity = identity;
|
self.server_identity = identity;
|
||||||
});
|
});
|
||||||
|
this.check_peer_exchange();
|
||||||
|
}
|
||||||
|
|
||||||
|
async check_peer_exchange() {
|
||||||
|
if (await tfrpc.rpc.isAdministrator()) {
|
||||||
|
this.peer_exchange = await tfrpc.rpc.globalSettingsGet('peer_exchange');
|
||||||
|
} else {
|
||||||
|
this.peer_exchange = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async enable_peer_exchange() {
|
||||||
|
await tfrpc.rpc.globalSettingsSet('peer_exchange', true);
|
||||||
|
await this.check_peer_exchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
render_connection_summary(connection) {
|
render_connection_summary(connection) {
|
||||||
@@ -251,7 +266,26 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
return html`
|
return html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
<div class="w3-container" style="box-sizing: border-box">
|
<div class="w3-container" style="box-sizing: border-box">
|
||||||
|
<div
|
||||||
|
class=${'w3-panel w3-padding w3-theme-l3' +
|
||||||
|
(this.peer_exchange !== false ? ' w3-hide' : '')}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Looking for connections? Enabling this option will include publicly
|
||||||
|
advertised rooms and pubs among the list of discovered connections
|
||||||
|
to help you replicate.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
class="w3-button w3-theme-d1"
|
||||||
|
@click=${this.enable_peer_exchange}
|
||||||
|
>
|
||||||
|
🔍🌐 Use publicly advertised peers
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<h2>New Connection</h2>
|
<h2>New Connection</h2>
|
||||||
<textarea class="w3-input w3-theme-d1" id="code"></textarea>
|
<textarea class="w3-input w3-theme-d1" id="code"></textarea>
|
||||||
${this.render_message(this.renderRoot.getElementById('code')?.value)}
|
${this.render_message(this.renderRoot.getElementById('code')?.value)}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, cache, html, unsafeHTML, until} from './lit-all.min.js';
|
import {LitElement, cache, html, unsafeHTML, until} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabNewsFeedElement extends LitElement {
|
class TfTabNewsFeedElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -18,6 +18,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
time_range: {type: Array},
|
time_range: {type: Array},
|
||||||
time_loading: {type: Array},
|
time_loading: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
grouped_private_messages: {type: Object},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -83,7 +84,6 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
`,
|
`,
|
||||||
[JSON.stringify(combined.map((x) => x.id))]
|
[JSON.stringify(combined.map((x) => x.id))]
|
||||||
);
|
);
|
||||||
let t0 = new Date();
|
|
||||||
let result = [].concat(
|
let result = [].concat(
|
||||||
combined,
|
combined,
|
||||||
await tfrpc.rpc.query(
|
await tfrpc.rpc.query(
|
||||||
@@ -100,14 +100,20 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let t1 = new Date();
|
console.log(result);
|
||||||
console.log((t1 - t0) / 1000);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch_messages(start_time, end_time) {
|
async fetch_messages(start_time, end_time) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('loadmessages', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
this.time_loading = [start_time, end_time];
|
this.time_loading = [start_time, end_time];
|
||||||
let result;
|
let result;
|
||||||
|
const k_max_results = 64;
|
||||||
if (this.hash == '#@') {
|
if (this.hash == '#@') {
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
@@ -118,7 +124,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
WHERE
|
WHERE
|
||||||
messages.author != ?1 AND
|
messages.author != ?1 AND
|
||||||
(?3 IS NULL OR messages.timestamp >= ?3) AND messages.timestamp < ?4
|
(?3 IS NULL OR messages.timestamp >= ?3) AND messages.timestamp < ?4
|
||||||
ORDER BY timestamp DESC limit 20)
|
ORDER BY timestamp DESC limit ?5)
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM mentions
|
FROM mentions
|
||||||
JOIN messages_refs ON mentions.id = messages_refs.ref
|
JOIN messages_refs ON mentions.id = messages_refs.ref
|
||||||
@@ -131,6 +137,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
JSON.stringify(this.following),
|
JSON.stringify(this.following),
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
|
k_max_results,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else if (this.hash.startsWith('#@')) {
|
} else if (this.hash.startsWith('#@')) {
|
||||||
@@ -140,7 +147,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
selected AS (SELECT rowid, id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
selected AS (SELECT rowid, id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
||||||
FROM messages
|
FROM messages
|
||||||
WHERE messages.author = ?1 AND (?2 IS NULL OR messages.timestamp >= 2) AND messages.timestamp < ?3
|
WHERE messages.author = ?1 AND (?2 IS NULL OR messages.timestamp >= 2) AND messages.timestamp < ?3
|
||||||
ORDER BY sequence DESC LIMIT 20
|
ORDER BY sequence DESC LIMIT ?4
|
||||||
)
|
)
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM selected
|
FROM selected
|
||||||
@@ -149,7 +156,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
UNION
|
UNION
|
||||||
SELECT TRUE AS is_primary, * FROM selected
|
SELECT TRUE AS is_primary, * FROM selected
|
||||||
`,
|
`,
|
||||||
[this.hash.substring(1), start_time, end_time]
|
[this.hash.substring(1), start_time, end_time, k_max_results]
|
||||||
);
|
);
|
||||||
} else if (this.hash.startsWith('#%')) {
|
} else if (this.hash.startsWith('#%')) {
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
@@ -166,7 +173,6 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
[this.hash.substring(1)]
|
[this.hash.substring(1)]
|
||||||
);
|
);
|
||||||
} else if (this.hash.startsWith('##')) {
|
} else if (this.hash.startsWith('##')) {
|
||||||
let t0 = new Date();
|
|
||||||
let initial_messages = await tfrpc.rpc.query(
|
let initial_messages = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
WITH
|
WITH
|
||||||
@@ -174,32 +180,30 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM messages
|
FROM messages
|
||||||
JOIN json_each(?) AS following ON messages.author = following.value
|
JOIN json_each(?) AS following ON messages.author = following.value
|
||||||
WHERE messages.content ->> 'channel' = ?4
|
WHERE messages.content ->> 'channel' = ?4 AND messages.content ->> 'type' != 'vote'
|
||||||
UNION
|
UNION
|
||||||
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM messages_refs
|
FROM messages_refs
|
||||||
JOIN messages ON messages.id = messages_refs.message
|
JOIN messages ON messages.id = messages_refs.message
|
||||||
JOIN json_each(?1) AS following ON messages.author = following.value
|
JOIN json_each(?1) AS following ON messages.author = following.value
|
||||||
WHERE messages_refs.ref = '#' || ?4
|
WHERE messages_refs.ref = '#' || ?4 AND messages.content ->> 'type' != 'vote'
|
||||||
)
|
)
|
||||||
SELECT TRUE AS is_primary, all_news.* FROM all_news
|
SELECT TRUE AS is_primary, all_news.* FROM all_news
|
||||||
WHERE (?2 IS NULL OR all_news.timestamp >= ?2) AND all_news.timestamp < ?3
|
WHERE (?2 IS NULL OR all_news.timestamp >= ?2) AND all_news.timestamp < ?3
|
||||||
ORDER BY all_news.timestamp DESC LIMIT 20
|
ORDER BY all_news.timestamp DESC LIMIT ?5
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
JSON.stringify(this.following),
|
JSON.stringify(this.following),
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
this.hash.substring(2),
|
this.hash.substring(2),
|
||||||
|
k_max_results,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
let t1 = new Date();
|
|
||||||
result = await this._fetch_related_messages(initial_messages);
|
result = await this._fetch_related_messages(initial_messages);
|
||||||
let t2 = new Date();
|
} else if (this.hash.startsWith('#🔐')) {
|
||||||
console.log(
|
let ids =
|
||||||
`load of ${result.length} rows took ${(t2 - t0) / 1000} (${(t1 - t0) / 1000} to find ${initial_messages.length} initial messages, ${(t2 - t1) / 1000} to find ${result.length} total messages) following=${this.following.length} st=${start_time} et=${end_time}`
|
this.hash == '#🔐' ? [] : this.hash.substring('#🔐'.length).split(',');
|
||||||
);
|
|
||||||
} else if (this.hash == '#🔐') {
|
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
||||||
@@ -208,11 +212,21 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
WHERE
|
WHERE
|
||||||
(?2 IS NULL OR (messages.timestamp >= ?2)) AND messages.timestamp < ?3 AND
|
(?2 IS NULL OR (messages.timestamp >= ?2)) AND messages.timestamp < ?3 AND
|
||||||
json(messages.content) LIKE '"%'
|
json(messages.content) LIKE '"%'
|
||||||
ORDER BY messages.rowid DESC LIMIT 20
|
ORDER BY messages.rowid DESC LIMIT ?4
|
||||||
`,
|
`,
|
||||||
[JSON.stringify(this.private_messages), start_time, end_time]
|
[
|
||||||
|
JSON.stringify(
|
||||||
|
this.grouped_private_messages?.[JSON.stringify(ids)]?.map(
|
||||||
|
(x) => x.id
|
||||||
|
) ?? []
|
||||||
|
),
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
k_max_results,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
result = (await this.decrypt(result)).filter((x) => x.decrypted);
|
let decrypted = (await this.decrypt(result)).filter((x) => x.decrypted);
|
||||||
|
result = await this._fetch_related_messages(decrypted);
|
||||||
} else if (this.hash == '#👍') {
|
} else if (this.hash == '#👍') {
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
@@ -222,40 +236,59 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
WHERE
|
WHERE
|
||||||
messages.content ->> 'type' = 'vote' AND
|
messages.content ->> 'type' = 'vote' AND
|
||||||
(?2 IS NULL OR messages.timestamp >= ?2) AND messages.timestamp < ?3
|
(?2 IS NULL OR messages.timestamp >= ?2) AND messages.timestamp < ?3
|
||||||
ORDER BY timestamp DESC limit 20)
|
ORDER BY timestamp DESC limit ?4)
|
||||||
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM votes
|
FROM votes
|
||||||
JOIN messages ON messages.id = votes.content ->> '$.vote.link'
|
JOIN messages ON messages.id = votes.content ->> '$.vote.link'
|
||||||
UNION
|
UNION
|
||||||
SELECT TRUE AS is_primary, * FROM votes
|
SELECT TRUE AS is_primary, * FROM votes
|
||||||
`,
|
`,
|
||||||
[JSON.stringify(this.following), start_time, end_time]
|
[JSON.stringify(this.following), start_time, end_time, k_max_results]
|
||||||
|
);
|
||||||
|
} else if (this.hash == '#🚩') {
|
||||||
|
result = await tfrpc.rpc.query(
|
||||||
|
`
|
||||||
|
WITH flags AS (SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
|
FROM messages
|
||||||
|
WHERE
|
||||||
|
messages.content ->> 'type' = 'flag' AND
|
||||||
|
(?1 IS NULL OR messages.timestamp >= ?1) AND messages.timestamp < ?2
|
||||||
|
ORDER BY timestamp DESC limit ?3)
|
||||||
|
SELECT FALSE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
|
FROM flags
|
||||||
|
JOIN messages ON messages.id = flags.content ->> '$.flag.link'
|
||||||
|
UNION
|
||||||
|
SELECT TRUE AS is_primary, * FROM flags
|
||||||
|
`,
|
||||||
|
[start_time, end_time, k_max_results]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let t0 = new Date();
|
|
||||||
let initial_messages = await tfrpc.rpc.query(
|
let initial_messages = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
WITH
|
WITH
|
||||||
all_news AS (
|
channels AS (SELECT '#' || value AS value FROM json_each(?5))
|
||||||
SELECT messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
SELECT TRUE AS is_primary, messages.rowid, messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
FROM messages
|
FROM messages
|
||||||
JOIN json_each(?) AS following ON messages.author = following.value
|
JOIN json_each(?1) AS following ON messages.author = following.value
|
||||||
),
|
WHERE messages.timestamp < ?3 AND (?2 IS NULL OR messages.timestamp >= ?2) AND
|
||||||
news AS (
|
messages.content ->> 'type' != 'vote' AND
|
||||||
SELECT * FROM all_news
|
(messages.content ->> 'root' IS NULL OR (
|
||||||
WHERE all_news.timestamp < ?3 AND (?2 IS NULL OR all_news.timestamp >= ?2)
|
NOT EXISTS (SELECT * FROM messages root JOIN channels ON ('#' || (root.content ->> 'channel')) = channels.value WHERE root.id = messages.content ->> 'root') AND
|
||||||
ORDER BY timestamp DESC LIMIT 20
|
NOT EXISTS (SELECT * FROM messages root JOIN messages_refs ON root.id = messages.content ->> 'root' JOIN channels ON messages_refs.message = root.id AND messages_refs.ref = channels.value)
|
||||||
)
|
)) AND
|
||||||
SELECT TRUE AS is_primary, news.* FROM news
|
(messages.content ->> 'channel' IS NULL OR ('#' || (messages.content ->> 'channel')) NOT IN (SELECT * FROM channels)) AND
|
||||||
|
NOT EXISTS (SELECT * FROM messages_refs JOIN channels ON messages_refs.message = messages.id AND messages_refs.ref = channels.value)
|
||||||
|
ORDER BY timestamp DESC LIMIT ?4
|
||||||
`,
|
`,
|
||||||
[JSON.stringify(this.following), start_time, end_time]
|
[
|
||||||
|
JSON.stringify(this.following),
|
||||||
|
start_time,
|
||||||
|
end_time,
|
||||||
|
k_max_results,
|
||||||
|
JSON.stringify(Object.keys(this.channels_latest)),
|
||||||
|
]
|
||||||
);
|
);
|
||||||
let t1 = new Date();
|
|
||||||
result = await this._fetch_related_messages(initial_messages);
|
result = await this._fetch_related_messages(initial_messages);
|
||||||
let t2 = new Date();
|
|
||||||
console.log(
|
|
||||||
`load of ${result.length} rows took ${(t2 - t0) / 1000} (${(t1 - t0) / 1000} to find ${initial_messages.length} initial messages, ${(t2 - t1) / 1000} to find ${result.length} total messages) following=${this.following.length} st=${start_time} et=${end_time}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
return result;
|
return result;
|
||||||
@@ -371,12 +404,20 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
let self = this;
|
let self = this;
|
||||||
this.loading++;
|
this.loading++;
|
||||||
let messages = [];
|
let messages = [];
|
||||||
|
let original_hash = this.hash;
|
||||||
try {
|
try {
|
||||||
if (this._messages_hash !== this.hash) {
|
if (this._messages_hash !== this.hash) {
|
||||||
this.messages = [];
|
this.messages = [];
|
||||||
this._messages_hash = this.hash;
|
this._messages_hash = this.hash;
|
||||||
}
|
}
|
||||||
this._messages_following = this.following;
|
this._messages_following = JSON.stringify(this.following);
|
||||||
|
this._private_messages = JSON.stringify([
|
||||||
|
this.private_messages,
|
||||||
|
this.grouped_private_messages,
|
||||||
|
]);
|
||||||
|
this._channels_latest = JSON.stringify(
|
||||||
|
Object.keys(this.channels_latest ?? {})
|
||||||
|
);
|
||||||
let now = new Date().valueOf();
|
let now = new Date().valueOf();
|
||||||
let start_time = now - 24 * 60 * 60 * 1000;
|
let start_time = now - 24 * 60 * 60 * 1000;
|
||||||
this.start_time = start_time;
|
this.start_time = start_time;
|
||||||
@@ -389,7 +430,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
} finally {
|
} finally {
|
||||||
this.loading--;
|
this.loading--;
|
||||||
}
|
}
|
||||||
this.messages = this.merge_messages(this.messages, messages);
|
if (this.hash == original_hash) {
|
||||||
|
this.messages = this.merge_messages(this.messages, messages);
|
||||||
|
}
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
console.log(
|
console.log(
|
||||||
`loading ${messages.length} messages done for ${self.whoami} in ${(new Date() - start_time) / 1000}s`
|
`loading ${messages.length} messages done for ${self.whoami} in ${(new Date() - start_time) / 1000}s`
|
||||||
@@ -415,15 +458,49 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close_private_chat() {
|
||||||
|
this.mark_all_read();
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('closeprivatechat', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: {
|
||||||
|
key: JSON.stringify(
|
||||||
|
this.hash == '#🔐'
|
||||||
|
? []
|
||||||
|
: this.hash.substring('#🔐'.length).split(',')
|
||||||
|
),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
tfrpc.rpc.setHash('#');
|
||||||
|
}
|
||||||
|
|
||||||
|
render_close_chat_button() {
|
||||||
|
if (this.hash.startsWith('#🔐')) {
|
||||||
|
return html`
|
||||||
|
<button class="w3-button w3-theme-d1" @click=${this.close_private_chat}>
|
||||||
|
Close Chat
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (
|
if (
|
||||||
!this.messages ||
|
!this.messages ||
|
||||||
this._messages_hash !== this.hash ||
|
this._messages_hash !== this.hash ||
|
||||||
JSON.stringify(this._messages_following) !==
|
this._messages_following !== JSON.stringify(this.following) ||
|
||||||
JSON.stringify(this.following)
|
this._private_messages !==
|
||||||
|
JSON.stringify([
|
||||||
|
this.private_messages,
|
||||||
|
this.grouped_private_messages,
|
||||||
|
]) ||
|
||||||
|
this._channels_latest !==
|
||||||
|
JSON.stringify(Object.keys(this.channels_latest))
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
`loading messages for ${this.whoami} (following ${this.following.length})`
|
`loading messages for ${this.whoami} (messages=${!this.messages},${this._messages_hash != this.hash} following=${this._messages_following !== JSON.stringify(this.following)}, channels=${this._channels_latest !== JSON.stringify(Object.keys(this.channels_latest))}, private=${this._private_messages !== JSON.stringify([this.private_messages, this.grouped_private_messages])},${this.private_messages?.length},${Object.keys(this.grouped_private_messages ?? {}).length})`
|
||||||
);
|
);
|
||||||
this.load_messages();
|
this.load_messages();
|
||||||
}
|
}
|
||||||
@@ -472,6 +549,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return cache(html`
|
return cache(html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
${this.unread_allowed()
|
${this.unread_allowed()
|
||||||
? html`<button
|
? html`<button
|
||||||
class="w3-button w3-theme-d1"
|
class="w3-button w3-theme-d1"
|
||||||
@@ -480,6 +560,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
Mark All Read
|
Mark All Read
|
||||||
</button>`
|
</button>`
|
||||||
: undefined}
|
: undefined}
|
||||||
|
${this.render_close_chat_button()}
|
||||||
<tf-news
|
<tf-news
|
||||||
id="news"
|
id="news"
|
||||||
whoami=${this.whoami}
|
whoami=${this.whoami}
|
||||||
@@ -492,6 +573,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
channel=${this.channel()}
|
channel=${this.channel()}
|
||||||
channel_unread=${this.channels_unread?.[this.channel()]}
|
channel_unread=${this.channels_unread?.[this.channel()]}
|
||||||
.recent_reactions=${this.recent_reactions}
|
.recent_reactions=${this.recent_reactions}
|
||||||
|
@mark_all_read=${this.mark_all_read}
|
||||||
></tf-news>
|
></tf-news>
|
||||||
${more}
|
${more}
|
||||||
`);
|
`);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
until,
|
until,
|
||||||
} from './lit-all.min.js';
|
} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabNewsElement extends LitElement {
|
class TfTabNewsElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -24,8 +24,12 @@ class TfTabNewsElement extends LitElement {
|
|||||||
channels_latest: {type: Object},
|
channels_latest: {type: Object},
|
||||||
connections: {type: Array},
|
connections: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
grouped_private_messages: {type: Object},
|
||||||
|
visible_private_messages: {type: Object},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
peer_exchange: {type: Boolean},
|
peer_exchange: {type: Boolean},
|
||||||
|
is_administrator: {type: Boolean},
|
||||||
|
stay_connected: {type: Boolean},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +117,19 @@ class TfTabNewsElement extends LitElement {
|
|||||||
) {
|
) {
|
||||||
return '✉️ ';
|
return '✉️ ';
|
||||||
}
|
}
|
||||||
|
} else if (channel?.startsWith('🔐')) {
|
||||||
|
let key = JSON.stringify(channel.substring('🔐'.length).split(','));
|
||||||
|
if (this.grouped_private_messages?.[key]) {
|
||||||
|
let grouped_latest = Math.max(
|
||||||
|
...this.grouped_private_messages?.[key]?.map((x) => x.rowid)
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
this.channels_unread[channel] === undefined ||
|
||||||
|
grouped_latest > this.channels_unread[channel]
|
||||||
|
) {
|
||||||
|
return '✉️ ';
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
this.channels_latest[channel] &&
|
this.channels_latest[channel] &&
|
||||||
this.channels_latest[channel] > 0 &&
|
this.channels_latest[channel] > 0 &&
|
||||||
@@ -154,11 +171,8 @@ class TfTabNewsElement extends LitElement {
|
|||||||
return this.hash.startsWith('##') ? this.hash.substring(2) : undefined;
|
return this.hash.startsWith('##') ? this.hash.substring(2) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
compare_follows() {
|
compare_follows(a, b) {
|
||||||
const now = new Date().valueOf();
|
return b[1].ts > a[1].ts ? 1 : b[1].ts < a[1].ts ? -1 : 0;
|
||||||
return function (a, b) {
|
|
||||||
return (b[1].ts > now ? -1 : b[1].ts) - (a[1].ts > now ? -1 : a[1].ts);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suggested_follows() {
|
suggested_follows() {
|
||||||
@@ -167,22 +181,24 @@ class TfTabNewsElement extends LitElement {
|
|||||||
** pinned at the top.
|
** pinned at the top.
|
||||||
*/
|
*/
|
||||||
let self = this;
|
let self = this;
|
||||||
|
let now = new Date().valueOf();
|
||||||
return Object.entries(this.users)
|
return Object.entries(this.users)
|
||||||
|
.filter((x) => x[1].ts < now)
|
||||||
.filter((x) => x[1].follow_depth > 1)
|
.filter((x) => x[1].follow_depth > 1)
|
||||||
.sort(self.compare_follows())
|
.sort(self.compare_follows)
|
||||||
.slice(0, 8)
|
.slice(0, 8)
|
||||||
.map((x) => x[0]);
|
.map((x) => x[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh() {
|
|
||||||
tfrpc.rpc.sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
async enable_peer_exchange() {
|
async enable_peer_exchange() {
|
||||||
await tfrpc.rpc.globalSettingsSet('peer_exchange', true);
|
await tfrpc.rpc.globalSettingsSet('peer_exchange', true);
|
||||||
await this.check_peer_exchange();
|
await this.check_peer_exchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_loading() {
|
||||||
|
return this.shadowRoot?.getElementById('news')?.loading;
|
||||||
|
}
|
||||||
|
|
||||||
render_sidebar() {
|
render_sidebar() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
@@ -204,7 +220,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
href="#"
|
href="#"
|
||||||
class="w3-bar-item w3-button"
|
class="w3-bar-item w3-button"
|
||||||
style="font-weight: bold"
|
style="font-weight: bold"
|
||||||
>${this.hash.substring(2)}</a
|
>${this.hash.substring(1)}</a
|
||||||
>
|
>
|
||||||
`
|
`
|
||||||
: undefined}
|
: undefined}
|
||||||
@@ -228,11 +244,34 @@ class TfTabNewsElement extends LitElement {
|
|||||||
>${this.unread_status('👍')}👍votes</a
|
>${this.unread_status('👍')}👍votes</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="#🔐"
|
href="#🚩"
|
||||||
class="w3-bar-item w3-button"
|
class="w3-bar-item w3-button"
|
||||||
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined}
|
style=${this.hash == '#🚩' ? 'font-weight: bold' : undefined}
|
||||||
>${this.unread_status('🔐')}🔐private</a
|
>${this.unread_status('🚩')}🚩flagged</a
|
||||||
>
|
>
|
||||||
|
${Object.keys(this?.visible_private_messages ?? [])
|
||||||
|
?.sort()
|
||||||
|
?.map(
|
||||||
|
(key) => html`
|
||||||
|
<a
|
||||||
|
href=${'#🔐' + JSON.parse(key).join(',')}
|
||||||
|
class="w3-bar-item w3-button"
|
||||||
|
style=${this.hash == '#🔐' + JSON.parse(key).join(',')
|
||||||
|
? 'font-weight: bold'
|
||||||
|
: undefined}
|
||||||
|
>${this.unread_status('🔐' + JSON.parse(key).join(','))}
|
||||||
|
${(key != '[]' ? JSON.parse(key) : [this.whoami]).map(
|
||||||
|
(id) => html`
|
||||||
|
<tf-user
|
||||||
|
id=${id}
|
||||||
|
nolink="true"
|
||||||
|
.users=${this.users}
|
||||||
|
></tf-user>
|
||||||
|
`
|
||||||
|
)}</a
|
||||||
|
>
|
||||||
|
`
|
||||||
|
)}
|
||||||
${Object.keys(this.drafts)
|
${Object.keys(this.drafts)
|
||||||
.sort()
|
.sort()
|
||||||
.map(
|
.map(
|
||||||
@@ -266,16 +305,34 @@ class TfTabNewsElement extends LitElement {
|
|||||||
(this.connections?.some((x) => x.flags.one_shot)
|
(this.connections?.some((x) => x.flags.one_shot)
|
||||||
? ' w3-spin'
|
? ' w3-spin'
|
||||||
: '')}
|
: '')}
|
||||||
@click=${this.refresh}
|
@click=${() =>
|
||||||
|
this.dispatchEvent(
|
||||||
|
new Event('refresh', {bubbles: true, composed: true})
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
↻ Sync now
|
↻ Sync now
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class=${'w3-bar-item w3-button' +
|
class="w3-bar-item w3-button w3-ripple"
|
||||||
|
@click=${() =>
|
||||||
|
this.dispatchEvent(
|
||||||
|
new Event('toggle_stay_connected', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span style="display: inline-block; width: 1.8em"
|
||||||
|
>${this.stay_connected ? '🔗' : '⛓️💥'}</span
|
||||||
|
>
|
||||||
|
${this.stay_connected ? 'Online mode' : 'Passive mode'}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class=${'w3-bar-item w3-button w3-border w3-leftbar w3-rightbar' +
|
||||||
(this.peer_exchange !== false ? ' w3-hide' : '')}
|
(this.peer_exchange !== false ? ' w3-hide' : '')}
|
||||||
@click=${this.enable_peer_exchange}
|
@click=${this.enable_peer_exchange}
|
||||||
>
|
>
|
||||||
Enable peer exchange
|
🔍🌐 Use publicly advertised peers
|
||||||
</button>
|
</button>
|
||||||
`
|
`
|
||||||
: undefined}
|
: undefined}
|
||||||
@@ -345,9 +402,12 @@ class TfTabNewsElement extends LitElement {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
return cache(html`
|
return cache(html`
|
||||||
|
<style>
|
||||||
|
${generate_theme()}
|
||||||
|
</style>
|
||||||
${this.render_sidebar()}
|
${this.render_sidebar()}
|
||||||
<div
|
<div
|
||||||
style="margin-left: 2in; padding: 0px; top: 0; max-height: 100%; overflow: auto; contain: layout"
|
style="margin-left: 2in; padding: 0px; top: 0; height: 100vh; max-height: 100%; overflow: auto; contain: layout"
|
||||||
id="main"
|
id="main"
|
||||||
class="w3-main"
|
class="w3-main"
|
||||||
>
|
>
|
||||||
@@ -374,7 +434,12 @@ class TfTabNewsElement extends LitElement {
|
|||||||
>
|
>
|
||||||
${this.unread_status()}☰
|
${this.unread_status()}☰
|
||||||
</div>
|
</div>
|
||||||
Welcome, <tf-user id=${this.whoami} .users=${this.users}></tf-user>!
|
<span
|
||||||
|
style="display: inline-block; width: 100%; max-width: 100%; white-space: nowrap; overflow: hidden"
|
||||||
|
>
|
||||||
|
Welcome,
|
||||||
|
<tf-user id=${this.whoami} .users=${this.users}></tf-user>!
|
||||||
|
</span>
|
||||||
${edit_profile}
|
${edit_profile}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -385,6 +450,9 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.drafts=${this.drafts}
|
.drafts=${this.drafts}
|
||||||
@tf-draft=${this.draft}
|
@tf-draft=${this.draft}
|
||||||
.channel=${this.channel()}
|
.channel=${this.channel()}
|
||||||
|
.recipients=${this.hash.startsWith('#🔐')
|
||||||
|
? this.hash.substring('#🔐'.length).split(',')
|
||||||
|
: undefined}
|
||||||
></tf-compose>
|
></tf-compose>
|
||||||
</div>
|
</div>
|
||||||
${profile}
|
${profile}
|
||||||
@@ -401,6 +469,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.channels_unread=${this.channels_unread}
|
.channels_unread=${this.channels_unread}
|
||||||
.channels_latest=${this.channels_latest}
|
.channels_latest=${this.channels_latest}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
|
.grouped_private_messages=${this.grouped_private_messages}
|
||||||
.recent_reactions=${this.recent_reactions}
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-tab-news-feed>
|
></tf-tab-news-feed>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,136 +0,0 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
|
||||||
import {styles} from './tf-styles.js';
|
|
||||||
|
|
||||||
class TfTabQueryElement extends LitElement {
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
whoami: {type: String},
|
|
||||||
users: {type: Object},
|
|
||||||
following: {type: Array},
|
|
||||||
query: {type: String},
|
|
||||||
expanded: {type: Object},
|
|
||||||
results: {type: Array},
|
|
||||||
error: {type: Object},
|
|
||||||
duration: {type: Number},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = styles;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
let self = this;
|
|
||||||
this.whoami = null;
|
|
||||||
this.users = {};
|
|
||||||
this.following = [];
|
|
||||||
this.expanded = {};
|
|
||||||
this.duration = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async search(query) {
|
|
||||||
console.log('Searching...', this.whoami, query);
|
|
||||||
this.results = [];
|
|
||||||
this.error = undefined;
|
|
||||||
this.duration = undefined;
|
|
||||||
let search = this.renderRoot.getElementById('search');
|
|
||||||
if (search) {
|
|
||||||
search.value = query;
|
|
||||||
search.focus();
|
|
||||||
}
|
|
||||||
await tfrpc.rpc.setHash('#sql=' + encodeURIComponent(query));
|
|
||||||
let start_time = new Date();
|
|
||||||
try {
|
|
||||||
this.results = await tfrpc.rpc.query(query, []);
|
|
||||||
} catch (error) {
|
|
||||||
this.error = error;
|
|
||||||
}
|
|
||||||
let end_time = new Date();
|
|
||||||
this.duration = (end_time - start_time).valueOf();
|
|
||||||
console.log('Done.');
|
|
||||||
search = this.renderRoot.getElementById('search');
|
|
||||||
if (search) {
|
|
||||||
search.value = query;
|
|
||||||
search.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
search_keydown(event) {
|
|
||||||
if (event.keyCode == 13 && event.ctrlKey) {
|
|
||||||
this.query = this.renderRoot.getElementById('search').value;
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
on_expand(event) {
|
|
||||||
if (event.detail.expanded) {
|
|
||||||
let expand = {};
|
|
||||||
expand[event.detail.id] = true;
|
|
||||||
this.expanded = Object.assign({}, this.expanded, expand);
|
|
||||||
} else {
|
|
||||||
delete this.expanded[event.detail.id];
|
|
||||||
this.expanded = Object.assign({}, this.expanded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_results() {
|
|
||||||
if (!this.results?.length) {
|
|
||||||
return html`<div>No results.</div>`;
|
|
||||||
} else {
|
|
||||||
let keys = Object.keys(this.results[0]).sort();
|
|
||||||
return html`<table style="width: 100%; max-width: 100%">
|
|
||||||
<tr>
|
|
||||||
${keys.map((key) => html`<th>${key}</th>`)}
|
|
||||||
</tr>
|
|
||||||
${this.results.map(
|
|
||||||
(row) =>
|
|
||||||
html`<tr>
|
|
||||||
${keys.map((key) => html`<td>${row[key]}</td>`)}
|
|
||||||
</tr>`
|
|
||||||
)}
|
|
||||||
</table>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_error() {
|
|
||||||
if (this.error) {
|
|
||||||
return html`<h2 style="color: red">${this.error.message}</h2>
|
|
||||||
<pre style="color: red">${this.error.stack}</pre>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.query !== this.last_query) {
|
|
||||||
this.last_query = this.query;
|
|
||||||
this.search(this.query);
|
|
||||||
}
|
|
||||||
let self = this;
|
|
||||||
return html`
|
|
||||||
<div style="display: flex; flex-direction: row; gap: 4px">
|
|
||||||
<textarea
|
|
||||||
id="search"
|
|
||||||
rows="8"
|
|
||||||
class="w3-input w3-theme-d1"
|
|
||||||
style="flex: 1; resize: vertical"
|
|
||||||
@keydown=${this.search_keydown}
|
|
||||||
>
|
|
||||||
${this.query}</textarea
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-theme-d1"
|
|
||||||
@click=${(event) =>
|
|
||||||
self.search(self.renderRoot.getElementById('search').value)}
|
|
||||||
>
|
|
||||||
Execute
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div ?hidden=${this.duration === undefined}>
|
|
||||||
Took ${this.duration / 1000.0} seconds.
|
|
||||||
</div>
|
|
||||||
<div ?hidden=${this.duration !== undefined}>Executing...</div>
|
|
||||||
${this.render_error()} ${this.render_results()}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define('tf-tab-query', TfTabQueryElement);
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTabSearchElement extends LitElement {
|
class TfTabSearchElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -11,6 +11,9 @@ class TfTabSearchElement extends LitElement {
|
|||||||
following: {type: Array},
|
following: {type: Array},
|
||||||
query: {type: String},
|
query: {type: String},
|
||||||
expanded: {type: Object},
|
expanded: {type: Object},
|
||||||
|
messages: {type: Array},
|
||||||
|
results: {type: Array},
|
||||||
|
error: {type: Object},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,24 +41,40 @@ class TfTabSearchElement extends LitElement {
|
|||||||
search.select();
|
search.select();
|
||||||
}
|
}
|
||||||
await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query));
|
await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query));
|
||||||
let results = await tfrpc.rpc.query(
|
this.error = undefined;
|
||||||
`
|
this.results = [];
|
||||||
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
this.messages = [];
|
||||||
FROM messages_fts(?)
|
if (query.startsWith('sql:')) {
|
||||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
this.messages = [];
|
||||||
JOIN json_each(?) AS following ON messages.author = following.value
|
try {
|
||||||
ORDER BY timestamp DESC limit 100
|
this.results = await tfrpc.rpc.query(
|
||||||
`,
|
query.substring('sql:'.length),
|
||||||
['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)]
|
[]
|
||||||
);
|
);
|
||||||
console.log('Done.');
|
} catch (e) {
|
||||||
search = this.renderRoot.getElementById('search');
|
this.results = [];
|
||||||
if (search) {
|
this.error = e;
|
||||||
search.value = query;
|
}
|
||||||
search.focus();
|
} else {
|
||||||
search.select();
|
let results = await tfrpc.rpc.query(
|
||||||
|
`
|
||||||
|
SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature
|
||||||
|
FROM messages_fts(?)
|
||||||
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||||
|
JOIN json_each(?) AS following ON messages.author = following.value
|
||||||
|
ORDER BY timestamp DESC limit 100
|
||||||
|
`,
|
||||||
|
['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)]
|
||||||
|
);
|
||||||
|
console.log('Done.');
|
||||||
|
search = this.renderRoot.getElementById('search');
|
||||||
|
if (search) {
|
||||||
|
search.value = query;
|
||||||
|
search.focus();
|
||||||
|
search.select();
|
||||||
|
}
|
||||||
|
this.messages = results;
|
||||||
}
|
}
|
||||||
this.renderRoot.getElementById('news').messages = results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
search_keydown(event) {
|
search_keydown(event) {
|
||||||
@@ -87,6 +106,39 @@ class TfTabSearchElement extends LitElement {
|
|||||||
tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts));
|
tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render_results() {
|
||||||
|
if (this.error) {
|
||||||
|
return html`<h2 style="color: red">${this.error.message}</h2>
|
||||||
|
<pre style="color: red">${this.error.stack}</pre>`;
|
||||||
|
} else if (this.messages?.length) {
|
||||||
|
return html`<tf-news
|
||||||
|
id="news"
|
||||||
|
whoami=${this.whoami}
|
||||||
|
.messages=${this.messages}
|
||||||
|
.users=${this.users}
|
||||||
|
.expanded=${this.expanded}
|
||||||
|
.drafts=${this.drafts}
|
||||||
|
@tf-expand=${this.on_expand}
|
||||||
|
@tf-draft=${this.draft}
|
||||||
|
></tf-news>`;
|
||||||
|
} else if (this.results?.length) {
|
||||||
|
let keys = Object.keys(this.results[0]).sort();
|
||||||
|
return html`<table style="width: 100%; max-width: 100%">
|
||||||
|
<tr>
|
||||||
|
${keys.map((key) => html`<th>${key}</th>`)}
|
||||||
|
</tr>
|
||||||
|
${this.results.map(
|
||||||
|
(row) =>
|
||||||
|
html`<tr>
|
||||||
|
${keys.map((key) => html`<td>${row[key]}</td>`)}
|
||||||
|
</tr>`
|
||||||
|
)}
|
||||||
|
</table>`;
|
||||||
|
} else {
|
||||||
|
return html`<div>No results.</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.query !== this.last_query) {
|
if (this.query !== this.last_query) {
|
||||||
this.last_query = this.query;
|
this.last_query = this.query;
|
||||||
@@ -94,11 +146,14 @@ class TfTabSearchElement extends LitElement {
|
|||||||
}
|
}
|
||||||
let self = this;
|
let self = this;
|
||||||
return html`
|
return html`
|
||||||
<div style="display: flex; flex-direction: row; gap: 4px">
|
<style>${generate_theme()}</style>
|
||||||
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
|
<div class="w3-padding">
|
||||||
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
|
<div style="display: flex; flex-direction: row; gap: 4px">
|
||||||
|
<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input>
|
||||||
|
<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button>
|
||||||
|
</div>
|
||||||
|
${this.render_results()}
|
||||||
</div>
|
</div>
|
||||||
<tf-news id="news" whoami=${this.whoami} .messages=${this.messages} .users=${this.users} .expanded=${this.expanded} .drafts=${this.drafts} @tf-expand=${this.on_expand} @tf-draft=${this.draft}></tf-news>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
import {LitElement, html, unsafeHTML} from './lit-all.min.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfTagElement extends LitElement {
|
class TfTagElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -17,11 +17,15 @@ class TfTagElement extends LitElement {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
let number = this.count ? html` (${this.count})` : undefined;
|
let number = this.count ? html` (${this.count})` : undefined;
|
||||||
return html`<a
|
return html`
|
||||||
href=${'#' + encodeURIComponent(this.tag)}
|
<style>
|
||||||
class="w3-tag w3-theme-d1 w3-round-4 w3-button"
|
${generate_theme()}</style
|
||||||
>${this.tag}${number}</a
|
><a
|
||||||
> `;
|
href=${'#' + encodeURIComponent(this.tag)}
|
||||||
|
class="w3-tag w3-theme-d1 w3-round-4 w3-button"
|
||||||
|
>${this.tag}${number}</a
|
||||||
|
>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import {LitElement, html} from './lit-all.min.js';
|
import {LitElement, html} from './lit-all.min.js';
|
||||||
import * as tfrpc from '/static/tfrpc.js';
|
import * as tfrpc from '/static/tfrpc.js';
|
||||||
import {styles} from './tf-styles.js';
|
import {styles, generate_theme} from './tf-styles.js';
|
||||||
|
|
||||||
class TfUserElement extends LitElement {
|
class TfUserElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
id: {type: String},
|
id: {type: String},
|
||||||
fallback_name: {type: String},
|
fallback_name: {type: String},
|
||||||
|
icon_only: {type: Boolean},
|
||||||
users: {type: Object},
|
users: {type: Object},
|
||||||
|
nolink: {type: Boolean},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,6 +19,7 @@ class TfUserElement extends LitElement {
|
|||||||
super();
|
super();
|
||||||
this.id = null;
|
this.id = null;
|
||||||
this.fallback_name = null;
|
this.fallback_name = null;
|
||||||
|
this.icon_only = false;
|
||||||
this.users = {};
|
this.users = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,9 +35,12 @@ class TfUserElement extends LitElement {
|
|||||||
>😎</span
|
>😎</span
|
||||||
>`;
|
>`;
|
||||||
let name = this.users?.[this.id]?.name;
|
let name = this.users?.[this.id]?.name;
|
||||||
name = html`<a target="_top" href=${'#' + this.id}
|
let name_string = name ?? this.fallback_name ?? this.id;
|
||||||
>${name ?? this.fallback_name ?? this.id}</a
|
name = this.icon_only
|
||||||
>`;
|
? undefined
|
||||||
|
: !this.nolink
|
||||||
|
? html`<a target="_top" href=${'#' + this.id}>${name_string}</a>`
|
||||||
|
: html`<span>${name_string}</span>`;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
let image_link = user.image;
|
let image_link = user.image;
|
||||||
@@ -48,14 +54,19 @@ class TfUserElement extends LitElement {
|
|||||||
class=${'w3-theme-l4 ' + shape}
|
class=${'w3-theme-l4 ' + shape}
|
||||||
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
|
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
|
||||||
src="/${image_link}/view"
|
src="/${image_link}/view"
|
||||||
|
title=${name_string + ' (' + this.id + ')'}
|
||||||
/>`;
|
/>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return html` <div
|
return html` <style>
|
||||||
style="display: inline-block; vertical-align: middle; font-weight: bold; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis"
|
${generate_theme()}
|
||||||
>
|
</style>
|
||||||
${image} ${name}
|
<div
|
||||||
</div>`;
|
style=${'display: inline-block; vertical-align: middle; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis' +
|
||||||
|
(this.nolink ? '' : '; font-weight: bold')}
|
||||||
|
>
|
||||||
|
${image} ${name}
|
||||||
|
</div>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ function image(node, entering) {
|
|||||||
'</div>'
|
'</div>'
|
||||||
);
|
);
|
||||||
if (this.options.safe && potentiallyUnsafe(node.destination)) {
|
if (this.options.safe && potentiallyUnsafe(node.destination)) {
|
||||||
this.lit('<img src="" alt="');
|
this.lit('<img src="" title="');
|
||||||
} else {
|
} else {
|
||||||
this.lit('<img src="' + this.esc(node.destination) + '" alt="');
|
this.lit('<img src="' + this.esc(node.destination) + '" title="');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.disableTags += 1;
|
this.disableTags += 1;
|
||||||
@@ -104,12 +104,12 @@ export function markdown(md) {
|
|||||||
node.destination.startsWith('@') &&
|
node.destination.startsWith('@') &&
|
||||||
node.destination.endsWith('.ed25519')
|
node.destination.endsWith('.ed25519')
|
||||||
) {
|
) {
|
||||||
node.destination = '#' + node.destination;
|
node.destination = '#' + encodeURIComponent(node.destination);
|
||||||
} else if (
|
} else if (
|
||||||
node.destination.startsWith('%') &&
|
node.destination.startsWith('%') &&
|
||||||
node.destination.endsWith('.sha256')
|
node.destination.endsWith('.sha256')
|
||||||
) {
|
) {
|
||||||
node.destination = '#' + node.destination;
|
node.destination = '#' + encodeURIComponent(node.destination);
|
||||||
} else if (
|
} else if (
|
||||||
node.destination.startsWith('&') &&
|
node.destination.startsWith('&') &&
|
||||||
node.destination.endsWith('.sha256')
|
node.destination.endsWith('.sha256')
|
||||||
|
|||||||
5
apps/trace.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"type": "tildefriends-app",
|
||||||
|
"emoji": "📦",
|
||||||
|
"previous": "&mhBOscDHiJ4VNnod27NOdRVC+4cXYZXIdYjsQBfmTYg=.sha256"
|
||||||
|
}
|
||||||
27
apps/trace/app.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
async function main() {
|
||||||
|
let speedscope_js = await utf8Decode(
|
||||||
|
getFile('speedscope/speedscope-432XE7GS.js')
|
||||||
|
);
|
||||||
|
speedscope_js = speedscope_js.replace(/alert\(`Cannot load.*?return/, '');
|
||||||
|
app.setDocument(`
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title>speedscope</title>
|
||||||
|
<link rel="stylesheet" href="speedscope/speedscope-GHPHNKXC.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
delete window.localStorage;
|
||||||
|
window.location.hash = '#profileURL=${core.url}../../trace';
|
||||||
|
</script>
|
||||||
|
<script>${speedscope_js}</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 679 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -11,7 +11,7 @@
|
|||||||
<link rel="icon" type="image/x-icon" href="favicon-FOKUP5Y5.ico">
|
<link rel="icon" type="image/x-icon" href="favicon-FOKUP5Y5.ico">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="speedscope-VHEG2FVF.js"></script>
|
<script src="speedscope-432XE7GS.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
apps/trace/speedscope/release.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
speedscope@1.24.0
|
||||||
|
Mon Oct 20 18:11:29 PDT 2025
|
||||||
|
fc76932551754a442cd5c4f0afdba28032d14d8a
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "👋",
|
"emoji": "👋",
|
||||||
"previous": "&fY3YUKPuH/wqOgKPVNJu1vWEHCXf5fToL2qiVXMRmxc=.sha256"
|
"previous": "&n1QkPkB5JoduFSx8UKOY3IlZqS2GwLiTUZv4ZrEOthQ=.sha256"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
async function main() {
|
|
||||||
await app.setDocument(utf8Decode(getFile('index.html')));
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
1
apps/welcome/gitea.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 640 640" width="32" height="32"><path d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12" style="fill:#fff"/><path d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6M125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1m300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1" style="fill:#609926"/><path d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8s2 16.3 9.1 20c7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3s17.4 1.7 22.5-5.3c5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8z" style="fill:#609926"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -47,8 +47,10 @@
|
|||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://dev.tildefriends.net/cory/tildefriends"
|
href="https://dev.tildefriends.net/cory/tildefriends"
|
||||||
><i class="fa fa-mug-hot"></i> Development</a
|
|
||||||
>
|
>
|
||||||
|
<img src="gitea.svg" style="height: 1em; margin: 0" />
|
||||||
|
Development
|
||||||
|
</a>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-black w3-padding-large"
|
class="w3-button w3-black w3-padding-large"
|
||||||
href="https://docs.tildefriends.net/"
|
href="https://docs.tildefriends.net/"
|
||||||
@@ -76,7 +78,8 @@
|
|||||||
<h2>First-time user checklist:</h2>
|
<h2>First-time user checklist:</h2>
|
||||||
<ol type="1" style="text-align: left">
|
<ol type="1" style="text-align: left">
|
||||||
<li>
|
<li>
|
||||||
<a href="https://dev.tildefriends.net/cory/tildefriends/releases"
|
<a
|
||||||
|
href="https://dev.tildefriends.net/cory/tildefriends/releases/latest"
|
||||||
>Download</a
|
>Download</a
|
||||||
>
|
>
|
||||||
Tilde Friends or use
|
Tilde Friends or use
|
||||||
@@ -84,7 +87,7 @@
|
|||||||
>https://www.tildefriends.net/</a
|
>https://www.tildefriends.net/</a
|
||||||
>.
|
>.
|
||||||
<div class="w3-cell-row">
|
<div class="w3-cell-row">
|
||||||
<div class="w3-container w3-cell">
|
<div class="w3-container w3-cell w3-mobile">
|
||||||
<h3>Mobile</h3>
|
<h3>Mobile</h3>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
@@ -101,7 +104,7 @@
|
|||||||
src="googleplay.svg"
|
src="googleplay.svg"
|
||||||
style="height: 2em; margin: 0"
|
style="height: 2em; margin: 0"
|
||||||
/>
|
/>
|
||||||
Get it on Google Play (Open Testing)
|
Get it on Google Play
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
|
||||||
@@ -113,7 +116,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>Just launch the app.</p>
|
<p>Just launch the app.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-container w3-cell">
|
<div class="w3-container w3-cell w3-mobile">
|
||||||
<h3>Web</h3>
|
<h3>Web</h3>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
@@ -128,8 +131,19 @@
|
|||||||
>
|
>
|
||||||
to take it for a spin right away.
|
to take it for a spin right away.
|
||||||
</p>
|
</p>
|
||||||
|
<h3>PeachCloud</h3>
|
||||||
|
<p>
|
||||||
|
Tilde Friends is also a part of 🍑☁️<a
|
||||||
|
href="https://peach-docs.commoninternet.net/"
|
||||||
|
>PeachCloud</a
|
||||||
|
>, which is available on
|
||||||
|
<a href="https://apps.yunohost.org/app/peachpub"
|
||||||
|
>YunoHost</a
|
||||||
|
>
|
||||||
|
for accessible self-hosting.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-container w3-cell">
|
<div class="w3-container w3-cell w3-mobile">
|
||||||
<h3>Desktop</h3>
|
<h3>Desktop</h3>
|
||||||
<p>
|
<p>
|
||||||
<a
|
<a
|
||||||
@@ -284,7 +298,7 @@
|
|||||||
|
|
||||||
<!-- Technlology Section -->
|
<!-- Technlology Section -->
|
||||||
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
|
<div class="w3-container w3-padding-64 w3-light-grey w3-center">
|
||||||
<h1 class="w3-jumbo"><b>Built the Old Fashioned Way</b></h1>
|
<h1 class="w3-jumbo"><b>Built to Last</b></h1>
|
||||||
<p>
|
<p>
|
||||||
Tilde Friends strives to use only simple and widely adopted dependencies
|
Tilde Friends strives to use only simple and widely adopted dependencies
|
||||||
in order to keep it easy to build for all sorts of platforms and
|
in order to keep it easy to build for all sorts of platforms and
|
||||||
@@ -326,10 +340,6 @@
|
|||||||
<i class="fa fa-lock w3-text-purple w3-jumbo"></i>
|
<i class="fa fa-lock w3-text-purple w3-jumbo"></i>
|
||||||
<p>libsodium</p>
|
<p>libsodium</p>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/openssl/openssl/releases" class="w3-col s3">
|
|
||||||
<i class="fa fa-shield-halved w3-text-green w3-jumbo"></i>
|
|
||||||
<p>OpenSSL</p>
|
|
||||||
</a>
|
|
||||||
<a
|
<a
|
||||||
href="https://github.com/ianlancetaylor/libbacktrace"
|
href="https://github.com/ianlancetaylor/libbacktrace"
|
||||||
class="w3-col s3"
|
class="w3-col s3"
|
||||||
@@ -337,13 +347,13 @@
|
|||||||
<i class="fa fa-burst w3-text-pink w3-jumbo"></i>
|
<i class="fa fa-burst w3-text-pink w3-jumbo"></i>
|
||||||
<p>libbacktrace</p>
|
<p>libbacktrace</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w3-row" style="margin-top: 64px">
|
|
||||||
<a href="https://codemirror.net/docs/changelog/" class="w3-col s3">
|
<a href="https://codemirror.net/docs/changelog/" class="w3-col s3">
|
||||||
<i class="fa fa-keyboard w3-text-indigo w3-jumbo"></i>
|
<i class="fa fa-keyboard w3-text-indigo w3-jumbo"></i>
|
||||||
<p>CodeMirror</p>
|
<p>CodeMirror</p>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w3-row" style="margin-top: 64px">
|
||||||
<a href="https://github.com/jlfwong/speedscope/" class="w3-col s3">
|
<a href="https://github.com/jlfwong/speedscope/" class="w3-col s3">
|
||||||
<i class="fa fa-microscope w3-text-orange w3-jumbo"></i>
|
<i class="fa fa-microscope w3-text-orange w3-jumbo"></i>
|
||||||
<p>Speedscope</p>
|
<p>Speedscope</p>
|
||||||
@@ -356,9 +366,6 @@
|
|||||||
<i class="fa fa-book-atlas w3-text-purple w3-jumbo"></i>
|
<i class="fa fa-book-atlas w3-text-purple w3-jumbo"></i>
|
||||||
<p>c-ares</p>
|
<p>c-ares</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w3-row" style="margin-top: 64px">
|
|
||||||
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
|
<a href="https://www.gnu.org/software/make/" class="w3-col s3">
|
||||||
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
|
<i class="fa fa-hammer w3-text-teal w3-jumbo"></i>
|
||||||
<p>GNU Make</p>
|
<p>GNU Make</p>
|
||||||
|
|||||||
8
apps/wiki/lit-all.min.js
vendored
39
core/app.js
@@ -1,7 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfapp Tilde Friends App JS
|
||||||
|
* Tilde Friends server-side app wrapper.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
import * as core from './core.js';
|
import * as core from './core.js';
|
||||||
|
|
||||||
let gSessionIndex = 0;
|
export {App};
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
|
/** A sequence number of apps. */
|
||||||
|
let g_session_index = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
** App constructor.
|
||||||
|
** @return An app instance.
|
||||||
|
*/
|
||||||
function App() {
|
function App() {
|
||||||
this._send_queue = [];
|
this._send_queue = [];
|
||||||
this.calls = {};
|
this.calls = {};
|
||||||
@@ -9,6 +25,12 @@ function App() {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Create a function wrapper that when called invokes a function on the app
|
||||||
|
** itself.
|
||||||
|
** @param api The function and argument names.
|
||||||
|
** @return A function.
|
||||||
|
*/
|
||||||
App.prototype.makeFunction = function (api) {
|
App.prototype.makeFunction = function (api) {
|
||||||
let self = this;
|
let self = this;
|
||||||
let result = function () {
|
let result = function () {
|
||||||
@@ -32,6 +54,10 @@ App.prototype.makeFunction = function (api) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Send a message to the app.
|
||||||
|
** @param message The message to send.
|
||||||
|
*/
|
||||||
App.prototype.send = function (message) {
|
App.prototype.send = function (message) {
|
||||||
if (this._send_queue) {
|
if (this._send_queue) {
|
||||||
if (this._on_output) {
|
if (this._on_output) {
|
||||||
@@ -46,6 +72,11 @@ App.prototype.send = function (message) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
** App socket handler.
|
||||||
|
** @param request The HTTP request of the WebSocket connection.
|
||||||
|
** @param response The HTTP response.
|
||||||
|
*/
|
||||||
exports.app_socket = async function socket(request, response) {
|
exports.app_socket = async function socket(request, response) {
|
||||||
let process;
|
let process;
|
||||||
let options = {};
|
let options = {};
|
||||||
@@ -118,7 +149,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
parentApp: parentApp,
|
parentApp: parentApp,
|
||||||
id: blobId,
|
id: blobId,
|
||||||
},
|
},
|
||||||
await ssb.getIdentityInfo(
|
await ssb_internal.getIdentityInfo(
|
||||||
credentials?.session?.name,
|
credentials?.session?.name,
|
||||||
packageOwner,
|
packageOwner,
|
||||||
packageName
|
packageName
|
||||||
@@ -133,7 +164,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
options.packageOwner = packageOwner;
|
options.packageOwner = packageOwner;
|
||||||
options.packageName = packageName;
|
options.packageName = packageName;
|
||||||
options.url = message.url;
|
options.url = message.url;
|
||||||
let sessionId = 'session_' + (gSessionIndex++).toString();
|
let sessionId = 'session_' + (g_session_index++).toString();
|
||||||
if (blobId) {
|
if (blobId) {
|
||||||
if (message.edit_only) {
|
if (message.edit_only) {
|
||||||
response.send(
|
response.send(
|
||||||
@@ -218,4 +249,4 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
response.upgrade(100, {});
|
response.upgrade(100, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
export {App};
|
/** @} */
|
||||||
|
|||||||
@@ -75,6 +75,10 @@
|
|||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
#code_of_conduct:has(>textarea:empty) {
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div style="display: flex; flex-direction: column; max-width: 1280px; margin: auto">
|
<div style="display: flex; flex-direction: column; max-width: 1280px; margin: auto">
|
||||||
<h1 ?hidden=${this.name}>Welcome.</h1>
|
<h1 ?hidden=${this.name}>Welcome.</h1>
|
||||||
@@ -126,8 +130,10 @@
|
|||||||
There is currently no administrator. You will be made administrator.
|
There is currently no administrator. You will be made administrator.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Code of Conduct</h2>
|
<div id="code_of_conduct">
|
||||||
<textarea readonly rows="20" cols="80" style="resize: none">${this.code_of_conduct}</textarea>
|
<h2>Code of Conduct</h2>
|
||||||
|
<textarea readonly rows="20" style="resize: none; width: 100%">${this.code_of_conduct}</textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
648
core/client.js
321
core/core.js
@@ -1,12 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfcore Tilde Friends Core JS
|
||||||
|
* Tilde Friends process management, in JavaScript.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
import * as app from './app.js';
|
import * as app from './app.js';
|
||||||
import * as http from './http.js';
|
|
||||||
|
|
||||||
|
export {invoke, getProcessBlob};
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
|
/** All running processes. */
|
||||||
let gProcesses = {};
|
let gProcesses = {};
|
||||||
|
/** Whether stats are currently being sent. */
|
||||||
let gStatsTimer = false;
|
let gStatsTimer = false;
|
||||||
|
/** Effectively a process ID. */
|
||||||
let g_handler_index = 0;
|
let g_handler_index = 0;
|
||||||
|
/** Whether updating accounts information is currently scheduled. */
|
||||||
|
let g_update_accounts_scheduled;
|
||||||
|
/** Time between pings, in milliseconds. */
|
||||||
const k_ping_interval = 60 * 1000;
|
const k_ping_interval = 60 * 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an error.
|
||||||
|
* @param error The error.
|
||||||
|
*/
|
||||||
function printError(error) {
|
function printError(error) {
|
||||||
if (error.stackTrace) {
|
if (error.stackTrace) {
|
||||||
print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
||||||
@@ -19,6 +38,12 @@ function printError(error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke a handler.
|
||||||
|
* @param handlers The handlers on which to invoke the callback.
|
||||||
|
* @param argv Arguments to pass to the handlers.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function invoke(handlers, argv) {
|
function invoke(handlers, argv) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
@@ -39,6 +64,12 @@ function invoke(handlers, argv) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a named event to all registered apps.
|
||||||
|
* @param eventName the name of the event.
|
||||||
|
* @param argv Arguments to pass to the handlers.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function broadcastEvent(eventName, argv) {
|
function broadcastEvent(eventName, argv) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
for (let process of Object.values(gProcesses)) {
|
for (let process of Object.values(gProcesses)) {
|
||||||
@@ -49,6 +80,11 @@ function broadcastEvent(eventName, argv) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to all other instances of the same app.
|
||||||
|
* @param message The message.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function broadcast(message) {
|
function broadcast(message) {
|
||||||
let sender = this;
|
let sender = this;
|
||||||
let promises = [];
|
let promises = [];
|
||||||
@@ -65,6 +101,15 @@ function broadcast(message) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to all instances of the same app running as the same user.
|
||||||
|
* @param user The user.
|
||||||
|
* @param packageOwner The owner of the app.
|
||||||
|
* @param packageName The name of the app.
|
||||||
|
* @param eventName The name of the event.
|
||||||
|
* @param argv The arguments to pass.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function broadcastAppEventToUser(
|
function broadcastAppEventToUser(
|
||||||
user,
|
user,
|
||||||
packageOwner,
|
packageOwner,
|
||||||
@@ -87,6 +132,11 @@ function broadcastAppEventToUser(
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user context information for a call.
|
||||||
|
* @param caller The calling process.
|
||||||
|
* @param process The receiving process.
|
||||||
|
*/
|
||||||
function getUser(caller, process) {
|
function getUser(caller, process) {
|
||||||
return {
|
return {
|
||||||
key: process.key,
|
key: process.key,
|
||||||
@@ -97,38 +147,26 @@ function getUser(caller, process) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getApps(user, process) {
|
/**
|
||||||
if (
|
* Send a message.
|
||||||
process.credentials &&
|
* @param from The calling process.
|
||||||
process.credentials.session &&
|
* @param to The receiving process.
|
||||||
process.credentials.session.name
|
* @param message The message.
|
||||||
) {
|
* @return A promise.
|
||||||
if (user && user !== process.credentials.session.name && user !== 'core') {
|
*/
|
||||||
return {};
|
|
||||||
} else if (!user) {
|
|
||||||
user = process.credentials.session.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user) {
|
|
||||||
let db = new Database(user);
|
|
||||||
try {
|
|
||||||
let names = JSON.parse(await db.get('apps'));
|
|
||||||
let result = {};
|
|
||||||
for (let name of names) {
|
|
||||||
result[name] = await db.get('path:' + name);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function postMessageInternal(from, to, message) {
|
function postMessageInternal(from, to, message) {
|
||||||
if (to.eventHandlers['message']) {
|
if (to.eventHandlers['message']) {
|
||||||
return invoke(to.eventHandlers['message'], [getUser(from, from), message]);
|
return invoke(to.eventHandlers['message'], [getUser(from, from), message]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a process for an app blob.
|
||||||
|
* @param blobId The blob identifier.
|
||||||
|
* @param key A unique key for the invocation.
|
||||||
|
* @param options Other options.
|
||||||
|
* @return The process.
|
||||||
|
*/
|
||||||
async function getProcessBlob(blobId, key, options) {
|
async function getProcessBlob(blobId, key, options) {
|
||||||
let process = gProcesses[key];
|
let process = gProcesses[key];
|
||||||
if (!process && !(options && 'create' in options && !options.create)) {
|
if (!process && !(options && 'create' in options && !options.create)) {
|
||||||
@@ -142,6 +180,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
process.task = new Task();
|
process.task = new Task();
|
||||||
process.packageOwner = options.packageOwner;
|
process.packageOwner = options.packageOwner;
|
||||||
process.packageName = options.packageName;
|
process.packageName = options.packageName;
|
||||||
|
process.url = options?.url;
|
||||||
process.eventHandlers = {};
|
process.eventHandlers = {};
|
||||||
if (!options?.script || options?.script === 'app.js') {
|
if (!options?.script || options?.script === 'app.js') {
|
||||||
process.app = new app.App();
|
process.app = new app.App();
|
||||||
@@ -155,54 +194,13 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
});
|
});
|
||||||
gProcesses[key] = process;
|
gProcesses[key] = process;
|
||||||
process.task.onExit = function (exitCode, terminationSignal) {
|
process.task.onExit = function (exitCode, terminationSignal) {
|
||||||
broadcastEvent('onSessionEnd', [getUser(process, process)]);
|
|
||||||
process.task = null;
|
process.task = null;
|
||||||
delete gProcesses[key];
|
delete gProcesses[key];
|
||||||
};
|
};
|
||||||
let imports = {
|
let imports = {
|
||||||
core: {
|
core: {
|
||||||
broadcast: broadcast.bind(process),
|
broadcast: broadcast.bind(process),
|
||||||
register: function (eventName, handler) {
|
|
||||||
if (!process.eventHandlers[eventName]) {
|
|
||||||
process.eventHandlers[eventName] = [];
|
|
||||||
}
|
|
||||||
process.eventHandlers[eventName].push(handler);
|
|
||||||
},
|
|
||||||
unregister: function (eventName, handler) {
|
|
||||||
if (process.eventHandlers[eventName]) {
|
|
||||||
let index = process.eventHandlers[eventName].indexOf(handler);
|
|
||||||
if (index != -1) {
|
|
||||||
process.eventHandlers[eventName].splice(index, 1);
|
|
||||||
}
|
|
||||||
if (process.eventHandlers[eventName].length == 0) {
|
|
||||||
delete process.eventHandlers[eventName];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
user: getUser(process, process),
|
user: getUser(process, process),
|
||||||
users: async function () {
|
|
||||||
try {
|
|
||||||
return JSON.parse(await new Database('auth').get('users'));
|
|
||||||
} catch {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
permissionsGranted: async function () {
|
|
||||||
let user = process?.credentials?.session?.name;
|
|
||||||
let settings = await loadSettings();
|
|
||||||
if (
|
|
||||||
user &&
|
|
||||||
options?.packageOwner &&
|
|
||||||
options?.packageName &&
|
|
||||||
settings.userPermissions &&
|
|
||||||
settings.userPermissions[user] &&
|
|
||||||
settings.userPermissions[user][options.packageOwner]
|
|
||||||
) {
|
|
||||||
return settings.userPermissions[user][options.packageOwner][
|
|
||||||
options.packageName
|
|
||||||
];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
allPermissionsGranted: async function () {
|
allPermissionsGranted: async function () {
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
@@ -216,13 +214,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
return settings.userPermissions[user];
|
return settings.userPermissions[user];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
permissionsForUser: async function (user) {
|
permissionTest: async function (permission, description) {
|
||||||
let settings = await loadSettings();
|
|
||||||
return settings?.permissions?.[user] ?? [];
|
|
||||||
},
|
|
||||||
apps: (user) => getApps(user, process),
|
|
||||||
getSockets: getSockets,
|
|
||||||
permissionTest: async function (permission) {
|
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
if (!user || !options?.packageOwner || !options?.packageName) {
|
if (!user || !options?.packageOwner || !options?.packageName) {
|
||||||
@@ -249,7 +241,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
} else if (process.app) {
|
} else if (process.app) {
|
||||||
return process.app
|
return process.app
|
||||||
.makeFunction(['requestPermission'])(permission)
|
.makeFunction(['requestPermission'])(permission, description)
|
||||||
.then(async function (value) {
|
.then(async function (value) {
|
||||||
if (value == 'allow') {
|
if (value == 'allow') {
|
||||||
await ssb.setUserPermission(
|
await ssb.setUserPermission(
|
||||||
@@ -282,26 +274,26 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
throw Error(`Permission denied: ${permission}.`);
|
throw Error(`Permission denied: ${permission}.`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
app: {
|
|
||||||
owner: options?.packageOwner,
|
|
||||||
name: options?.packageName,
|
|
||||||
},
|
|
||||||
url: options?.url,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
process.sendIdentities = async function () {
|
process.sendIdentities = async function () {
|
||||||
process.app.send(
|
let identities = await ssb_internal.getIdentityInfo(
|
||||||
Object.assign(
|
process?.credentials?.session?.name,
|
||||||
{
|
options?.packageOwner,
|
||||||
action: 'identities',
|
options?.packageName
|
||||||
},
|
|
||||||
await ssb.getIdentityInfo(
|
|
||||||
process?.credentials?.session?.name,
|
|
||||||
options?.packageOwner,
|
|
||||||
options?.packageName
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
let json = JSON.stringify(identities);
|
||||||
|
if (process._last_sent_identities !== json) {
|
||||||
|
process.app.send(
|
||||||
|
Object.assign(
|
||||||
|
{
|
||||||
|
action: 'identities',
|
||||||
|
},
|
||||||
|
identities
|
||||||
|
)
|
||||||
|
);
|
||||||
|
process._last_sent_identities = json;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
process.setActiveIdentity = async function (identity) {
|
process.setActiveIdentity = async function (identity) {
|
||||||
if (
|
if (
|
||||||
@@ -338,7 +330,7 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
options.packageName,
|
options.packageName,
|
||||||
'setActiveIdentity',
|
'setActiveIdentity',
|
||||||
[
|
[
|
||||||
await ssb.getActiveIdentity(
|
await imports.ssb.getActiveIdentity(
|
||||||
process.credentials?.session?.name,
|
process.credentials?.session?.name,
|
||||||
options.packageOwner,
|
options.packageOwner,
|
||||||
options.packageName
|
options.packageName
|
||||||
@@ -351,21 +343,11 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (process.credentials?.permissions?.administration) {
|
if (process.credentials?.permissions?.administration) {
|
||||||
imports.core.globalSettingsDescriptions = async function () {
|
|
||||||
let settings = Object.assign({}, defaultGlobalSettings());
|
|
||||||
for (let [key, value] of Object.entries(await loadSettings())) {
|
|
||||||
if (settings[key]) {
|
|
||||||
settings[key].value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return settings;
|
|
||||||
};
|
|
||||||
imports.core.globalSettingsGet = async function (key) {
|
|
||||||
let settings = await loadSettings();
|
|
||||||
return settings?.[key];
|
|
||||||
};
|
|
||||||
imports.core.globalSettingsSet = async function (key, value) {
|
imports.core.globalSettingsSet = async function (key, value) {
|
||||||
await imports.core.permissionTest('set_global_setting');
|
await imports.core.permissionTest(
|
||||||
|
'set_global_setting',
|
||||||
|
`Set ${JSON.stringify(key)} to ${JSON.stringify(value)}.`
|
||||||
|
);
|
||||||
print('Setting', key, value);
|
print('Setting', key, value);
|
||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
settings[key] = value;
|
settings[key] = value;
|
||||||
@@ -445,26 +427,6 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
imports.ssb.setActiveIdentity = (id) => process.setActiveIdentity(id);
|
imports.ssb.setActiveIdentity = (id) => process.setActiveIdentity(id);
|
||||||
imports.ssb.getActiveIdentity = () =>
|
|
||||||
ssb.getActiveIdentity(
|
|
||||||
process.credentials?.session?.name,
|
|
||||||
options.packageOwner,
|
|
||||||
options.packageName
|
|
||||||
);
|
|
||||||
imports.ssb.getOwnerIdentities = function () {
|
|
||||||
if (options.packageOwner) {
|
|
||||||
return ssb.getIdentities(options.packageOwner);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
imports.ssb.getIdentities = function () {
|
|
||||||
if (
|
|
||||||
process.credentials &&
|
|
||||||
process.credentials.session &&
|
|
||||||
process.credentials.session.name
|
|
||||||
) {
|
|
||||||
return ssb.getIdentities(process.credentials.session.name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
imports.ssb.getPrivateKey = function (id) {
|
imports.ssb.getPrivateKey = function (id) {
|
||||||
if (
|
if (
|
||||||
process.credentials &&
|
process.credentials &&
|
||||||
@@ -484,8 +446,18 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
process.credentials.session &&
|
process.credentials.session &&
|
||||||
process.credentials.session.name
|
process.credentials.session.name
|
||||||
) {
|
) {
|
||||||
|
let action;
|
||||||
|
try {
|
||||||
|
if (message?.type === 'vote' && message?.vote?.expression) {
|
||||||
|
action = `React with ${message?.vote?.expression}.`;
|
||||||
|
} else if (typeof message === 'string') {
|
||||||
|
action = `Post a private message.`;
|
||||||
|
} else {
|
||||||
|
action = `Publish ${'aeiou'.indexOf(message?.type?.toLowerCase()?.substring(0, 1)) != -1 ? 'an' : 'a'} "${message?.type}" message.`;
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
imports.core.permissionTest('ssb_append')
|
imports.core.permissionTest('ssb_append', action)
|
||||||
).then(function () {
|
).then(function () {
|
||||||
return ssb.appendMessageWithIdentity(
|
return ssb.appendMessageWithIdentity(
|
||||||
process.credentials.session.name,
|
process.credentials.session.name,
|
||||||
@@ -522,25 +494,28 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
imports.ssb.swapWithServerIdentity = function (id) {
|
if (process.credentials?.permissions?.administration) {
|
||||||
if (
|
imports.ssb.swapWithServerIdentity = function (id) {
|
||||||
process.credentials &&
|
if (
|
||||||
process.credentials.session &&
|
process.credentials &&
|
||||||
process.credentials.session.name
|
process.credentials.session &&
|
||||||
) {
|
process.credentials.session.name
|
||||||
return ssb.swapWithServerIdentity(
|
) {
|
||||||
process.credentials.session.name,
|
return ssb.swapWithServerIdentity(
|
||||||
id
|
process.credentials.session.name,
|
||||||
);
|
id
|
||||||
}
|
);
|
||||||
};
|
}
|
||||||
imports.ssb.addEventListener = undefined;
|
};
|
||||||
imports.ssb.removeEventListener = undefined;
|
imports.ssb.addBlock = async function (id) {
|
||||||
imports.ssb.getIdentityInfo = undefined;
|
await imports.core.permissionTest('modify_blocks', `Block ${id}.`);
|
||||||
imports.fetch = async function (url, options) {
|
await ssb_internal.addBlock(id);
|
||||||
let settings = await loadSettings();
|
};
|
||||||
return http.fetch(url, options, settings?.fetch_hosts);
|
imports.ssb.removeBlock = async function (id) {
|
||||||
};
|
await imports.core.permissionTest('modify_blocks', `Unblock ${id}.`);
|
||||||
|
await ssb_internal.removeBlock(id);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
process.credentials &&
|
process.credentials &&
|
||||||
@@ -644,7 +619,6 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
printError(e);
|
printError(e);
|
||||||
}
|
}
|
||||||
broadcastEvent('onSessionBegin', [getUser(process, process)]);
|
|
||||||
if (process.app) {
|
if (process.app) {
|
||||||
process.app.send({action: 'ready', version: version()});
|
process.app.send({action: 'ready', version: version()});
|
||||||
await process.sendPermissions();
|
await process.sendPermissions();
|
||||||
@@ -667,18 +641,46 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssb.addEventListener('message', function () {
|
/**
|
||||||
|
* Send any changed account information.
|
||||||
|
*/
|
||||||
|
function updateAccounts() {
|
||||||
|
g_update_accounts_scheduled = false;
|
||||||
|
let promises = [];
|
||||||
|
for (let process of Object.values(gProcesses)) {
|
||||||
|
promises.push(process.sendIdentities());
|
||||||
|
}
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSB message added callback.
|
||||||
|
*/
|
||||||
|
ssb_internal.addEventListener('message', function () {
|
||||||
broadcastEvent('onMessage', [...arguments]);
|
broadcastEvent('onMessage', [...arguments]);
|
||||||
|
|
||||||
|
if (!g_update_accounts_scheduled) {
|
||||||
|
setTimeout(updateAccounts, 1000);
|
||||||
|
g_update_accounts_scheduled = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ssb.addEventListener('broadcasts', function () {
|
ssb_internal.addEventListener('blob', function () {
|
||||||
|
broadcastEvent('onBlob', [...arguments]);
|
||||||
|
});
|
||||||
|
|
||||||
|
ssb_internal.addEventListener('broadcasts', function () {
|
||||||
broadcastEvent('onBroadcastsChanged', []);
|
broadcastEvent('onBroadcastsChanged', []);
|
||||||
});
|
});
|
||||||
|
|
||||||
ssb.addEventListener('connections', function () {
|
ssb_internal.addEventListener('connections', function () {
|
||||||
broadcastEvent('onConnectionsChanged', []);
|
broadcastEvent('onConnectionsChanged', []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load settings from the database.
|
||||||
|
* @return The settings as a key value pairs object.
|
||||||
|
*/
|
||||||
async function loadSettings() {
|
async function loadSettings() {
|
||||||
let data = {};
|
let data = {};
|
||||||
try {
|
try {
|
||||||
@@ -697,6 +699,9 @@ async function loadSettings() {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send periodic stats to all clients.
|
||||||
|
*/
|
||||||
function sendStats() {
|
function sendStats() {
|
||||||
let apps = Object.values(gProcesses)
|
let apps = Object.values(gProcesses)
|
||||||
.filter((process) => process.app)
|
.filter((process) => process.app)
|
||||||
@@ -712,6 +717,16 @@ function sendStats() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke an app's handler.js.
|
||||||
|
* @param response The response object.
|
||||||
|
* @param app_blob_id The app's blob identifier.
|
||||||
|
* @param path The request path.
|
||||||
|
* @param query The request query string.
|
||||||
|
* @param headers The request headers.
|
||||||
|
* @param package_owner The app's owner.
|
||||||
|
* @param package_name The app's name.
|
||||||
|
*/
|
||||||
exports.callAppHandler = async function callAppHandler(
|
exports.callAppHandler = async function callAppHandler(
|
||||||
response,
|
response,
|
||||||
app_blob_id,
|
app_blob_id,
|
||||||
@@ -777,4 +792,4 @@ exports.callAppHandler = async function callAppHandler(
|
|||||||
response.end(answer?.data);
|
response.end(answer?.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
export {invoke, getProcessBlob};
|
/** @} */
|
||||||
|
|||||||
67
core/eula.html
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Tilde Friends Usage Agreement</title>
|
||||||
|
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
</head>
|
||||||
|
<body class="w3-container">
|
||||||
|
<h1>Tilde Friends Usage Agreement</h1>
|
||||||
|
<p>
|
||||||
|
Tilde Friends is an app that enables communication with other users
|
||||||
|
through the
|
||||||
|
<a href="https://ssbc.github.io/scuttlebutt-protocol-guide/"
|
||||||
|
>Secure Scuttlebutt</a
|
||||||
|
>
|
||||||
|
protocol.
|
||||||
|
</p>
|
||||||
|
<h2>Your actions are your responsibility</h2>
|
||||||
|
<p>
|
||||||
|
Apple tolerates no objectionable content or abusive users on their
|
||||||
|
platforms.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
You are responsible for your own actions within this app. You are
|
||||||
|
responsible for complying with all applicable rules and laws.
|
||||||
|
</p>
|
||||||
|
<h2>You choose what you see</h2>
|
||||||
|
<p>
|
||||||
|
You are in full control of the content you see in Tilde Friends. The peers
|
||||||
|
to which you choose to connect and the users you choose to follow directly
|
||||||
|
determine the content presented to you. Initially you will be following no
|
||||||
|
one with no connections and as a result see no user-generated content.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you encounter objectionable content, you can filter it from your view
|
||||||
|
by blocking the user who posted it. This also makes it so that users
|
||||||
|
following you will not see it as a consequence of following you.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The <code>admin</code> app contains a variety of settings that control the
|
||||||
|
types of connections Tilde Friends will make or accept, including whether
|
||||||
|
the app will even accept or make connections at all.
|
||||||
|
</p>
|
||||||
|
<h2>This app is not a service</h2>
|
||||||
|
<p>
|
||||||
|
Tilde Friends is an app. It relies on no servers. The author of this app
|
||||||
|
has no more ability to see or filter what you post or read than any other
|
||||||
|
user of the network.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you believe objectionable content obtained from a service that is
|
||||||
|
running as part of the Secure Scuttlebutt network should be flagged,
|
||||||
|
report it to the operator of the service, generally by contacting the
|
||||||
|
email address listed when visiting the server address in a web browser.
|
||||||
|
</p>
|
||||||
|
<h2>Agreement</h2>
|
||||||
|
<p>
|
||||||
|
If you do not accept these terms, do not use this app. You may close and
|
||||||
|
delete it now.
|
||||||
|
</p>
|
||||||
|
<div class="w3-center w3-margin">
|
||||||
|
<a class="w3-button w3-blue w3-round-large" href="/eula/accept"
|
||||||
|
>Accept Agreement</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
113
core/http.js
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* TODO: document so we can improve this
|
|
||||||
* @param {*} url
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function parseUrl(url) {
|
|
||||||
// XXX: Hack.
|
|
||||||
let match = url.match(new RegExp('(\\w+)://([^/:]+)(?::(\\d+))?(.*)'));
|
|
||||||
return {
|
|
||||||
protocol: match[1],
|
|
||||||
host: match[2],
|
|
||||||
path: match[4],
|
|
||||||
port: match[3] ? parseInt(match[3]) : match[1] == 'http' ? 80 : 443,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} data
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function parseResponse(data) {
|
|
||||||
let firstLine;
|
|
||||||
let headers = {};
|
|
||||||
while (true) {
|
|
||||||
let endLine = data.indexOf('\r\n');
|
|
||||||
let line = data.substring(0, endLine);
|
|
||||||
data = data.substring(endLine + 2);
|
|
||||||
if (!line.length) {
|
|
||||||
break;
|
|
||||||
} else if (!firstLine) {
|
|
||||||
firstLine = line;
|
|
||||||
} else {
|
|
||||||
let colon = line.indexOf(':');
|
|
||||||
headers[line.substring(colon)] = line.substring(colon + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {body: data};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} url
|
|
||||||
* @param {*} options
|
|
||||||
* @param {*} allowed_hosts
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function fetch(url, options, allowed_hosts) {
|
|
||||||
let parsed = parseUrl(url);
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
if ((allowed_hosts ?? []).indexOf(parsed.host) == -1) {
|
|
||||||
throw new Error(`fetch() request to host ${parsed.host} is not allowed.`);
|
|
||||||
}
|
|
||||||
let socket = new Socket();
|
|
||||||
let buffer = new Uint8Array(0);
|
|
||||||
|
|
||||||
return socket
|
|
||||||
.connect(parsed.host, parsed.port)
|
|
||||||
.then(function () {
|
|
||||||
socket.read(function (data) {
|
|
||||||
if (data && data.length) {
|
|
||||||
let newBuffer = new Uint8Array(buffer.length + data.length);
|
|
||||||
newBuffer.set(buffer, 0);
|
|
||||||
newBuffer.set(data, buffer.length);
|
|
||||||
buffer = newBuffer;
|
|
||||||
} else {
|
|
||||||
let result = parseHttpResponse(buffer);
|
|
||||||
if (!result) {
|
|
||||||
reject(new Exception('Parse failed.'));
|
|
||||||
}
|
|
||||||
if (typeof result == 'number') {
|
|
||||||
if (result == -2) {
|
|
||||||
reject('Incomplete request.');
|
|
||||||
} else {
|
|
||||||
reject('Bad request.');
|
|
||||||
}
|
|
||||||
} else if (typeof result == 'object') {
|
|
||||||
resolve({
|
|
||||||
body: buffer.slice(result.bytes_parsed),
|
|
||||||
status: result.status,
|
|
||||||
message: result.message,
|
|
||||||
headers: result.headers,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reject(new Exception('Unexpected parse result.'));
|
|
||||||
}
|
|
||||||
resolve(parseResponse(utf8Decode(buffer)));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (parsed.port == 443) {
|
|
||||||
return socket.startTls();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
let body =
|
|
||||||
typeof options?.body == 'string'
|
|
||||||
? utf8Encode(options.body)
|
|
||||||
: options.body || new Uint8Array(0);
|
|
||||||
let headers = utf8Encode(
|
|
||||||
`${options?.method ?? 'GET'} ${parsed.path} HTTP/1.0\r\nHost: ${parsed.host}\r\nConnection: close\r\nContent-Length: ${body.length}\r\n\r\n`
|
|
||||||
);
|
|
||||||
let fullRequest = new Uint8Array(headers.length + body.length);
|
|
||||||
fullRequest.set(headers, 0);
|
|
||||||
fullRequest.set(body, headers.length);
|
|
||||||
socket.write(fullRequest);
|
|
||||||
})
|
|
||||||
.catch(function (error) {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,10 @@
|
|||||||
<link type="text/css" rel="stylesheet" href="/static/style.css" />
|
<link type="text/css" rel="stylesheet" href="/static/style.css" />
|
||||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||||
<link type="image/svg+xml" rel="icon" href="/static/tildefriends.svg" />
|
<link type="image/svg+xml" rel="icon" href="/static/tildefriends.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, maximum-scale=1"
|
||||||
|
/>
|
||||||
<meta
|
<meta
|
||||||
name="title"
|
name="title"
|
||||||
content="Tilde Friends - Make friends and apps from your web browser."
|
content="Tilde Friends - Make friends and apps from your web browser."
|
||||||
|
|||||||
@@ -152,4 +152,5 @@ body {
|
|||||||
border-bottom: 4px solid #fff;
|
border-bottom: 4px solid #fff;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
max-width: 80%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfrpc Tilde Friends RPC.
|
||||||
|
* Tilde Friends RPC.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Whether this module is being run in a web browser. */
|
||||||
const k_is_browser = get_is_browser();
|
const k_is_browser = get_is_browser();
|
||||||
|
/** Registered methods. */
|
||||||
let g_api = {};
|
let g_api = {};
|
||||||
|
/** The next method identifier. */
|
||||||
let g_next_id = 1;
|
let g_next_id = 1;
|
||||||
|
/** Identifiers of pending calls. */
|
||||||
let g_calls = {};
|
let g_calls = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Check if being called from a browser vs. server-side.
|
||||||
* @returns
|
* @return true if called from a browser.
|
||||||
*/
|
*/
|
||||||
function get_is_browser() {
|
function get_is_browser() {
|
||||||
try {
|
try {
|
||||||
@@ -15,16 +26,30 @@ function get_is_browser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
if (k_is_browser) {
|
if (k_is_browser) {
|
||||||
print = console.log;
|
print = console.log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (k_is_browser) {
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
|
call_rpc(event.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.register('message', function (message) {
|
||||||
|
call_rpc(message?.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export let rpc = new Proxy({}, {get: make_rpc});
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Make a function to invoke a remote procedure.
|
||||||
* @param {*} target
|
* @param target The target.
|
||||||
* @param {*} prop
|
* @param prop The name of the function.
|
||||||
* @param {*} receiver
|
* @param receiver The receiver.
|
||||||
* @returns
|
* @return A function.
|
||||||
*/
|
*/
|
||||||
function make_rpc(target, prop, receiver) {
|
function make_rpc(target, prop, receiver) {
|
||||||
return function () {
|
return function () {
|
||||||
@@ -55,8 +80,8 @@ function make_rpc(target, prop, receiver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Send a response.
|
||||||
* @param {*} response
|
* @param response The response.
|
||||||
*/
|
*/
|
||||||
function send(response) {
|
function send(response) {
|
||||||
if (k_is_browser) {
|
if (k_is_browser) {
|
||||||
@@ -67,8 +92,8 @@ function send(response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Invoke a remote procedure.
|
||||||
* @param {*} message
|
* @param message An object describing the call.
|
||||||
*/
|
*/
|
||||||
function call_rpc(message) {
|
function call_rpc(message) {
|
||||||
if (message && message.message === 'tfrpc') {
|
if (message && message.message === 'tfrpc') {
|
||||||
@@ -112,22 +137,12 @@ function call_rpc(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k_is_browser) {
|
|
||||||
window.addEventListener('message', function (event) {
|
|
||||||
call_rpc(event.data);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
core.register('message', function (message) {
|
|
||||||
call_rpc(message?.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export let rpc = new Proxy({}, {get: make_rpc});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Register a function that to be called remotely.
|
||||||
* @param {*} method
|
* @param method The method.
|
||||||
*/
|
*/
|
||||||
export function register(method) {
|
export function register(method) {
|
||||||
g_api[method.name] = method;
|
g_api[method.name] = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|||||||
@@ -25,14 +25,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.0.31";
|
version = "0.2025.11";
|
||||||
|
|
||||||
src = pkgs.fetchFromGitea {
|
src = pkgs.fetchFromGitea {
|
||||||
domain = "dev.tildefriends.net";
|
domain = "dev.tildefriends.net";
|
||||||
owner = "cory";
|
owner = "cory";
|
||||||
repo = "tildefriends";
|
repo = "tildefriends";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
hash = "sha256-c2ZKVNikI5jN5GQuvp7S53qqnRZniSrJMF1FUZdVNPI=";
|
hash = "sha256-z4v4ghKOBTMv+agTUKg+HU8zfE4imluXFsozQCT4qX8=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
deps/codemirror/cm6.js
vendored
451
deps/codemirror_src/package-lock.json
generated
vendored
@@ -19,9 +19,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/autocomplete": {
|
"node_modules/@codemirror/autocomplete": {
|
||||||
"version": "6.18.6",
|
"version": "6.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz",
|
||||||
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
"integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@@ -30,9 +31,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.8.1",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz",
|
||||||
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
|
"integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
||||||
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
@@ -53,9 +56,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-html": {
|
"node_modules/@codemirror/lang-html": {
|
||||||
"version": "6.4.9",
|
"version": "6.4.11",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz",
|
||||||
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
"integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/lang-css": "^6.0.0",
|
"@codemirror/lang-css": "^6.0.0",
|
||||||
@@ -65,13 +69,14 @@
|
|||||||
"@codemirror/view": "^6.17.0",
|
"@codemirror/view": "^6.17.0",
|
||||||
"@lezer/common": "^1.0.0",
|
"@lezer/common": "^1.0.0",
|
||||||
"@lezer/css": "^1.1.0",
|
"@lezer/css": "^1.1.0",
|
||||||
"@lezer/html": "^1.3.0"
|
"@lezer/html": "^1.3.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lang-javascript": {
|
"node_modules/@codemirror/lang-javascript": {
|
||||||
"version": "6.2.4",
|
"version": "6.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
|
||||||
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
|
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.6.0",
|
"@codemirror/language": "^6.6.0",
|
||||||
@@ -86,15 +91,17 @@
|
|||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
||||||
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@lezer/json": "^1.0.0"
|
"@lezer/json": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.11.1",
|
"version": "6.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz",
|
||||||
"integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==",
|
"integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.23.0",
|
"@codemirror/view": "^6.23.0",
|
||||||
@@ -105,9 +112,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lint": {
|
"node_modules/@codemirror/lint": {
|
||||||
"version": "6.8.5",
|
"version": "6.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz",
|
||||||
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
|
"integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.35.0",
|
"@codemirror/view": "^6.35.0",
|
||||||
@@ -118,6 +126,7 @@
|
|||||||
"version": "6.5.11",
|
"version": "6.5.11",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
||||||
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.0.0",
|
||||||
@@ -128,6 +137,7 @@
|
|||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||||
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@marijn/find-cluster-break": "^1.0.0"
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -136,6 +146,7 @@
|
|||||||
"version": "6.1.3",
|
"version": "6.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
||||||
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@@ -144,9 +155,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.37.2",
|
"version": "6.38.8",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.8.tgz",
|
||||||
"integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==",
|
"integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
"crelt": "^1.0.6",
|
"crelt": "^1.0.6",
|
||||||
@@ -155,17 +167,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.8",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
"integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
|
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.2.1",
|
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
|
||||||
"@jridgewell/trace-mapping": "^0.3.24"
|
"@jridgewell/trace-mapping": "^0.3.24"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/resolve-uri": {
|
"node_modules/@jridgewell/resolve-uri": {
|
||||||
@@ -173,54 +182,51 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"license": "MIT",
|
||||||
"node": ">=6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/set-array": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/source-map": {
|
"node_modules/@jridgewell/source-map": {
|
||||||
"version": "0.3.6",
|
"version": "0.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
|
||||||
"integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
|
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
"@jridgewell/trace-mapping": "^0.3.25"
|
"@jridgewell/trace-mapping": "^0.3.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.25",
|
"version": "0.3.31",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||||
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
|
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.3.0.tgz",
|
||||||
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
|
"integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/css": {
|
"node_modules/@lezer/css": {
|
||||||
"version": "1.2.1",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz",
|
||||||
"integrity": "sha512-2F5tOqzKEKbCUNraIXc0f6HKeyKlmMWJnBB0i4XW6dJgssrZO/YlZ2pY5xgyqDleqqhiNJ3dQhbrV2aClZQMvg==",
|
"integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -228,17 +234,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/highlight": {
|
"node_modules/@lezer/highlight": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
||||||
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/html": {
|
"node_modules/@lezer/html": {
|
||||||
"version": "1.3.10",
|
"version": "1.3.12",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz",
|
||||||
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
|
"integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -246,9 +254,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/javascript": {
|
"node_modules/@lezer/javascript": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
|
||||||
"integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
|
"integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.1.3",
|
"@lezer/highlight": "^1.1.3",
|
||||||
@@ -259,6 +268,7 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||||
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -266,9 +276,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/lr": {
|
"node_modules/@lezer/lr": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.3.tgz",
|
||||||
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
"integrity": "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -276,12 +287,14 @@
|
|||||||
"node_modules/@marijn/find-cluster-break": {
|
"node_modules/@marijn/find-cluster-break": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||||
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="
|
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-node-resolve": {
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
"version": "15.3.1",
|
"version": "15.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
|
||||||
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
|
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^5.0.1",
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
"@types/resolve": "1.20.2",
|
"@types/resolve": "1.20.2",
|
||||||
@@ -306,6 +319,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialize-javascript": "^6.0.1",
|
"serialize-javascript": "^6.0.1",
|
||||||
"smob": "^1.0.0",
|
"smob": "^1.0.0",
|
||||||
@@ -324,9 +338,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/pluginutils": {
|
"node_modules/@rollup/pluginutils": {
|
||||||
"version": "5.2.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
|
||||||
"integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==",
|
"integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
@@ -345,240 +360,286 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
|
||||||
"integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==",
|
"integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
|
||||||
"integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==",
|
"integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
|
||||||
"integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==",
|
"integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
|
||||||
"integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==",
|
"integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
|
||||||
"integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==",
|
"integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
|
||||||
"integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==",
|
"integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
|
||||||
"integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==",
|
"integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
|
||||||
"integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==",
|
"integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
|
||||||
"integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==",
|
"integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
|
||||||
"integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==",
|
"integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
|
||||||
"integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==",
|
"integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
|
||||||
"integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==",
|
"integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
|
||||||
"integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==",
|
"integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
|
||||||
"integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==",
|
"integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
|
||||||
"integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==",
|
"integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
|
||||||
"integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==",
|
"integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
|
||||||
"integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==",
|
"integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
|
||||||
"integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==",
|
"integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"openharmony"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
|
"version": "4.53.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
|
||||||
|
"integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
|
||||||
"integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==",
|
"integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||||
|
"version": "4.53.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
|
||||||
|
"integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
|
||||||
"integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==",
|
"integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@@ -587,18 +648,21 @@
|
|||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
|
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
|
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -610,12 +674,14 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/codemirror": {
|
"node_modules/codemirror": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
||||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/commands": "^6.0.0",
|
"@codemirror/commands": "^6.0.0",
|
||||||
@@ -630,17 +696,20 @@
|
|||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/crelt": {
|
"node_modules/crelt": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -648,13 +717,15 @@
|
|||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@@ -667,6 +738,7 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@@ -675,6 +747,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
},
|
},
|
||||||
@@ -686,6 +759,7 @@
|
|||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hasown": "^2.0.2"
|
"hasown": "^2.0.2"
|
||||||
},
|
},
|
||||||
@@ -699,17 +773,20 @@
|
|||||||
"node_modules/is-module": {
|
"node_modules/is-module": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||||
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="
|
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -722,16 +799,18 @@
|
|||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.10",
|
"version": "1.22.11",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
|
||||||
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.16.0",
|
"is-core-module": "^2.16.1",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||||
},
|
},
|
||||||
@@ -746,9 +825,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.44.0",
|
"version": "4.53.3",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
|
||||||
"integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==",
|
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.8"
|
"@types/estree": "1.0.8"
|
||||||
},
|
},
|
||||||
@@ -760,26 +840,28 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.44.0",
|
"@rollup/rollup-android-arm-eabi": "4.53.3",
|
||||||
"@rollup/rollup-android-arm64": "4.44.0",
|
"@rollup/rollup-android-arm64": "4.53.3",
|
||||||
"@rollup/rollup-darwin-arm64": "4.44.0",
|
"@rollup/rollup-darwin-arm64": "4.53.3",
|
||||||
"@rollup/rollup-darwin-x64": "4.44.0",
|
"@rollup/rollup-darwin-x64": "4.53.3",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.44.0",
|
"@rollup/rollup-freebsd-arm64": "4.53.3",
|
||||||
"@rollup/rollup-freebsd-x64": "4.44.0",
|
"@rollup/rollup-freebsd-x64": "4.53.3",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.44.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.44.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.53.3",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.44.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.53.3",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.44.0",
|
"@rollup/rollup-linux-arm64-musl": "4.53.3",
|
||||||
"@rollup/rollup-linux-loongarch64-gnu": "4.44.0",
|
"@rollup/rollup-linux-loong64-gnu": "4.53.3",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.44.0",
|
"@rollup/rollup-linux-ppc64-gnu": "4.53.3",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.44.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.53.3",
|
||||||
"@rollup/rollup-linux-riscv64-musl": "4.44.0",
|
"@rollup/rollup-linux-riscv64-musl": "4.53.3",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.44.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.53.3",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.44.0",
|
"@rollup/rollup-linux-x64-gnu": "4.53.3",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.44.0",
|
"@rollup/rollup-linux-x64-musl": "4.53.3",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.44.0",
|
"@rollup/rollup-openharmony-arm64": "4.53.3",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.44.0",
|
"@rollup/rollup-win32-arm64-msvc": "4.53.3",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.44.0",
|
"@rollup/rollup-win32-ia32-msvc": "4.53.3",
|
||||||
|
"@rollup/rollup-win32-x64-gnu": "4.53.3",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.53.3",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -801,13 +883,15 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/serialize-javascript": {
|
"node_modules/serialize-javascript": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||||
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"randombytes": "^2.1.0"
|
"randombytes": "^2.1.0"
|
||||||
}
|
}
|
||||||
@@ -816,13 +900,15 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
||||||
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -832,20 +918,23 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/style-mod": {
|
"node_modules/style-mod": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
||||||
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@@ -854,13 +943,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "5.43.1",
|
"version": "5.44.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
|
||||||
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
|
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.3",
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.15.0",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
"source-map-support": "~0.5.20"
|
"source-map-support": "~0.5.20"
|
||||||
},
|
},
|
||||||
@@ -874,7 +964,8 @@
|
|||||||
"node_modules/w3c-keyname": {
|
"node_modules/w3c-keyname": {
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
deps/libbacktrace
vendored
8
deps/lit/lit-all.min.js
vendored
2
deps/lit/lit-all.min.js.map
vendored
1
deps/openssl_src
vendored
2
deps/picohttpparser
vendored
2
deps/quickjs
vendored
3
deps/speedscope/release.txt
vendored
@@ -1,3 +0,0 @@
|
|||||||
speedscope@1.22.2
|
|
||||||
Sat Feb 15 13:02:38 PST 2025
|
|
||||||
1c254dcb3e2b4f6d921340d20e972d9d27b788f4
|
|
||||||
2544
deps/sqlite/shell.c
vendored
6055
deps/sqlite/sqlite3.c
vendored
583
deps/sqlite/sqlite3.h
vendored
7
deps/sqlite/sqlite3ext.h
vendored
@@ -368,6 +368,10 @@ struct sqlite3_api_routines {
|
|||||||
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
||||||
/* Version 3.50.0 and later */
|
/* Version 3.50.0 and later */
|
||||||
int (*setlk_timeout)(sqlite3*,int,int);
|
int (*setlk_timeout)(sqlite3*,int,int);
|
||||||
|
/* Version 3.51.0 and later */
|
||||||
|
int (*set_errmsg)(sqlite3*,int,const char*);
|
||||||
|
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -703,6 +707,9 @@ typedef int (*sqlite3_loadext_entry)(
|
|||||||
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
||||||
/* Version 3.50.0 and later */
|
/* Version 3.50.0 and later */
|
||||||
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
||||||
|
/* Version 3.51.0 and later */
|
||||||
|
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
|
||||||
|
#define sqlite3_db_status64 sqlite3_api->db_status64
|
||||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||||
|
|
||||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||||
|
|||||||
32
docs/model.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Model
|
||||||
|
|
||||||
|
A reasonable mental model of Tilde Friends is as a virtual computer. User
|
||||||
|
interace is through a web browser. Communication with the outside world is
|
||||||
|
through the Secure Scuttlebutt (SSB) network protocol. Persistence is through
|
||||||
|
an SSB store and an additional key-value store in an sqlite database.
|
||||||
|
|
||||||
|
The schema for the sqlite database is primarily a `messages` table and a
|
||||||
|
`blobs` table, which are what one would expect from the SSB specifications.
|
||||||
|
|
||||||
|
```dot
|
||||||
|
digraph {
|
||||||
|
web_browser -> tilde_friends_web_interface [dir=both];
|
||||||
|
web_browser [shape=rect,label="Web Browser"];
|
||||||
|
subgraph cluster_tilde_friends {
|
||||||
|
label = "Tilde Friends";
|
||||||
|
tilde_friends_web_interface -> example_app [dir=both];
|
||||||
|
subgraph cluster_sandbox {
|
||||||
|
label = "app sandbox";
|
||||||
|
example_app;
|
||||||
|
}
|
||||||
|
example_app -> tilde_friends_core;
|
||||||
|
tilde_friends_core -> example_app;
|
||||||
|
tilde_friends_web_interface -> tilde_friends_core;
|
||||||
|
tilde_friends_core -> "db.sqlite";
|
||||||
|
tilde_friends_core -> ssb;
|
||||||
|
"db.sqlite" [shape=cylinder];
|
||||||
|
}
|
||||||
|
ssb -> other_ssb_clients [label="Secure Handshake",dir=both];
|
||||||
|
other_ssb_clients [shape=rect,label="SSB Peers"];
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -41,11 +41,9 @@ options:
|
|||||||
ssb_port (default: 8008): Port on which to listen for SSB secure handshake connections.
|
ssb_port (default: 8008): Port on which to listen for SSB secure handshake connections.
|
||||||
http_local_only (default: false): Whether to bind http(s) to the loopback address. Otherwise any.
|
http_local_only (default: false): Whether to bind http(s) to the loopback address. Otherwise any.
|
||||||
http_port (default: 12345): Port on which to listen for HTTP connections.
|
http_port (default: 12345): Port on which to listen for HTTP connections.
|
||||||
https_port (default: 0): Port on which to listen for secure HTTP connections.
|
|
||||||
out_http_port_file (default: ""): File to which to write bound HTTP port.
|
out_http_port_file (default: ""): File to which to write bound HTTP port.
|
||||||
blob_fetch_age_seconds (default: -1): Only blobs mentioned more recently than this age will be automatically fetched.
|
blob_fetch_age_seconds (default: -1): Only blobs mentioned more recently than this age will be automatically fetched.
|
||||||
blob_expire_age_seconds (default: -1): Blobs older than this will be automatically deleted.
|
blob_expire_age_seconds (default: -1): Blobs older than this will be automatically deleted.
|
||||||
fetch_hosts (default: ""): Comma-separated list of host names to which HTTP fetch requests are allowed. None if empty.
|
|
||||||
http_redirect (default: ""): If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "http://example.com")
|
http_redirect (default: ""): If connecting by HTTP and HTTPS is configured, Location header prefix (ie, "http://example.com")
|
||||||
index (default: "/~core/intro/"): Default path.
|
index (default: "/~core/intro/"): Default path.
|
||||||
index_map (default: ""): Mappings from hostname to redirect path, one per line, as in: "www.tildefriends.net=/~core/index/"
|
index_map (default: ""): Mappings from hostname to redirect path, one per line, as in: "www.tildefriends.net=/~core/index/"
|
||||||
@@ -61,6 +59,8 @@ options:
|
|||||||
autologin (default: false): Whether mobile autologin is supported.
|
autologin (default: false): Whether mobile autologin is supported.
|
||||||
broadcast (default: true): Send network discovery broadcasts.
|
broadcast (default: true): Send network discovery broadcasts.
|
||||||
discovery (default: true): Receive network discovery broadcasts.
|
discovery (default: true): Receive network discovery broadcasts.
|
||||||
|
stay_connected (default: false): Whether to attempt to keep several peer connections open.
|
||||||
|
accepted_eula_version (default: 0): The version of the last accepted EULA.
|
||||||
-o, --one-proc Run everything in one process (unsafely!).
|
-o, --one-proc Run everything in one process (unsafely!).
|
||||||
-z, --zip path Zip archive from which to load files.
|
-z, --zip path Zip archive from which to load files.
|
||||||
-v, --verbose Log raw messages.
|
-v, --verbose Log raw messages.
|
||||||
|
|||||||
8
flake.lock
generated
@@ -20,16 +20,16 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748037224,
|
"lastModified": 1763948260,
|
||||||
"narHash": "sha256-92vihpZr6dwEMV6g98M5kHZIttrWahb9iRPBm1atcPk=",
|
"narHash": "sha256-dY9qLD0H0zOUgU3vWacPY6Qc421BeQAfm8kBuBtPVE0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "f09dede81861f3a83f7f06641ead34f02f37597f",
|
"rev": "1c8ba8d3f7634acac4a2094eef7c32ad9106532c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixos-24.11",
|
"ref": "nixos-25.05",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
description = "Tilde Friends is a platform for making, running, and sharing web applications.";
|
description = "Tilde Friends is a platform for making, running, and sharing web applications.";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
metadata/en-US/changelogs/39.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
* Updating Android SDK+target versions.
|
||||||
|
* Minor UI improvements.
|
||||||
14
metadata/en-US/changelogs/40.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
* Added an option to stay connected to a handful of peers.
|
||||||
|
* Load more messages at a time.
|
||||||
|
* Fix a set of Android not responding errors.
|
||||||
|
* Target Android 15 (API level 35) to meet new requirements.
|
||||||
|
* Support JS-less webapps.
|
||||||
|
* Fix unnecessary tunnel disconnects.
|
||||||
|
* Many small user interface tweaks.
|
||||||
|
* Update:
|
||||||
|
* CodeMirror
|
||||||
|
* OpenSSL 3.5.1
|
||||||
|
* lit 3.3.1
|
||||||
|
* picohttpparser
|
||||||
|
* speedscope 1.23.0
|
||||||
|
* sqlite 3.50.4
|
||||||
9
metadata/en-US/changelogs/42.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
* Private messages interface overhaul in progress.
|
||||||
|
* Added a loading indicator.
|
||||||
|
* Documented the core JavaScript.
|
||||||
|
* Fixed @-completion.
|
||||||
|
* Covered up launch on Android with the splash screen.
|
||||||
|
* Update:
|
||||||
|
* CodeMirror
|
||||||
|
* OpenSSL 3.5.2
|
||||||
|
* speedscope 1.23.1
|
||||||
8
metadata/en-US/changelogs/43.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
* Fixed multiple issues with blob replication.
|
||||||
|
* Fixed some link encoding issues.
|
||||||
|
* Fixed some context menus being cut off.
|
||||||
|
* Minor Android fixes.
|
||||||
|
* Updates:
|
||||||
|
* CodeMirror
|
||||||
|
* OpenSSL 3.5.3
|
||||||
|
* QuickJS 2025-09-13
|
||||||
10
metadata/en-US/changelogs/44.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
* Faster load times.
|
||||||
|
* Private message fixes.
|
||||||
|
* Fix contact groups expanding/collapsing.
|
||||||
|
* Manual SSB theme color picker.
|
||||||
|
* Give channel subscribe/unsubscribe similar grouping treatment to follows/blocks.
|
||||||
|
* Slightly improved following/blocking message display.
|
||||||
|
* Remove the query tab in favor of searching for "sql:SELECT ...".
|
||||||
|
* Exclude messages for subscribed channels from the general feed.
|
||||||
|
* Remove OpenSSL.
|
||||||
|
* Updates: CodeMirror, libbacktrace, and speedscope 1.24.0.
|
||||||
9
metadata/en-US/changelogs/48.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
* Fixed disagreement in identity information.
|
||||||
|
* Show more context when prompting for permissions.
|
||||||
|
* Reduce redundant queries to improve load times.
|
||||||
|
* Improved profile load times.
|
||||||
|
* Don't show an empty code of conduct.
|
||||||
|
* Resolve ambiguity when a user is both followed and blocked (they're blocked).
|
||||||
|
* Move perf tracing viewer into a trace app.
|
||||||
|
* Minor UI improvements.
|
||||||
|
* Updates: CodeMirror, emojis, libbacktrace, sqlite 3.51.0.
|
||||||
7
package-lock.json
generated
@@ -11,9 +11,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-5xGWRa90Sp2+x1dQtNpIpeOQpTDBs9cZDmA/qs2vDNN2i18PdapqY7CmBeyLlMuGqXJRIOPaCaVZTLNQRWUH/A==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.unprompted.tildefriends"
|
package="com.unprompted.tildefriends"
|
||||||
android:versionCode="38"
|
android:versionCode="49"
|
||||||
android:versionName="0.0.32">
|
android:versionName="0.2025.12-wip">
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ import android.os.RemoteException;
|
|||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
import android.webkit.CookieManager;
|
import android.webkit.CookieManager;
|
||||||
import android.webkit.DownloadListener;
|
import android.webkit.DownloadListener;
|
||||||
import android.webkit.JsPromptResult;
|
import android.webkit.JsPromptResult;
|
||||||
@@ -43,6 +43,7 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class TildeFriendsActivity extends Activity {
|
public class TildeFriendsActivity extends Activity {
|
||||||
@@ -50,39 +51,44 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
TildeFriendsWebView web_view;
|
TildeFriendsWebView web_view;
|
||||||
String base_url;
|
String base_url;
|
||||||
String port_file_path;
|
String port_file_path;
|
||||||
|
Thread create_thread;
|
||||||
Thread server_thread;
|
Thread server_thread;
|
||||||
|
Thread log_thread;
|
||||||
ServiceConnection service_connection;
|
ServiceConnection service_connection;
|
||||||
FileObserver observer;
|
FileObserver observer;
|
||||||
|
LinkedBlockingQueue<String> log_queue = new LinkedBlockingQueue<String>();
|
||||||
|
|
||||||
private ValueCallback<Uri[]> upload_message;
|
private ValueCallback<Uri[]> upload_message;
|
||||||
private final static int FILECHOOSER_RESULT = 1;
|
private final static int FILECHOOSER_RESULT = 1;
|
||||||
private float touch_down_y;
|
private float touch_down_y;
|
||||||
|
private boolean ready = false;
|
||||||
|
private boolean loaded = false;
|
||||||
|
private boolean shutting_down = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Log.w("tildefriends", "Calling system.loadLibrary().");
|
log("Calling system.loadLibrary().");
|
||||||
System.loadLibrary("tildefriends");
|
System.loadLibrary("tildefriends");
|
||||||
Log.w("tildefriends", "system.loadLibrary() completed.");
|
log("system.loadLibrary() completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
|
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
|
||||||
public static native int tf_sandbox_main(int pipe_fd);
|
public static native int tf_sandbox_main(int pipe_fd);
|
||||||
|
|
||||||
@Override
|
public static void log(String message) {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
if (s_activity != null && s_activity.log_queue != null && message != null) {
|
||||||
s_activity = this;
|
try {
|
||||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
s_activity.log_queue.put(message);
|
||||||
.detectLeakedClosableObjects()
|
} catch (InterruptedException e) {
|
||||||
.penaltyLog()
|
android.util.Log.w("tildefriends", message);
|
||||||
.build());
|
}
|
||||||
super.onCreate(savedInstanceState);
|
}
|
||||||
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
}
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
|
|
||||||
|
private void createThread() {
|
||||||
web_view = (TildeFriendsWebView)findViewById(R.id.web);
|
web_view = (TildeFriendsWebView)findViewById(R.id.web);
|
||||||
set_status("Extracting executable...");
|
log(String.format("getFilesDir() is %s", getFilesDir().toString()));
|
||||||
Log.w("tildefriends", String.format("getFilesDir() is %s", getFilesDir().toString()));
|
log(String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
|
||||||
Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
|
log(String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
|
||||||
Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
|
|
||||||
|
|
||||||
port_file_path = getFilesDir().toString() + "/port.txt";
|
port_file_path = getFilesDir().toString() + "/port.txt";
|
||||||
new File(port_file_path).delete();
|
new File(port_file_path).delete();
|
||||||
@@ -90,178 +96,256 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
|
|
||||||
TildeFriendsActivity activity = this;
|
TildeFriendsActivity activity = this;
|
||||||
|
|
||||||
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
|
|
||||||
observer = make_file_observer(getFilesDir().toString(), port_file_path);
|
|
||||||
observer.startWatching();
|
|
||||||
|
|
||||||
set_status("Starting server...");
|
|
||||||
server_thread = new Thread(new Runnable() {
|
server_thread = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.w("tildefriends", "Calling tf_server_main.");
|
log("Watching for changes in: " + getFilesDir().toString());
|
||||||
|
observer = make_file_observer(getFilesDir().toString(), port_file_path);
|
||||||
|
observer.startWatching();
|
||||||
|
|
||||||
|
log("Calling tf_server_main.");
|
||||||
int result = tf_server_main(
|
int result = tf_server_main(
|
||||||
getFilesDir().toString(),
|
getFilesDir().toString(),
|
||||||
getPackageResourcePath().toString(),
|
getPackageResourcePath().toString(),
|
||||||
port_file_path,
|
port_file_path,
|
||||||
(ConnectivityManager)getApplicationContext().getSystemService(CONNECTIVITY_SERVICE));
|
(ConnectivityManager)getApplicationContext().getSystemService(CONNECTIVITY_SERVICE));
|
||||||
Log.w("tildefriends", "tf_server_main returned " + result + ".");
|
log("tf_server_main returned " + result + ".");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
server_thread.start();
|
server_thread.start();
|
||||||
|
|
||||||
web_view.getSettings().setJavaScriptEnabled(true);
|
runOnUiThread(() -> {
|
||||||
web_view.getSettings().setDatabaseEnabled(true);
|
web_view.getSettings().setJavaScriptEnabled(true);
|
||||||
web_view.getSettings().setDomStorageEnabled(true);
|
web_view.getSettings().setDomStorageEnabled(true);
|
||||||
|
|
||||||
set_database_path();
|
set_database_enabled();
|
||||||
|
set_database_path();
|
||||||
|
|
||||||
web_view.setDownloadListener(new DownloadListener() {
|
web_view.setDownloadListener(new DownloadListener() {
|
||||||
public void onDownloadStart(String url, String userAgent, String content_disposition, String mime_type, long content_length) {
|
public void onDownloadStart(String url, String userAgent, String content_disposition, String mime_type, long content_length) {
|
||||||
Log.w("tildefriends", "Let's download: " + url + " (" + content_disposition + ")");
|
log("Let's download: " + url + " (" + content_disposition + ")");
|
||||||
String file_name = URLUtil.guessFileName(url, content_disposition, mime_type);
|
String file_name = URLUtil.guessFileName(url, content_disposition, mime_type);
|
||||||
if (url.startsWith("data:") && url.indexOf(',') != -1) {
|
if (url.startsWith("data:") && url.indexOf(',') != -1) {
|
||||||
String b64 = url.substring(url.indexOf(',') + 1);
|
String b64 = url.substring(url.indexOf(',') + 1);
|
||||||
byte[] data = Base64.decode(b64, Base64.DEFAULT);
|
byte[] data = Base64.decode(b64, Base64.DEFAULT);
|
||||||
Log.w("tildefriends", "Downloaded " + data.length + " bytes.");
|
log("Downloaded " + data.length + " bytes.");
|
||||||
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||||
try (OutputStream stream = new FileOutputStream(new File(path, file_name))) {
|
try (OutputStream stream = new FileOutputStream(new File(path, file_name))) {
|
||||||
stream.write(data);
|
stream.write(data);
|
||||||
} catch (java.io.IOException e) {
|
} catch (java.io.IOException e) {
|
||||||
Log.w("tildefriends", "IOException: " + e.toString());
|
log("IOException: " + e.toString());
|
||||||
|
}
|
||||||
|
Toast.makeText(getApplicationContext(), "Downloaded File", Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||||
|
request.setMimeType(mime_type);
|
||||||
|
String cookies = CookieManager.getInstance().getCookie(url);
|
||||||
|
request.addRequestHeader("cookie", cookies);
|
||||||
|
request.addRequestHeader("User-Agent", userAgent);
|
||||||
|
request.setDescription("Downloading file...");
|
||||||
|
request.setTitle(file_name);
|
||||||
|
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||||
|
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, content_disposition, mime_type));
|
||||||
|
DownloadManager dm = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
|
||||||
|
dm.enqueue(request);
|
||||||
|
Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
Toast.makeText(getApplicationContext(), "Downloaded File", Toast.LENGTH_LONG).show();
|
|
||||||
} else {
|
|
||||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
|
||||||
request.setMimeType(mime_type);
|
|
||||||
String cookies = CookieManager.getInstance().getCookie(url);
|
|
||||||
request.addRequestHeader("cookie", cookies);
|
|
||||||
request.addRequestHeader("User-Agent", userAgent);
|
|
||||||
request.setDescription("Downloading file...");
|
|
||||||
request.setTitle(file_name);
|
|
||||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
|
||||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, content_disposition, mime_type));
|
|
||||||
DownloadManager dm = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
|
|
||||||
dm.enqueue(request);
|
|
||||||
Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
web_view.setWebChromeClient(new WebChromeClient() {
|
web_view.setWebChromeClient(new WebChromeClient() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
||||||
new AlertDialog.Builder(view.getContext())
|
new AlertDialog.Builder(view.getContext())
|
||||||
.setTitle("Tilde Friends")
|
.setTitle("Tilde Friends")
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
{
|
||||||
result.confirm();
|
public void onClick(DialogInterface dialog, int which)
|
||||||
}
|
{
|
||||||
})
|
result.confirm();
|
||||||
.create()
|
}
|
||||||
.show();
|
})
|
||||||
return true;
|
.create()
|
||||||
}
|
.show();
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
|
|
||||||
new AlertDialog.Builder(view.getContext())
|
|
||||||
.setTitle("Tilde Friends")
|
|
||||||
.setMessage(message)
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.confirm();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create()
|
|
||||||
.show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
|
||||||
EditText input = new EditText(view.getContext());
|
|
||||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
|
||||||
input.setText(defaultValue);
|
|
||||||
|
|
||||||
new AlertDialog.Builder(view.getContext())
|
|
||||||
.setTitle("Tilde Friends")
|
|
||||||
.setMessage(message)
|
|
||||||
.setView(input)
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.confirm(input.getText().toString());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create()
|
|
||||||
.show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** https://stackoverflow.com/questions/5907369/file-upload-in-webview
|
|
||||||
** https://stackoverflow.com/questions/8586691/how-to-open-file-save-dialog-in-android
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> message, WebChromeClient.FileChooserParams params) {
|
|
||||||
upload_message = message;
|
|
||||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
|
||||||
intent.setType("*/*");
|
|
||||||
TildeFriendsActivity.this.startActivityForResult(Intent.createChooser(intent, "File Chooser"), TildeFriendsActivity.FILECHOOSER_RESULT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onConsoleMessage(android.webkit.ConsoleMessage consoleMessage) {
|
|
||||||
Log.d("tildefriends", consoleMessage.message() + " -- From line " + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
web_view.setWebViewClient(new WebViewClient() {
|
|
||||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
|
|
||||||
{
|
|
||||||
if (request.getUrl() != null && request.getUrl().toString().startsWith(base_url)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, request.getUrl()));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
|
||||||
|
new AlertDialog.Builder(view.getContext())
|
||||||
|
.setTitle("Tilde Friends")
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.confirm();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.cancel();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
||||||
|
EditText input = new EditText(view.getContext());
|
||||||
|
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
||||||
|
input.setText(defaultValue);
|
||||||
|
|
||||||
|
new AlertDialog.Builder(view.getContext())
|
||||||
|
.setTitle("Tilde Friends")
|
||||||
|
.setMessage(message)
|
||||||
|
.setView(input)
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.confirm(input.getText().toString());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.cancel();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** https://stackoverflow.com/questions/5907369/file-upload-in-webview
|
||||||
|
** https://stackoverflow.com/questions/8586691/how-to-open-file-save-dialog-in-android
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> message, WebChromeClient.FileChooserParams params) {
|
||||||
|
upload_message = message;
|
||||||
|
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||||
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
intent.setType("*/*");
|
||||||
|
TildeFriendsActivity.this.startActivityForResult(Intent.createChooser(intent, "File Chooser"), TildeFriendsActivity.FILECHOOSER_RESULT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onConsoleMessage(android.webkit.ConsoleMessage consoleMessage) {
|
||||||
|
log(consoleMessage.message() + " -- From line " + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
web_view.setWebViewClient(new WebViewClient() {
|
||||||
|
@Override
|
||||||
|
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
|
||||||
|
{
|
||||||
|
if (request.getUrl() != null && request.getUrl().toString().startsWith(base_url)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, request.getUrl()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageFinished(WebView view, String url) {
|
||||||
|
s_activity.loaded = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
s_activity.create_thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
s_activity = this;
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
log_thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!s_activity.shutting_down) {
|
||||||
|
try {
|
||||||
|
String message = log_queue.take();
|
||||||
|
if (message != null) {
|
||||||
|
android.util.Log.w("tildefriends", message);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log_thread.start();
|
||||||
|
StrictMode.setThreadPolicy(
|
||||||
|
new StrictMode.ThreadPolicy.Builder()
|
||||||
|
.detectAll()
|
||||||
|
//.penaltyDialog()
|
||||||
|
.penaltyLog()
|
||||||
|
.build());
|
||||||
|
StrictMode.setVmPolicy(
|
||||||
|
new StrictMode.VmPolicy.Builder()
|
||||||
|
.detectLeakedClosableObjects()
|
||||||
|
.detectAll()
|
||||||
|
.penaltyLog()
|
||||||
|
.build());
|
||||||
|
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
TextView refresh = (TextView)findViewById(R.id.refresh);
|
TextView refresh = (TextView)findViewById(R.id.refresh);
|
||||||
refresh.setVisibility(View.GONE);
|
refresh.setVisibility(View.GONE);
|
||||||
refresh.setText("REFRESH");
|
refresh.setText("REFRESH");
|
||||||
|
|
||||||
|
final View content = findViewById(android.R.id.content);
|
||||||
|
content.getViewTreeObserver().addOnPreDrawListener(
|
||||||
|
new ViewTreeObserver.OnPreDrawListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw() {
|
||||||
|
if (s_activity.ready && s_activity.loaded) {
|
||||||
|
content.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
create_thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
s_activity.createThread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
create_thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy()
|
protected void onDestroy()
|
||||||
{
|
{
|
||||||
super.onDestroy();
|
try {
|
||||||
|
shutting_down = true;
|
||||||
|
if (log_queue != null) {
|
||||||
|
log_queue.put("Goodbye.");
|
||||||
|
}
|
||||||
|
log_thread.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
log_thread = null;
|
||||||
s_activity = null;
|
s_activity = null;
|
||||||
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -353,46 +437,33 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void set_status(String text) {
|
|
||||||
TextView text_view = (TextView)findViewById(R.id.text);
|
|
||||||
web_view.setVisibility(View.GONE);
|
|
||||||
text_view.setVisibility(View.VISIBLE);
|
|
||||||
text_view.setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hide_status() {
|
|
||||||
TextView text_view = (TextView)findViewById(R.id.text);
|
|
||||||
web_view.setVisibility(View.VISIBLE);
|
|
||||||
text_view.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void start_sandbox(int pipe_fd) {
|
public static void start_sandbox(int pipe_fd) {
|
||||||
Log.w("tildefriends", "starting service with fd: " + pipe_fd);
|
log("starting service with fd: " + pipe_fd);
|
||||||
Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class);
|
Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class);
|
||||||
s_activity.service_connection = new ServiceConnection() {
|
s_activity.service_connection = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
public void onBindingDied(ComponentName name) {
|
public void onBindingDied(ComponentName name) {
|
||||||
Log.w("tildefriends", "onBindingDied");
|
log("onBindingDied");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNullBinding(ComponentName name) {
|
public void onNullBinding(ComponentName name) {
|
||||||
Log.w("tildefriends", "onNullBinding");
|
log("onNullBinding");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||||
Log.w("tildefriends", "onServiceConnected");
|
log("onServiceConnected");
|
||||||
Parcel data = Parcel.obtain();
|
Parcel data = Parcel.obtain();
|
||||||
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(pipe_fd)) {
|
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(pipe_fd)) {
|
||||||
data.writeParcelable(pfd, 0);
|
data.writeParcelable(pfd, 0);
|
||||||
} catch (java.io.IOException e) {
|
} catch (java.io.IOException e) {
|
||||||
Log.w("tildefriends", "IOException: " + e);
|
log("IOException: " + e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
binder.transact(TildeFriendsSandboxService.START_CALL, data, null, IBinder.FLAG_ONEWAY);
|
binder.transact(TildeFriendsSandboxService.START_CALL, data, null, IBinder.FLAG_ONEWAY);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.w("tildefriends", "RemoteException");
|
log("RemoteException");
|
||||||
} finally {
|
} finally {
|
||||||
data.recycle();
|
data.recycle();
|
||||||
}
|
}
|
||||||
@@ -400,14 +471,14 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName name) {
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
Log.w("tildefriends", "onServiceDisconnected");
|
log("onServiceDisconnected");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE);
|
s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void stop_sandbox() {
|
public static void stop_sandbox() {
|
||||||
Log.w("tildefriends", "stop_sandbox");
|
log("stop_sandbox");
|
||||||
if (s_activity.service_connection != null) {
|
if (s_activity.service_connection != null) {
|
||||||
s_activity.unbindService(s_activity.service_connection);
|
s_activity.unbindService(s_activity.service_connection);
|
||||||
s_activity.service_connection = null;
|
s_activity.service_connection = null;
|
||||||
@@ -419,14 +490,11 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
if (port >= 0) {
|
if (port >= 0) {
|
||||||
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
|
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
hide_status();
|
ready = true;
|
||||||
web_view.loadUrl(base_url + "login/auto");
|
web_view.loadUrl(base_url + "login/auto");
|
||||||
});
|
});
|
||||||
|
observer.stopWatching();
|
||||||
observer = null;
|
observer = null;
|
||||||
} else {
|
|
||||||
runOnUiThread(() -> {
|
|
||||||
set_status("Waiting to connect...");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,4 +519,10 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
web_view.getSettings().setDatabasePath(getDatabasePath("webview").getPath());
|
web_view.getSettings().setDatabasePath(getDatabasePath("webview").getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void set_database_enabled()
|
||||||
|
{
|
||||||
|
web_view.getSettings().setDatabaseEnabled(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||