36 Commits

Author SHA1 Message Date
1f2664e5a8 ssb: Reduce redundant work in ssb.following.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m15s
2025-05-11 22:20:16 -04:00
35656a5c34 prettier 2025-05-11 21:54:53 -04:00
799f22e989 ssb: The updated fetch_abouts means that image JSON is now a string we need to handle in tf-user / tf-profile.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m16s
2025-05-11 21:42:48 -04:00
e226a37251 prettier
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 31m40s
2025-05-09 19:54:12 -04:00
8e3bc9d700 ssb: Now add back the about cache, and load times are getting good.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 31m43s
2025-05-09 13:25:05 -04:00
58c3e6c2ab build: Fix a -fanalyze issue in the tests.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 31m32s
2025-05-09 07:55:39 -04:00
0dc148bfea ssb: Don't forget the about info we know as we reload.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 4m53s
2025-05-09 07:35:52 -04:00
3eff1b08a9 ssb: Let about info load in its own time.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 4m45s
2025-05-09 07:27:35 -04:00
02d789471f ssb: Oops, filter on relevant accounts.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 4m33s
2025-05-08 12:58:57 -04:00
d367d47c4d ssb: Switch to a more brute force about-gathering approach. I think if I start with this and avoid querying all known accounts up-front, we will be plenty fast.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 5m12s
2025-05-08 12:39:26 -04:00
c93b8fc045 ssb: Show overall unread status on the hamburger menu.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 4m34s
2025-05-07 19:59:39 -04:00
eb9377e21d ssb: Add settings for broadcast and discovery.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 4m34s
2025-05-07 19:05:57 -04:00
a1764eee42 update: CodeMirror.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 5m16s
2025-05-07 18:37:23 -04:00
86ef74e20d test: More CLI tests, and make -u optional for publish, too.
Some checks failed
Build Tilde Friends / Build-All (push) Failing after 5m11s
2025-05-07 18:31:58 -04:00
4de53b9926 core: sqlite checkpoint tweaks. Switch the periodic checkpoint to passive mode. Truncate mode was painful on mobile. I'm seeing it succeed often enough that we don't grow indefinitely. Also fix the print.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-05-07 18:15:33 -04:00
99a195a3fd update: sqlite 3.49.2. 2025-05-07 18:00:30 -04:00
f1ced31f69 ssb: Faster loads by encouraging the right queries with CTEs in fetch_about.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-05-07 17:52:02 -04:00
b3cedf2baa ssb: Begin to add some CLI tests.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m19s
2025-05-06 12:49:57 -04:00
3bf19fabda ssb: Don't require -u for the private command. #119
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m44s
2025-05-05 21:51:38 -04:00
cf81ebe8ad ssb: emoji-fy other cases of some reactions.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-05-05 21:32:40 -04:00
278b5566a1 ssb: Remove some unintended whitespace at the bottom of messages.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-05-05 21:09:58 -04:00
e8c1390f09 ssb: Reply arrow that shows up better on my phone.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 32m57s
2025-05-01 12:38:11 -04:00
3c04abda45 ssb: More shutdown correctness. #108
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 32m26s
2025-04-30 12:35:40 -04:00
2597f99ccf ssb: Get recent reactions up front so that we don't need to delay showing the dialog for them.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 32m33s
2025-04-29 20:48:47 -04:00
9d3a07c1cf build: OpenBSD 7.7's SSL matches these signatures again.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 32m57s
2025-04-27 17:29:59 -04:00
bdfd8925b5 ssb: Remove some extra margin that slipped in.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 31m13s
2025-04-27 10:18:37 -04:00
1a4d1985f4 core: Revisit drag+drop into the editor. Works better but not as I intended. Use it just to update the screenshot in the welcome app.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-04-27 10:18:20 -04:00
6273f3ea53 ssb: Make the connections sidebar header also a link to the connections tab.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m18s
2025-04-26 18:53:08 -04:00
5bdc6fa471 update: CodeMirror.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-04-26 18:47:04 -04:00
3ba41291db update: QuickJS 2025-04-26.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-04-26 18:30:56 -04:00
0867811952 update: libuv 1.51.0.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m0s
2025-04-26 09:06:37 -04:00
8d961cd805 ssb: Indicate that content warnings can be expanded.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 32m38s
2025-04-24 12:35:36 -04:00
97cea7b40b build: Attempt to include native debug symbols in the Android .aab file.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 32m58s
2025-04-23 20:47:31 -04:00
4106834db8 build: nix flake update did this (but really it was nix --extra-experimental-features nix-command --extra-experimental-features flakes flake update). I don't know how any of this actually works.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 33m7s
2025-04-23 18:36:28 -04:00
a4a8f7cab2 build: Let's start work on 0.0.31.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-04-23 18:33:28 -04:00
9e209ee800 build: nix => 0.0.30. 2025-04-23 18:19:58 -04:00
40 changed files with 759 additions and 454 deletions

View File

@@ -16,14 +16,14 @@ MAKEFLAGS += --no-builtin-rules
## LD := Linker. ## LD := Linker.
## ANDROID_SDK := Path to the Android SDK. ## ANDROID_SDK := Path to the Android SDK.
VERSION_CODE := 35 VERSION_CODE := 37
VERSION_CODE_IOS := 12 VERSION_CODE_IOS := 13
VERSION_NUMBER := 0.0.30 VERSION_NUMBER := 0.0.31-wip
VERSION_NAME := This program kills fascists. VERSION_NAME := This program kills fascists.
IPHONEOS_VERSION_MIN=14.0 IPHONEOS_VERSION_MIN=14.0
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3490100.zip SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3490200.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.17.0/bundletool-all-1.17.0.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
@@ -614,15 +614,16 @@ $(UV_OBJS): CFLAGS += \
-Ideps/libuv/include \ -Ideps/libuv/include \
-Ideps/libuv/src \ -Ideps/libuv/src \
-Wno-dangling-pointer \ -Wno-dangling-pointer \
-Wno-format-truncation \
-Wno-incompatible-pointer-types \ -Wno-incompatible-pointer-types \
-Wno-maybe-uninitialized \ -Wno-maybe-uninitialized \
-Wno-nonnull \
-Wno-sign-compare \ -Wno-sign-compare \
-Wno-unknown-attributes \ -Wno-unknown-attributes \
-Wno-unused-but-set-parameter \ -Wno-unused-but-set-parameter \
-Wno-unused-but-set-variable \ -Wno-unused-but-set-variable \
-Wno-unused-result \ -Wno-unused-result \
-Wno-unused-variable \ -Wno-unused-variable
-Wno-nonnull
$(filter out/win%,$(UV_OBJS)): \ $(filter out/win%,$(UV_OBJS)): \
CFLAGS += \ CFLAGS += \
-Wno-cast-function-type \ -Wno-cast-function-type \
@@ -742,7 +743,7 @@ $(SQLITE_OBJS): CFLAGS += \
QUICKJS_SOURCES := \ QUICKJS_SOURCES := \
deps/quickjs/cutils.c \ deps/quickjs/cutils.c \
deps/quickjs/libbf.c \ deps/quickjs/dtoa.c \
deps/quickjs/libregexp.c \ deps/quickjs/libregexp.c \
deps/quickjs/libunicode.c \ deps/quickjs/libunicode.c \
deps/quickjs/quickjs.c deps/quickjs/quickjs.c
@@ -1015,7 +1016,7 @@ $(BUNDLETOOL):
@curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL) @curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL)
out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL) out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL)
@rm -rf out/aab/staging/ @rm -rf out/aab/staging/ out/aab/base.zip
@mkdir -p out/aab/staging @mkdir -p out/aab/staging
@$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \ @$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk \
-I $(ANDROID_PLATFORM)/android.jar \ -I $(ANDROID_PLATFORM)/android.jar \
@@ -1035,14 +1036,11 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
@cp out/apk/classes.dex out/aab/staging/dex/ @cp out/apk/classes.dex out/aab/staging/dex/
@rm -fv out/base.zip @rm -fv out/base.zip
@mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86 @mkdir -p out/aab/staging/lib/arm64-v8a out/aab/staging/lib/armeabi-v7a out/aab/staging/lib/x86_64 out/aab/staging/lib/x86
@cp out/androidrelease/tildefriends out/aab/staging/lib/arm64-v8a/libtildefriends.so @mkdir -p out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86_64 out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/x86
@cp out/androidrelease-armv7a/tildefriends out/aab/staging/lib/armeabi-v7a/libtildefriends.so @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease/tildefriends -o out/aab/staging/lib/arm64-v8a/libtildefriends.so
@cp out/androidrelease-x86_64/tildefriends out/aab/staging/lib/x86_64/libtildefriends.so @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-armv7a/tildefriends -o out/aab/staging/lib/armeabi-v7a/libtildefriends.so
@cp out/androidrelease-x86/tildefriends out/aab/staging/lib/x86/libtildefriends.so @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-x86_64/tildefriends -o out/aab/staging/lib/x86_64/libtildefriends.so
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/arm64-v8a/libtildefriends.so @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/androidrelease-x86/tildefriends -o out/aab/staging/lib/x86/libtildefriends.so
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/armeabi-v7a/libtildefriends.so
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86_64/libtildefriends.so
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/aab/staging/lib/x86/libtildefriends.so
@cp -r apps/ out/aab/staging/root/ @cp -r apps/ out/aab/staging/root/
@rm -rf out/aab/staging/root/apps/welcome* @rm -rf out/aab/staging/root/apps/welcome*
@cp -r core/ out/aab/staging/root/ @cp -r core/ out/aab/staging/root/
@@ -1051,6 +1049,11 @@ out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGET
@cp -r deps/codemirror/ out/aab/staging/root/deps/ @cp -r deps/codemirror/ out/aab/staging/root/deps/
@cd out/aab/staging/; zip -r ../base.zip *; cd ../../../ @cd out/aab/staging/; zip -r ../base.zip *; cd ../../../
@java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@ @java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/arm64-v8a/libtildefriends.so.sym
@$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip --only-keep-debug out/androidrelease-armv7a/tildefriends -o out/aab/staging/BUNDLE-METADATA/com.android.tools.build.debugsymbols/armeabi-v7a/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
@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) $@
aab: out/TildeFriends.aab ## Build an Android App Bundle. aab: out/TildeFriends.aab ## Build an Android App Bundle.

View File

@@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "🦀", "emoji": "🦀",
"previous": "&Zv/eOewtUPxYuALmYV8v+JDKwH4+aN8zCTYFwB7oYEw=.sha256" "previous": "&Omm/IjiQ9yXgJrDUtXp3q+Qdu9qDLfi05FXI5JtP5Qo=.sha256"
} }

View File

@@ -14,23 +14,8 @@ function get_emojis() {
}); });
} }
async function get_recent(author) { export async function picker(callback, anchor, author, recent) {
let recent = await tfrpc.rpc.query(
`
SELECT DISTINCT content ->> '$.vote.expression' AS value
FROM messages
WHERE author = ? AND
content ->> '$.type' = 'vote'
ORDER BY timestamp DESC LIMIT 10
`,
[author]
);
return recent.map((x) => x.value);
}
export async function picker(callback, anchor, author) {
let json = await get_emojis(); let json = await get_emojis();
let recent = await get_recent(author);
let div = document.createElement('div'); let div = document.createElement('div');
div.id = 'emoji_picker'; div.id = 'emoji_picker';

View File

@@ -21,6 +21,7 @@ class TfElement extends LitElement {
guest: {type: Boolean}, guest: {type: Boolean},
url: {type: String}, url: {type: String},
private_messages: {type: Array}, private_messages: {type: Array},
recent_reactions: {type: Array},
}; };
} }
@@ -41,6 +42,7 @@ class TfElement extends LitElement {
this.channels_latest = {}; this.channels_latest = {};
this.loading_latest = 0; this.loading_latest = 0;
this.loading_latest_scheduled = 0; this.loading_latest_scheduled = 0;
this.recent_reactions = [];
tfrpc.rpc.getBroadcasts().then((b) => { tfrpc.rpc.getBroadcasts().then((b) => {
self.broadcasts = b || []; self.broadcasts = b || [];
}); });
@@ -150,7 +152,7 @@ class TfElement extends LitElement {
async fetch_about(following, users) { async fetch_about(following, users) {
let ids = Object.keys(following).sort(); let ids = Object.keys(following).sort();
const k_cache_version = 1; const k_cache_version = 2;
let cache = await tfrpc.rpc.databaseGet('about'); let cache = await tfrpc.rpc.databaseGet('about');
let original_cache = cache; let original_cache = cache;
cache = cache ? JSON.parse(cache) : {}; cache = cache ? JSON.parse(cache) : {};
@@ -158,116 +160,82 @@ class TfElement extends LitElement {
cache = { cache = {
version: k_cache_version, version: k_cache_version,
about: {}, about: {},
last_row_id: 0,
}; };
} }
let max_row_id = (
await tfrpc.rpc.query(
`
SELECT MAX(rowid) AS max_row_id FROM messages
`,
[]
)
)[0].max_row_id;
for (let id of Object.keys(cache.about)) { for (let id of Object.keys(cache.about)) {
if (ids.indexOf(id) == -1) { if (ids.indexOf(id) == -1) {
delete cache.about[id]; delete cache.about[id];
} else {
users[id] = Object.assign(users[id] || {}, cache.about[id]);
} }
} }
const k_chunk_size = 1024; let ids_out_of_date = ids.filter(
let min_row_id = 0; (x) =>
cache.about[x]?.seq === undefined ||
(users[x]?.seq && users[x]?.seq > cache.about[x].seq)
);
console.log( console.log(
'loading about for', 'loading about for',
ids.length, ids.length,
'accounts', 'accounts',
cache.last_row_id, ids_out_of_date.length,
'=>', 'out of date'
max_row_id
); );
if (ids_out_of_date.length) {
try { try {
while (true) { let rows = await tfrpc.rpc.query(
let abouts = await tfrpc.rpc.query(
` `
SELECT * FROM ( SELECT all_abouts.author, json(json_group_object(all_abouts.key, all_abouts.value)) AS about
FROM (
SELECT SELECT
messages.rowid AS rowid, messages.author, json(messages.content) AS content, messages.sequence messages.author,
FROM fields.key,
messages, RANK() OVER (PARTITION BY messages.author, fields.key ORDER BY messages.sequence DESC) AS rank,
json_each(?1) AS following fields.value
FROM messages JOIN json_each(messages.content) AS fields
WHERE WHERE
messages.author = following.value AND messages.content ->> '$.type' = 'about' AND
messages.content ->> 'type' = 'about' AND messages.content ->> '$.about' = messages.author AND
messages.rowid > ?3 AND NOT fields.key IN ('about', 'type')) all_abouts
messages.rowid <= ?4 JOIN json_each(?) AS following ON all_abouts.author = following.value
UNION WHERE rank = 1
SELECT GROUP BY all_abouts.author
messages.rowid AS rowid, messages.author, json(messages.content) AS content, messages.sequence
FROM
messages,
json_each(?2) AS following
WHERE
messages.author = following.value AND
messages.content ->> 'type' = 'about' AND
messages.rowid > ?6 AND
messages.rowid <= ?4
)
ORDER BY rowid LIMIT ?5
`, `,
[ [JSON.stringify(ids_out_of_date)]
JSON.stringify(ids.filter((id) => cache.about[id])),
JSON.stringify(ids.filter((id) => !cache.about[id])),
cache.last_row_id,
max_row_id,
k_chunk_size,
min_row_id,
]
); );
let max_seen; users = users || {};
for (let about of abouts) { for (let row of rows) {
let content = JSON.parse(about.content); users[row.author] = Object.assign(
if (content.about === about.author) { users[row.author] || {},
delete content.type; JSON.parse(row.about)
delete content.about; );
cache.about[about.author] = Object.assign( cache.about[row.author] = Object.assign(
cache.about[about.author] || {}, {seq: users[row.author].seq},
content JSON.parse(row.about)
); );
} }
max_seen = about.rowid; } catch (e) {
console.log(e);
} }
console.log( }
'cache =',
cache.last_row_id, for (let id of ids_out_of_date) {
'seen =', if (!cache.about[id]?.seq) {
max_seen, cache.about[id] = {seq: users[id]?.seq ?? 0};
'max =', }
max_row_id }
);
cache.last_row_id = Math.max(cache.last_row_id, max_seen ?? max_row_id);
min_row_id = Math.max(min_row_id, max_seen ?? max_row_id);
let new_cache = JSON.stringify(cache); let new_cache = JSON.stringify(cache);
if (new_cache !== original_cache) { if (new_cache != original_cache) {
let start_time = new Date(); let start_time = new Date();
tfrpc.rpc.databaseSet('about', new_cache).then(function () { tfrpc.rpc.databaseSet('about', new_cache).then(function () {
console.log('saving about took', (new Date() - start_time) / 1000); console.log('saving about took', (new Date() - start_time) / 1000);
}); });
} }
users = users || {};
for (let id of Object.keys(cache.about)) {
users[id] = Object.assign(
{follow_depth: following[id]?.d},
users[id] || {},
cache.about[id]
);
}
if (cache.last_row_id >= max_row_id) {
break;
}
}
} catch (e) {
console.log(e);
}
return Object.assign({}, users); return Object.assign({}, users);
} }
@@ -446,43 +414,61 @@ class TfElement extends LitElement {
[JSON.stringify(Object.keys(users))] [JSON.stringify(Object.keys(users))]
); );
for (let row of info) { for (let row of info) {
users[row.author].seq = row.max_seq; users[row.author] = Object.assign(
users[row.author].ts = row.max_ts; {
seq: row.max_sequence,
ts: row.max_ts,
},
users[row.author]
);
} }
return users; return users;
} }
async load_recent_reactions() {
this.recent_reactions = (
await tfrpc.rpc.query(
`
SELECT DISTINCT content ->> '$.vote.expression' AS value
FROM messages
WHERE author = ? AND
content ->> '$.type' = 'vote'
ORDER BY timestamp DESC LIMIT 10
`,
[this.whoami]
)
).map((x) => x.value);
}
async load() { async load() {
this.loading_latest = true; this.loading_latest = true;
try { try {
let start_time = new Date(); let start_time = new Date();
let whoami = this.whoami; let whoami = this.whoami;
let following = await tfrpc.rpc.following([whoami], 2); let following = await tfrpc.rpc.following([whoami], 2);
let old_users = this.users ?? {};
let users = {}; let users = {};
let by_count = []; let by_count = [];
for (let [id, v] of Object.entries(following)) { for (let [id, v] of Object.entries(following)) {
users[id] = { users[id] = Object.assign(
{
following: v.of, following: v.of,
blocking: v.ob, blocking: v.ob,
followed: v.if, followed: v.if,
blocked: v.ib, blocked: v.ib,
}; follow_depth: following[id]?.d,
},
old_users[id]
);
by_count.push({count: v.of, id: id}); by_count.push({count: v.of, id: id});
} }
let reactions = this.load_recent_reactions();
this.load_channels_latest(Object.keys(following)); this.load_channels_latest(Object.keys(following));
this.channels_unread = JSON.parse( this.channels_unread = JSON.parse(
(await tfrpc.rpc.databaseGet('unread')) ?? '{}' (await tfrpc.rpc.databaseGet('unread')) ?? '{}'
); );
this.following = Object.keys(following); this.following = Object.keys(following);
let about_start_time = new Date(); let about_start_time = new Date();
users = await this.fetch_about(following, users);
console.log(
'about took',
(new Date() - about_start_time) / 1000.0,
'seconds for',
Object.keys(users).length,
'users'
);
start_time = new Date(); start_time = new Date();
users = await this.fetch_user_info(users); users = await this.fetch_user_info(users);
console.log( console.log(
@@ -491,9 +477,22 @@ class TfElement extends LitElement {
'seconds' 'seconds'
); );
this.users = users; this.users = users;
let self = this;
this.fetch_about(following, users).then(function (result) {
self.users = result;
console.log(
'about took',
(new Date() - about_start_time) / 1000.0,
'seconds for',
Object.keys(users).length,
'users'
);
});
console.log( console.log(
`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}` `load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
); );
await reactions;
this.whoami = whoami; this.whoami = whoami;
this.loaded = whoami; this.loaded = whoami;
} finally { } finally {
@@ -551,6 +550,7 @@ class TfElement extends LitElement {
@channelsetunread=${this.channel_set_unread} @channelsetunread=${this.channel_set_unread}
.connections=${this.connections} .connections=${this.connections}
.private_messages=${this.private_messages} .private_messages=${this.private_messages}
.recent_reactions=${this.recent_reactions}
></tf-tab-news> ></tf-tab-news>
`; `;
} else if (this.tab === 'connections') { } else if (this.tab === 'connections') {

View File

@@ -16,6 +16,7 @@ class TfMessageElement extends LitElement {
expanded: {type: Object}, expanded: {type: Object},
channel: {type: String}, channel: {type: String},
channel_unread: {type: Number}, channel_unread: {type: Number},
recent_reactions: {type: Array},
}; };
} }
@@ -31,6 +32,7 @@ class TfMessageElement extends LitElement {
this.format = 'message'; this.format = 'message';
this.expanded = {}; this.expanded = {};
this.channel_unread = -1; this.channel_unread = -1;
this.recent_reactions = [];
} }
connectedCallback() { connectedCallback() {
@@ -84,9 +86,9 @@ class TfMessageElement extends LitElement {
render_votes() { render_votes() {
function normalize_expression(expression) { function normalize_expression(expression) {
if (expression === 'Like' || !expression) { if (expression === 'Like' || expression === 'like' || !expression) {
return '👍'; return '👍';
} else if (expression === 'Unlike') { } else if (expression === 'Unlike' || expression === 'unlike') {
return '👎'; return '👎';
} else if (expression === 'heart') { } else if (expression === 'heart') {
return '❤️'; return '❤️';
@@ -95,9 +97,10 @@ class TfMessageElement extends LitElement {
} }
} }
if (this.message?.votes?.length) { if (this.message?.votes?.length) {
return html` <div class="w3-container"> return html` <footer class="w3-container">
<div <div
class="w3-button w3-bar w3-padding-small" class="w3-button w3-bar"
style="padding: 0"
@click=${this.show_reactions} @click=${this.show_reactions}
> >
${(this.message.votes || []).map( ${(this.message.votes || []).map(
@@ -112,7 +115,7 @@ class TfMessageElement extends LitElement {
` `
)} )}
</div> </div>
</div>`; </footer>`;
} }
} }
@@ -155,7 +158,12 @@ class TfMessageElement extends LitElement {
} }
react(event) { react(event) {
emojis.picker((x) => this.vote(x), null, this.whoami); emojis.picker(
(x) => this.vote(x),
null,
this.whoami,
this.recent_reactions
);
} }
show_image(link) { show_image(link) {
@@ -306,6 +314,10 @@ class TfMessageElement extends LitElement {
); );
} }
is_expanded(tag) {
return this.expanded[(this.message.id || '') + (tag || '')];
}
render_children() { render_children() {
let self = this; let self = this;
if (this.message.child_messages?.length) { if (this.message.child_messages?.length) {
@@ -333,6 +345,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}
.recent_reactions=${this.recent_reactions}
></tf-message>` ></tf-message>`
)} )}
</div> </div>
@@ -441,7 +454,7 @@ class TfMessageElement extends LitElement {
${this.drafts[this.message?.id] === undefined ${this.drafts[this.message?.id] === undefined
? html` ? html`
<button class="w3-button w3-bar-item" @click=${this.show_reply}> <button class="w3-button w3-bar-item" @click=${this.show_reply}>
Reply ↩️ Reply
</button> </button>
` `
: undefined} : undefined}
@@ -529,6 +542,7 @@ class TfMessageElement extends LitElement {
.expanded=${self.expanded} .expanded=${self.expanded}
channel=${self.channel} channel=${self.channel}
channel_unread=${self.channel_unread} channel_unread=${self.channel_unread}
.recent_reactions=${self.recent_reactions}
></tf-message> ></tf-message>
` `
)} )}
@@ -540,6 +554,7 @@ class TfMessageElement extends LitElement {
let reply = let reply =
this.drafts[this.message?.id] !== undefined this.drafts[this.message?.id] !== undefined
? html` ? html`
<div class="w3-section w3-container">
<tf-compose <tf-compose
whoami=${this.whoami} whoami=${this.whoami}
.users=${this.users} .users=${this.users}
@@ -548,11 +563,13 @@ class TfMessageElement extends LitElement {
.drafts=${this.drafts} .drafts=${this.drafts}
@tf-discard=${this.discard_reply} @tf-discard=${this.discard_reply}
author=${this.message.author} author=${this.message.author}
.recent_reactions=${this.recent_reactions}
></tf-compose> ></tf-compose>
</div>
` `
: undefined; : undefined;
return html` return html`
<div class="w3-section w3-container">${reply}</div> ${reply}
<footer>${this.render_children()}</footer> <footer>${this.render_children()}</footer>
`; `;
} }
@@ -678,11 +695,14 @@ class TfMessageElement extends LitElement {
} }
let content_warning = html` let content_warning = html`
<div <div
class="w3-panel w3-round-xlarge w3-theme-l4" class="w3-panel w3-round-xlarge w3-theme-l4 w3"
style="cursor: pointer" style="cursor: pointer"
@click=${(x) => this.toggle_expanded(':cw')} @click=${(x) => this.toggle_expanded(':cw')}
> >
<p>${content.contentWarning}</p> <p>${content.contentWarning}</p>
<p class="w3-small">
${this.is_expanded(':cw') ? 'Show less' : 'Show more'}
</p>
</div> </div>
`; `;
let content_html = html` let content_html = html`

View File

@@ -13,6 +13,7 @@ class TfNewsElement extends LitElement {
expanded: {type: Object}, expanded: {type: Object},
channel: {type: String}, channel: {type: String},
channel_unread: {type: Number}, channel_unread: {type: Number},
recent_reactions: {type: Array},
}; };
} }
@@ -28,6 +29,7 @@ class TfNewsElement extends LitElement {
this.drafts = {}; this.drafts = {};
this.expanded = {}; this.expanded = {};
this.channel_unread = -1; this.channel_unread = -1;
this.recent_reactions = [];
} }
process_messages(messages) { process_messages(messages) {
@@ -211,6 +213,7 @@ class TfNewsElement extends LitElement {
collapsed="true" collapsed="true"
channel=${this.channel} channel=${this.channel}
channel_unread=${this.channel_unread} channel_unread=${this.channel_unread}
.recent_reactions=${this.recent_reactions}
></tf-message> ></tf-message>
${x.rowid == unread_rowid ${x.rowid == unread_rowid
? html`<div style="display: flex; flex-direction: row"> ? html`<div style="display: flex; flex-direction: row">

View File

@@ -242,8 +242,12 @@ class TfProfileElement extends LitElement {
</div> </div>
</div>` </div>`
: null; : null;
let image = let image = profile.image;
typeof profile.image == 'string' ? profile.image : profile.image?.link; if (typeof image == 'string' && !image.startsWith('&')) {
try {
image = JSON.parse(image)?.link;
} catch {}
}
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`<div class="w3-card-4 w3-container w3-theme-d3" style="box-sizing: border-box">

View File

@@ -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},
recent_reactions: {type: Array},
}; };
} }
@@ -37,6 +38,7 @@ class TfTabNewsFeedElement extends LitElement {
this.start_time = new Date().valueOf(); this.start_time = new Date().valueOf();
this.time_range = [0, 0]; this.time_range = [0, 0];
this.time_loading = undefined; this.time_loading = undefined;
this.recent_reactions = [];
this.loading = 0; this.loading = 0;
} }
@@ -452,6 +454,7 @@ class TfTabNewsFeedElement extends LitElement {
.expanded=${this.expanded} .expanded=${this.expanded}
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}
></tf-news> ></tf-news>
${more} ${more}
`); `);

View File

@@ -24,6 +24,7 @@ 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},
recent_reactions: {type: Array},
}; };
} }
@@ -43,6 +44,7 @@ class TfTabNewsElement extends LitElement {
this.channels_latest = {}; this.channels_latest = {};
this.channels = []; this.channels = [];
this.connections = []; this.connections = [];
this.recent_reactions = [];
tfrpc.rpc.localStorageGet('drafts').then(function (d) { tfrpc.rpc.localStorageGet('drafts').then(function (d) {
self.drafts = JSON.parse(d || '{}'); self.drafts = JSON.parse(d || '{}');
}); });
@@ -95,7 +97,13 @@ class TfTabNewsElement extends LitElement {
} }
unread_status(channel) { unread_status(channel) {
if (channel === undefined) {
if ( if (
Object.keys(this.channels_unread).some((x) => this.unread_status(x))
) {
return '✉️ ';
}
} else if (
this.channels_latest[channel] && this.channels_latest[channel] &&
this.channels_latest[channel] > 0 && this.channels_latest[channel] > 0 &&
(this.channels_unread[channel] === undefined || (this.channels_unread[channel] === undefined ||
@@ -223,7 +231,9 @@ class TfTabNewsElement extends LitElement {
` `
)} )}
<h4 class="w3-bar-item w3-theme-d2">Connections</h4> <a class="w3-bar-item w3-theme-d2 w3-button" href="#connections">
<h4 style="margin: 0">Connections</h4>
</a>
${this.connections ${this.connections
.filter((x) => x.id && !x.destroy_reason) .filter((x) => x.id && !x.destroy_reason)
.map( .map(
@@ -311,7 +321,7 @@ class TfTabNewsElement extends LitElement {
class="w3-button w3-hide-large" class="w3-button w3-hide-large"
@click=${this.show_sidebar} @click=${this.show_sidebar}
> >
&#9776; ${this.unread_status()}&#9776;
</div> </div>
Welcome, <tf-user id=${this.whoami} .users=${this.users}></tf-user>! Welcome, <tf-user id=${this.whoami} .users=${this.users}></tf-user>!
${edit_profile} ${edit_profile}
@@ -340,6 +350,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}
.recent_reactions=${this.recent_reactions}
></tf-tab-news-feed> ></tf-tab-news-feed>
</div> </div>
</div> </div>

View File

@@ -38,8 +38,11 @@ class TfUserElement extends LitElement {
if (user) { if (user) {
let image_link = user.image; let image_link = user.image;
image_link = if (typeof image_link == 'string' && !image_link.startsWith('&')) {
typeof image_link == 'string' ? image_link : image_link?.link; try {
image_link = JSON.parse(image_link)?.link;
} catch {}
}
if (image_link !== undefined) { if (image_link !== undefined) {
image = html`<img image = html`<img
class=${'w3-theme-l4 ' + shape} class=${'w3-theme-l4 ' + shape}

View File

@@ -1,5 +1,5 @@
{ {
"type": "tildefriends-app", "type": "tildefriends-app",
"emoji": "👋", "emoji": "👋",
"previous": "&wAb7J6E35xEXpiXsQ6t1RaWTGIvlatUnyH8ipF6pVic=.sha256" "previous": "&1o8MrBHfH42NnO+ruajwCmW/DUCb+IT1qtnAZI/agyo=.sha256"
} }

View File

@@ -45,6 +45,11 @@
<i class="fa fa-mobile-screen w3-xlarge"></i> <i class="fa fa-mobile-screen w3-xlarge"></i>
<i class="fa-brands fa-windows w3-xlarge"></i> <i class="fa-brands fa-windows w3-xlarge"></i>
</p> </p>
<a
class="w3-button w3-blue w3-padding-large"
href="https://www.tildefriends.net/~core/ssb/"
>🦀 Try It</a
>
<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/releases" href="https://dev.tildefriends.net/cory/tildefriends/releases"
@@ -52,12 +57,7 @@
> >
<a <a
class="w3-button w3-black w3-padding-large" class="w3-button w3-black w3-padding-large"
href="https://www.tildefriends.net/~core/ssb/" href="https://dev.tildefriends.net/cory/tildefriends"
><i class="fa fa-link"></i> Try It</a
>
<a
class="w3-button w3-black w3-padding-large"
href="https://dev.tildefriends.net/"
><i class="fa fa-mug-hot"></i> Development</a ><i class="fa fa-mug-hot"></i> Development</a
> >
<a <a
@@ -65,6 +65,11 @@
href="https://docs.tildefriends.net/" href="https://docs.tildefriends.net/"
><i class="fa fa-book"></i> Documentation</a ><i class="fa fa-book"></i> Documentation</a
> >
<a
class="w3-button w3-black w3-padding-large"
href="https://www.tildefriends.net/~cory/tildeblog/"
><i class="fa fa-solid fa-square-rss"></i> Blog</a
>
<p> <p>
<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"
@@ -86,6 +91,13 @@
<img src="googleplay.svg" style="height: 2em; margin: 0" /> <img src="googleplay.svg" style="height: 2em; margin: 0" />
Get it on Google Play (Open Testing) Get it on Google Play (Open Testing)
</a> </a>
<a
class="w3-button w3-round-large w3-padding w3-blue-gray w3-margin-top"
href="https://testflight.apple.com/join/tXxgtSpE"
>
<img src="ios.svg" style="height: 2em; margin: 0" />
Get it on iOS (TestFlight)
</a>
</p> </p>
</div> </div>
<div class="w3-col l4 m6"> <div class="w3-col l4 m6">

3
apps/welcome/ios.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="814" height="1000">
<path d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

View File

@@ -1,4 +1,4 @@
/* W3.CSS 5.01 March 14 2025 by Jan Egil and Borge Refsnes */ /* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit} html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */ /* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
@@ -108,10 +108,6 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px} .w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px} .w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px} .w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px} .w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word} .w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%} .w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
@@ -153,9 +149,9 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important} .w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
.w3-hover-none:hover{box-shadow:none!important} .w3-hover-none:hover{box-shadow:none!important}
/* Colors */ /* Colors */
.w3-amber,.w3-hover-amber:hover,.w3-warning{color:#000!important;background-color:#ffc107!important} .w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important} .w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
.w3-blue,.w3-hover-blue:hover,.w3-info,.w3-primary{color:#fff!important;background-color:#2196F3!important} .w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important} .w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important} .w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important} .w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
@@ -170,24 +166,15 @@ hr{border:0;border-top:1px solid #eee;margin:20px 0}
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important} .w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important} .w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important} .w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
.w3-red,.w3-hover-red:hover,.w3-danger{color:#fff!important;background-color:#f44336!important} .w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important} .w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important} .w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
.w3-yellow,.w3-hover-yellow:hover,.w3-note{color:#000!important;background-color:#ffeb3b!important} .w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important} .w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important} .w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover,.w3-secondary{color:#000!important;background-color:#9e9e9e!important}
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important} .w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important} .w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
.w3-emerald,.w3-hover-emerald:hover,.w3-success{color:#fff!important;background-color:#008a00!important}
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important} .w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important} .w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important} .w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}

View File

@@ -411,6 +411,7 @@ class TfFilesElement extends LitElement {
current: {type: String}, current: {type: String},
files: {type: Object}, files: {type: Object},
dropping: {type: Number}, dropping: {type: Number},
drop_target: {type: String},
}; };
} }
@@ -449,6 +450,9 @@ class TfFilesElement extends LitElement {
if (!this.files[file].clean) { if (!this.files[file].clean) {
classes.push('dirty'); classes.push('dirty');
} }
if (this.drop_target == file) {
classes.push('drop');
}
return html`<div return html`<div
class="${classes.join(' ')}" class="${classes.join(' ')}"
@click=${(x) => this.file_click(file)} @click=${(x) => this.file_click(file)}
@@ -465,11 +469,12 @@ class TfFilesElement extends LitElement {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.dropping = 0; this.dropping = 0;
this.drop_target = undefined;
for (let file of event.dataTransfer.files) { for (let file of event.dataTransfer.files) {
let buffer = await file.arrayBuffer(); let buffer = await file.arrayBuffer();
let text = new TextDecoder('latin1').decode(buffer); let text = new TextDecoder('latin1').decode(buffer);
gFiles[file.name] = { gFiles[file.name] = {
doc: new cm6.EditorState.create({ doc: cm6.EditorState.create({
doc: text, doc: text,
extensions: cm6.extensions, extensions: cm6.extensions,
}), }),
@@ -488,6 +493,7 @@ class TfFilesElement extends LitElement {
*/ */
drag_enter(event) { drag_enter(event) {
this.dropping++; this.dropping++;
this.drop_target = event.srcElement.innerText.trim();
event.preventDefault(); event.preventDefault();
} }
@@ -497,6 +503,13 @@ class TfFilesElement extends LitElement {
*/ */
drag_leave(event) { drag_leave(event) {
this.dropping--; this.dropping--;
if (this.dropping == 0) {
this.drop_target = undefined;
}
}
drag_over(event) {
event.preventDefault();
} }
/** /**
@@ -523,6 +536,10 @@ class TfFilesElement extends LitElement {
background-color: #2aa198; background-color: #2aa198;
} }
div.file.drop {
border: 4px solid red;
}
div.file.dirty::after { div.file.dirty::after {
content: '*'; content: '*';
} }
@@ -531,20 +548,12 @@ class TfFilesElement extends LitElement {
@drop=${this.drop} @drop=${this.drop}
@dragenter=${this.drag_enter} @dragenter=${this.drag_enter}
@dragleave=${this.drag_leave} @dragleave=${this.drag_leave}
@dragover=${this.drag_over}
> >
${Object.keys(this.files) ${Object.keys(this.files)
.sort() .sort()
.map((x) => self.render_file(x))} .map((x) => self.render_file(x))}
</div> </div>
<div
?hidden=${this.dropping == 0}
@drop=${this.drop}
@dragenter=${this.drag_enter}
@dragleave=${this.drag_leave}
style="text-align: center; vertical-align: middle; outline: 16px solid red; margin: -8px; background-color: rgba(255, 0, 0, 0.5); position: absolute; left: 16px; top: 16px; width: calc(100% - 16px); height: calc(100% - 16px); z-index: 1000"
>
Drop File(s)
</div>
`; `;
} }
} }

View File

@@ -25,14 +25,14 @@
}: }:
pkgs.stdenv.mkDerivation rec { pkgs.stdenv.mkDerivation rec {
pname = "tildefriends"; pname = "tildefriends";
version = "0.0.29"; version = "0.0.30";
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-bQXFpocOYOlFmVj9OZeQhNrgFuTJ8sx2RSw1tgmelOM="; hash = "sha256-t5yvouzSL2j/ge1VHLqzIZ+Avqj4iEDt7L+yrHoTZAQ=";
fetchSubmodules = true; fetchSubmodules = true;
}; };

File diff suppressed because one or more lines are too long

172
deps/codemirror_src/package-lock.json generated vendored
View File

@@ -144,9 +144,9 @@
} }
}, },
"node_modules/@codemirror/view": { "node_modules/@codemirror/view": {
"version": "6.36.5", "version": "6.36.7",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.5.tgz", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.36.7.tgz",
"integrity": "sha512-cd+FZEUlu3GQCYnguYm3EkhJ8KJVisqqUsCOKedBoAt/d9c76JUUap6U0UrpElln5k6VyrEOYliMuDAKIeDQLg==", "integrity": "sha512-kCWGW/chWGPgZqfZ36Um9Iz0X2IVpmCjg1P/qY6B6a2ecXtWRRAigmpJ6YgUQ5lTWXMyyVdfmpzhLZmsZQMbtg==",
"dependencies": { "dependencies": {
"@codemirror/state": "^6.5.0", "@codemirror/state": "^6.5.0",
"style-mod": "^4.1.0", "style-mod": "^4.1.0",
@@ -344,9 +344,9 @@
} }
}, },
"node_modules/@rollup/rollup-android-arm-eabi": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.2.tgz",
"integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", "integrity": "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -356,9 +356,9 @@
] ]
}, },
"node_modules/@rollup/rollup-android-arm64": { "node_modules/@rollup/rollup-android-arm64": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.2.tgz",
"integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", "integrity": "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -368,9 +368,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-arm64": { "node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.2.tgz",
"integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", "integrity": "sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -380,9 +380,9 @@
] ]
}, },
"node_modules/@rollup/rollup-darwin-x64": { "node_modules/@rollup/rollup-darwin-x64": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.2.tgz",
"integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", "integrity": "sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -392,9 +392,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-arm64": { "node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.2.tgz",
"integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", "integrity": "sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -404,9 +404,9 @@
] ]
}, },
"node_modules/@rollup/rollup-freebsd-x64": { "node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.2.tgz",
"integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", "integrity": "sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -416,9 +416,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-gnueabihf": { "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.2.tgz",
"integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", "integrity": "sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -428,9 +428,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm-musleabihf": { "node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.2.tgz",
"integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", "integrity": "sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -440,9 +440,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-gnu": { "node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.2.tgz",
"integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", "integrity": "sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -452,9 +452,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-arm64-musl": { "node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.2.tgz",
"integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", "integrity": "sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -464,9 +464,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-loongarch64-gnu": { "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.2.tgz",
"integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", "integrity": "sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@@ -476,9 +476,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.2.tgz",
"integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", "integrity": "sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -488,9 +488,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-gnu": { "node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.2.tgz",
"integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", "integrity": "sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -500,9 +500,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-riscv64-musl": { "node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.2.tgz",
"integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", "integrity": "sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@@ -512,9 +512,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-s390x-gnu": { "node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.2.tgz",
"integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", "integrity": "sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -524,9 +524,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-gnu": { "node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz",
"integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -536,9 +536,9 @@
] ]
}, },
"node_modules/@rollup/rollup-linux-x64-musl": { "node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.2.tgz",
"integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", "integrity": "sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -548,9 +548,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-arm64-msvc": { "node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.2.tgz",
"integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", "integrity": "sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -560,9 +560,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-ia32-msvc": { "node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.2.tgz",
"integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", "integrity": "sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -572,9 +572,9 @@
] ]
}, },
"node_modules/@rollup/rollup-win32-x64-msvc": { "node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.2.tgz",
"integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", "integrity": "sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -745,9 +745,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "4.40.0", "version": "4.40.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.2.tgz",
"integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", "integrity": "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==",
"dependencies": { "dependencies": {
"@types/estree": "1.0.7" "@types/estree": "1.0.7"
}, },
@@ -759,26 +759,26 @@
"npm": ">=8.0.0" "npm": ">=8.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.40.0", "@rollup/rollup-android-arm-eabi": "4.40.2",
"@rollup/rollup-android-arm64": "4.40.0", "@rollup/rollup-android-arm64": "4.40.2",
"@rollup/rollup-darwin-arm64": "4.40.0", "@rollup/rollup-darwin-arm64": "4.40.2",
"@rollup/rollup-darwin-x64": "4.40.0", "@rollup/rollup-darwin-x64": "4.40.2",
"@rollup/rollup-freebsd-arm64": "4.40.0", "@rollup/rollup-freebsd-arm64": "4.40.2",
"@rollup/rollup-freebsd-x64": "4.40.0", "@rollup/rollup-freebsd-x64": "4.40.2",
"@rollup/rollup-linux-arm-gnueabihf": "4.40.0", "@rollup/rollup-linux-arm-gnueabihf": "4.40.2",
"@rollup/rollup-linux-arm-musleabihf": "4.40.0", "@rollup/rollup-linux-arm-musleabihf": "4.40.2",
"@rollup/rollup-linux-arm64-gnu": "4.40.0", "@rollup/rollup-linux-arm64-gnu": "4.40.2",
"@rollup/rollup-linux-arm64-musl": "4.40.0", "@rollup/rollup-linux-arm64-musl": "4.40.2",
"@rollup/rollup-linux-loongarch64-gnu": "4.40.0", "@rollup/rollup-linux-loongarch64-gnu": "4.40.2",
"@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2",
"@rollup/rollup-linux-riscv64-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-gnu": "4.40.2",
"@rollup/rollup-linux-riscv64-musl": "4.40.0", "@rollup/rollup-linux-riscv64-musl": "4.40.2",
"@rollup/rollup-linux-s390x-gnu": "4.40.0", "@rollup/rollup-linux-s390x-gnu": "4.40.2",
"@rollup/rollup-linux-x64-gnu": "4.40.0", "@rollup/rollup-linux-x64-gnu": "4.40.2",
"@rollup/rollup-linux-x64-musl": "4.40.0", "@rollup/rollup-linux-x64-musl": "4.40.2",
"@rollup/rollup-win32-arm64-msvc": "4.40.0", "@rollup/rollup-win32-arm64-msvc": "4.40.2",
"@rollup/rollup-win32-ia32-msvc": "4.40.0", "@rollup/rollup-win32-ia32-msvc": "4.40.2",
"@rollup/rollup-win32-x64-msvc": "4.40.0", "@rollup/rollup-win32-x64-msvc": "4.40.2",
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },

2
deps/libuv vendored

Submodule deps/libuv updated: 8fb9cb9194...5152db2cbf

2
deps/quickjs vendored

49
deps/sqlite/shell.c vendored
View File

@@ -6267,8 +6267,7 @@ int sqlite3_ieee_init(
** step HIDDEN ** step HIDDEN
** ); ** );
** **
** The virtual table also has a rowid, logically equivalent to n+1 where ** The virtual table also has a rowid which is an alias for the value.
** "n" is the ascending integer in the aforesaid production definition.
** **
** Function arguments in queries against this virtual table are translated ** Function arguments in queries against this virtual table are translated
** into equality constraints against successive hidden columns. In other ** into equality constraints against successive hidden columns. In other
@@ -6323,6 +6322,7 @@ SQLITE_EXTENSION_INIT1
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
#include <math.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE
/* /*
@@ -6483,6 +6483,7 @@ static int seriesConnect(
int rc; int rc;
/* Column numbers */ /* Column numbers */
#define SERIES_COLUMN_ROWID (-1)
#define SERIES_COLUMN_VALUE 0 #define SERIES_COLUMN_VALUE 0
#define SERIES_COLUMN_START 1 #define SERIES_COLUMN_START 1
#define SERIES_COLUMN_STOP 2 #define SERIES_COLUMN_STOP 2
@@ -6570,13 +6571,11 @@ static int seriesColumn(
#endif #endif
/* /*
** Return the rowid for the current row, logically equivalent to n+1 where ** The rowid is the same as the value.
** "n" is the ascending integer in the aforesaid production definition.
*/ */
static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
series_cursor *pCur = (series_cursor*)cur; series_cursor *pCur = (series_cursor*)cur;
sqlite3_uint64 n = pCur->ss.uSeqIndexNow; *pRowid = pCur->ss.iValueNow;
*pRowid = (sqlite3_int64)((n<LARGEST_UINT64)? n+1 : 0);
return SQLITE_OK; return SQLITE_OK;
} }
@@ -6689,9 +6688,26 @@ static int seriesFilter(
** constraints on the "value" column. ** constraints on the "value" column.
*/ */
if( idxNum & 0x0080 ){ if( idxNum & 0x0080 ){
if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[i++]);
if( r==ceil(r) ){
iMin = iMax = (sqlite3_int64)r;
}else{
returnNoRows = 1;
}
}else{
iMin = iMax = sqlite3_value_int64(argv[i++]); iMin = iMax = sqlite3_value_int64(argv[i++]);
}
}else{ }else{
if( idxNum & 0x0300 ){ if( idxNum & 0x0300 ){
if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[i++]);
if( idxNum & 0x0200 && r==ceil(r) ){
iMin = (sqlite3_int64)ceil(r+1.0);
}else{
iMin = (sqlite3_int64)ceil(r);
}
}else{
iMin = sqlite3_value_int64(argv[i++]); iMin = sqlite3_value_int64(argv[i++]);
if( idxNum & 0x0200 ){ if( idxNum & 0x0200 ){
if( iMin==LARGEST_INT64 ){ if( iMin==LARGEST_INT64 ){
@@ -6701,7 +6717,16 @@ static int seriesFilter(
} }
} }
} }
}
if( idxNum & 0x3000 ){ if( idxNum & 0x3000 ){
if( sqlite3_value_numeric_type(argv[i])==SQLITE_FLOAT ){
double r = sqlite3_value_double(argv[i++]);
if( (idxNum & 0x2000)!=0 && r==floor(r) ){
iMax = (sqlite3_int64)(r-1.0);
}else{
iMax = (sqlite3_int64)floor(r);
}
}else{
iMax = sqlite3_value_int64(argv[i++]); iMax = sqlite3_value_int64(argv[i++]);
if( idxNum & 0x2000 ){ if( idxNum & 0x2000 ){
if( iMax==SMALLEST_INT64 ){ if( iMax==SMALLEST_INT64 ){
@@ -6711,6 +6736,7 @@ static int seriesFilter(
} }
} }
} }
}
if( iMin>iMax ){ if( iMin>iMax ){
returnNoRows = 1; returnNoRows = 1;
} }
@@ -6726,8 +6752,7 @@ static int seriesFilter(
pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep; pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
} }
if( pCur->ss.iTerm>iMax ){ if( pCur->ss.iTerm>iMax ){
sqlite3_uint64 d = pCur->ss.iTerm - iMax; pCur->ss.iTerm = iMax;
pCur->ss.iTerm -= ((d+szStep-1)/szStep)*szStep;
} }
}else{ }else{
sqlite3_int64 szStep = -pCur->ss.iStep; sqlite3_int64 szStep = -pCur->ss.iStep;
@@ -6737,8 +6762,7 @@ static int seriesFilter(
pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep; pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
} }
if( pCur->ss.iTerm<iMin ){ if( pCur->ss.iTerm<iMin ){
sqlite3_uint64 d = iMin - pCur->ss.iTerm; pCur->ss.iTerm = iMin;
pCur->ss.iTerm += ((d+szStep-1)/szStep)*szStep;
} }
} }
} }
@@ -6866,7 +6890,10 @@ static int seriesBestIndex(
continue; continue;
} }
if( pConstraint->iColumn<SERIES_COLUMN_START ){ if( pConstraint->iColumn<SERIES_COLUMN_START ){
if( pConstraint->iColumn==SERIES_COLUMN_VALUE && pConstraint->usable ){ if( (pConstraint->iColumn==SERIES_COLUMN_VALUE ||
pConstraint->iColumn==SERIES_COLUMN_ROWID)
&& pConstraint->usable
){
switch( op ){ switch( op ){
case SQLITE_INDEX_CONSTRAINT_EQ: case SQLITE_INDEX_CONSTRAINT_EQ:
case SQLITE_INDEX_CONSTRAINT_IS: { case SQLITE_INDEX_CONSTRAINT_IS: {

121
deps/sqlite/sqlite3.c vendored
View File

@@ -1,6 +1,6 @@
/****************************************************************************** /******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite ** This file is an amalgamation of many separate C source files from SQLite
** version 3.49.1. By combining all the individual C code files into this ** version 3.49.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation ** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be ** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements ** possible if the files were compiled separately. Performance improvements
@@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library. ** separate file. This file contains only code for the core SQLite library.
** **
** The content in this amalgamation comes from Fossil check-in ** The content in this amalgamation comes from Fossil check-in
** 873d4e274b4988d260ba8354a9718324a1c2 with changes in files: ** 17144570b0d96ae63cd6f3edca39e27ebd74 with changes in files:
** **
** **
*/ */
@@ -465,9 +465,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.49.1" #define SQLITE_VERSION "3.49.2"
#define SQLITE_VERSION_NUMBER 3049001 #define SQLITE_VERSION_NUMBER 3049002
#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70" #define SQLITE_SOURCE_ID "2025-05-07 10:39:52 17144570b0d96ae63cd6f3edca39e27ebd74925252bbaf6723bcb2f6b4861fb1"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@@ -19064,6 +19064,7 @@ struct Index {
unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */ unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */ unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */ unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bIdxRowid:1; /* One or more of the index keys is the ROWID */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */ unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
unsigned bHasExpr:1; /* Index contains an expression, either a literal unsigned bHasExpr:1; /* Index contains an expression, either a literal
** expression, or a reference to a VIRTUAL column */ ** expression, or a reference to a VIRTUAL column */
@@ -97241,6 +97242,7 @@ case OP_MakeRecord: {
zHdr += sqlite3PutVarint(zHdr, serial_type); zHdr += sqlite3PutVarint(zHdr, serial_type);
if( pRec->n ){ if( pRec->n ){
assert( pRec->z!=0 ); assert( pRec->z!=0 );
assert( pRec->z!=(const char*)sqlite3CtypeMap );
memcpy(zPayload, pRec->z, pRec->n); memcpy(zPayload, pRec->z, pRec->n);
zPayload += pRec->n; zPayload += pRec->n;
} }
@@ -115468,11 +115470,11 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
sqlite3VdbeTypeofColumn(v, r1); assert( regFree1==0 || regFree1==r1 );
if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest); sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL); VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break; break;
} }
case TK_BETWEEN: { case TK_BETWEEN: {
@@ -115643,11 +115645,11 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
case TK_ISNULL: case TK_ISNULL:
case TK_NOTNULL: { case TK_NOTNULL: {
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
sqlite3VdbeTypeofColumn(v, r1); assert( regFree1==0 || regFree1==r1 );
if( regFree1 ) sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest); sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
testcase( regFree1==0 );
break; break;
} }
case TK_BETWEEN: { case TK_BETWEEN: {
@@ -126336,6 +126338,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
assert( j<=0x7fff ); assert( j<=0x7fff );
if( j<0 ){ if( j<0 ){
j = pTab->iPKey; j = pTab->iPKey;
pIndex->bIdxRowid = 1;
}else{ }else{
if( pTab->aCol[j].notNull==0 ){ if( pTab->aCol[j].notNull==0 ){
pIndex->uniqNotNull = 0; pIndex->uniqNotNull = 0;
@@ -139132,48 +139135,48 @@ static const char *const pragCName[] = {
/* 13 */ "pk", /* 13 */ "pk",
/* 14 */ "hidden", /* 14 */ "hidden",
/* table_info reuses 8 */ /* table_info reuses 8 */
/* 15 */ "schema", /* Used by: table_list */ /* 15 */ "name", /* Used by: function_list */
/* 16 */ "name", /* 16 */ "builtin",
/* 17 */ "type", /* 17 */ "type",
/* 18 */ "ncol", /* 18 */ "enc",
/* 19 */ "wr", /* 19 */ "narg",
/* 20 */ "strict", /* 20 */ "flags",
/* 21 */ "seqno", /* Used by: index_xinfo */ /* 21 */ "schema", /* Used by: table_list */
/* 22 */ "cid", /* 22 */ "name",
/* 23 */ "name", /* 23 */ "type",
/* 24 */ "desc", /* 24 */ "ncol",
/* 25 */ "coll", /* 25 */ "wr",
/* 26 */ "key", /* 26 */ "strict",
/* 27 */ "name", /* Used by: function_list */ /* 27 */ "seqno", /* Used by: index_xinfo */
/* 28 */ "builtin", /* 28 */ "cid",
/* 29 */ "type", /* 29 */ "name",
/* 30 */ "enc", /* 30 */ "desc",
/* 31 */ "narg", /* 31 */ "coll",
/* 32 */ "flags", /* 32 */ "key",
/* 33 */ "tbl", /* Used by: stats */ /* 33 */ "seq", /* Used by: index_list */
/* 34 */ "idx", /* 34 */ "name",
/* 35 */ "wdth", /* 35 */ "unique",
/* 36 */ "hght", /* 36 */ "origin",
/* 37 */ "flgs", /* 37 */ "partial",
/* 38 */ "seq", /* Used by: index_list */ /* 38 */ "tbl", /* Used by: stats */
/* 39 */ "name", /* 39 */ "idx",
/* 40 */ "unique", /* 40 */ "wdth",
/* 41 */ "origin", /* 41 */ "hght",
/* 42 */ "partial", /* 42 */ "flgs",
/* 43 */ "table", /* Used by: foreign_key_check */ /* 43 */ "table", /* Used by: foreign_key_check */
/* 44 */ "rowid", /* 44 */ "rowid",
/* 45 */ "parent", /* 45 */ "parent",
/* 46 */ "fkid", /* 46 */ "fkid",
/* index_info reuses 21 */ /* 47 */ "busy", /* Used by: wal_checkpoint */
/* 47 */ "seq", /* Used by: database_list */ /* 48 */ "log",
/* 48 */ "name", /* 49 */ "checkpointed",
/* 49 */ "file", /* 50 */ "seq", /* Used by: database_list */
/* 50 */ "busy", /* Used by: wal_checkpoint */ /* 51 */ "name",
/* 51 */ "log", /* 52 */ "file",
/* 52 */ "checkpointed", /* index_info reuses 27 */
/* collation_list reuses 38 */
/* 53 */ "database", /* Used by: lock_status */ /* 53 */ "database", /* Used by: lock_status */
/* 54 */ "status", /* 54 */ "status",
/* collation_list reuses 33 */
/* 55 */ "cache_size", /* Used by: default_cache_size */ /* 55 */ "cache_size", /* Used by: default_cache_size */
/* module_list pragma_list reuses 9 */ /* module_list pragma_list reuses 9 */
/* 56 */ "timeout", /* Used by: busy_timeout */ /* 56 */ "timeout", /* Used by: busy_timeout */
@@ -139266,7 +139269,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "collation_list", {/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 38, 2, /* ColNames: */ 33, 2,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
@@ -139301,7 +139304,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "database_list", {/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 47, 3, /* ColNames: */ 50, 3,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
@@ -139381,7 +139384,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "function_list", {/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0, /* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 27, 6, /* ColNames: */ 15, 6,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#endif #endif
@@ -139410,17 +139413,17 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "index_info", {/* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 21, 3, /* ColNames: */ 27, 3,
/* iArg: */ 0 }, /* iArg: */ 0 },
{/* zName: */ "index_list", {/* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 38, 5, /* ColNames: */ 33, 5,
/* iArg: */ 0 }, /* iArg: */ 0 },
{/* zName: */ "index_xinfo", {/* zName: */ "index_xinfo",
/* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 21, 6, /* ColNames: */ 27, 6,
/* iArg: */ 1 }, /* iArg: */ 1 },
#endif #endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK) #if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
@@ -139599,7 +139602,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "stats", {/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS, /* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
/* ColNames: */ 33, 5, /* ColNames: */ 38, 5,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
@@ -139618,7 +139621,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "table_list", {/* zName: */ "table_list",
/* ePragTyp: */ PragTyp_TABLE_LIST, /* ePragTyp: */ PragTyp_TABLE_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1,
/* ColNames: */ 15, 6, /* ColNames: */ 21, 6,
/* iArg: */ 0 }, /* iArg: */ 0 },
{/* zName: */ "table_xinfo", {/* zName: */ "table_xinfo",
/* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragTyp: */ PragTyp_TABLE_INFO,
@@ -139695,7 +139698,7 @@ static const PragmaName aPragmaName[] = {
{/* zName: */ "wal_checkpoint", {/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema, /* ePragFlg: */ PragFlg_NeedSchema,
/* ColNames: */ 50, 3, /* ColNames: */ 47, 3,
/* iArg: */ 0 }, /* iArg: */ 0 },
#endif #endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
@@ -147073,6 +147076,7 @@ static int multiSelect(
multi_select_end: multi_select_end:
pDest->iSdst = dest.iSdst; pDest->iSdst = dest.iSdst;
pDest->nSdst = dest.nSdst; pDest->nSdst = dest.nSdst;
pDest->iSDParm2 = dest.iSDParm2;
if( pDelete ){ if( pDelete ){
sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete); sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
} }
@@ -151027,6 +151031,7 @@ static void agginfoFree(sqlite3 *db, void *pArg){
** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries ** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
** * The outer query is a simple count(*) with no WHERE clause or other ** * The outer query is a simple count(*) with no WHERE clause or other
** extraneous syntax. ** extraneous syntax.
** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10)
** **
** Return TRUE if the optimization is undertaken. ** Return TRUE if the optimization is undertaken.
*/ */
@@ -151059,7 +151064,11 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */ if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */ if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){
testcase( pSub->selFlags & SF_Aggregate );
testcase( pSub->selFlags & SF_Distinct );
return 0; /* Not an aggregate nor DISTINCT */
}
assert( pSub->pHaving==0 ); /* Due to the previous */ assert( pSub->pHaving==0 ); /* Due to the previous */
pSub = pSub->pPrior; /* Repeat over compound */ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub ); }while( pSub );
@@ -166881,7 +166890,7 @@ static int whereLoopAddBtreeIndex(
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
&& pNew->u.btree.nEq<pProbe->nColumn && pNew->u.btree.nEq<pProbe->nColumn
&& (pNew->u.btree.nEq<pProbe->nKeyCol || && (pNew->u.btree.nEq<pProbe->nKeyCol ||
pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY) (pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY && !pProbe->bIdxRowid))
){ ){
if( pNew->u.btree.nEq>3 ){ if( pNew->u.btree.nEq>3 ){
sqlite3ProgressCheck(pParse); sqlite3ProgressCheck(pParse);
@@ -255874,7 +255883,7 @@ static void fts5SourceIdFunc(
){ ){
assert( nArg==0 ); assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused); UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70", -1, SQLITE_TRANSIENT); sqlite3_result_text(pCtx, "fts5: 2025-05-07 10:39:52 17144570b0d96ae63cd6f3edca39e27ebd74925252bbaf6723bcb2f6b4861fb1", -1, SQLITE_TRANSIENT);
} }
/* /*

View File

@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.49.1" #define SQLITE_VERSION "3.49.2"
#define SQLITE_VERSION_NUMBER 3049001 #define SQLITE_VERSION_NUMBER 3049002
#define SQLITE_SOURCE_ID "2025-02-18 13:38:58 873d4e274b4988d260ba8354a9718324a1c26187a4ab4c1cc0227c03d0f10e70" #define SQLITE_SOURCE_ID "2025-05-07 10:39:52 17144570b0d96ae63cd6f3edca39e27ebd74925252bbaf6723bcb2f6b4861fb1"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers

6
flake.lock generated
View File

@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1739758141, "lastModified": 1745279238,
"narHash": "sha256-uq6A2L7o1/tR6VfmYhZWoVAwb3gTy7j4Jx30MIrH0rE=", "narHash": "sha256-AQ7M9wTa/Pa/kK5pcGTgX/DGqMHyzsyINfN7ktsI7Fo=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c618e28f70257593de75a7044438efc1c1fc0791", "rev": "9684b53175fc6c09581e94cc85f05ab77464c7e3",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -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="35" android:versionCode="37"
android:versionName="0.0.30"> android:versionName="0.0.31-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

View File

@@ -13,13 +13,13 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.0.30</string> <string>0.0.31</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
<array> <array>
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>12</string> <string>13</string>
<key>DTPlatformName</key> <key>DTPlatformName</key>
<string>iphoneos</string> <string>iphoneos</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View File

@@ -461,7 +461,7 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
} }
} }
if (show_usage || !user || !identity || !content) if (show_usage || !identity || !content)
{ {
tf_printf("\n%s publish [options]\n\n", file); tf_printf("\n%s publish [options]\n\n", file);
tf_printf("options:\n"); tf_printf("options:\n");
@@ -480,6 +480,14 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL); tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
tf_ssb_set_quiet(ssb, true); tf_ssb_set_quiet(ssb, true);
uint8_t private_key[512] = { 0 }; uint8_t private_key[512] = { 0 };
bool free_user = false;
if (!user)
{
user = tf_ssb_db_get_user_for_identity(ssb, identity);
free_user = true;
}
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key))) if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
{ {
JSContext* context = tf_ssb_get_context(ssb); JSContext* context = tf_ssb_get_context(ssb);
@@ -509,6 +517,12 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
{ {
tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user); tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
} }
if (free_user)
{
tf_free((void*)user);
}
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
tf_free((void*)default_db_path); tf_free((void*)default_db_path);
return result; return result;
@@ -531,7 +545,7 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
{ "id", required_argument, NULL, 'i' }, { "id", required_argument, NULL, 'i' },
{ "recipients", required_argument, NULL, 'r' }, { "recipients", required_argument, NULL, 'r' },
{ "db-path", required_argument, NULL, 'd' }, { "db-path", required_argument, NULL, 'd' },
{ "text", required_argument, NULL, 'c' }, { "text", required_argument, NULL, 't' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ 0 }, { 0 },
}; };
@@ -566,11 +580,11 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
} }
} }
if (show_usage || !user || !identity || !recipients || !text) if (show_usage || !identity || !recipients || !text)
{ {
tf_printf("\n%s private [options]\n\n", file); tf_printf("\n%s private [options]\n\n", file);
tf_printf("options:\n"); tf_printf("options:\n");
tf_printf(" -u, --user user User owning identity with which to publish.\n"); tf_printf(" -u, --user user User owning identity with which to publish (optional).\n");
tf_printf(" -i, --id identity Identity with which to publish message.\n"); tf_printf(" -i, --id identity Identity with which to publish message.\n");
tf_printf(" -r, --recipients recipients Recipient identities.\n"); tf_printf(" -r, --recipients recipients Recipient identities.\n");
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path); tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", default_db_path);
@@ -591,6 +605,13 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
recipient_list[recipient_count++] = identity; recipient_list[recipient_count++] = identity;
bool free_user = false;
if (!user)
{
user = tf_ssb_db_get_user_for_identity(ssb, identity);
free_user = true;
}
if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key))) if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
{ {
char* copy = tf_strdup(recipients); char* copy = tf_strdup(recipients);
@@ -642,6 +663,11 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
{ {
tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user); tf_printf("Did not find private key for identity %s belonging to %s.\n", identity, user);
} }
if (free_user)
{
tf_free((void*)user);
}
done: done:
tf_ssb_destroy(ssb); tf_ssb_destroy(ssb);
tf_free((void*)default_db_path); tf_free((void*)default_db_path);

View File

@@ -386,29 +386,17 @@ size_t tf_mem_get_uv_malloc_size()
return s_uv_malloc_size; return s_uv_malloc_size;
} }
#if defined(__OpenBSD__)
static void* _tf_tls_alloc(size_t size)
#else
static void* _tf_tls_alloc(size_t size, const char* file, int line) static void* _tf_tls_alloc(size_t size, const char* file, int line)
#endif
{ {
return _tf_alloc(&s_tls_malloc_size, size); return _tf_alloc(&s_tls_malloc_size, size);
} }
#if defined(__OpenBSD__)
static void* _tf_tls_realloc(void* ptr, size_t size)
#else
static void* _tf_tls_realloc(void* ptr, size_t size, const char* file, int line) static void* _tf_tls_realloc(void* ptr, size_t size, const char* file, int line)
#endif
{ {
return _tf_realloc(&s_tls_malloc_size, ptr, size); return _tf_realloc(&s_tls_malloc_size, ptr, size);
} }
#if defined(__OpenBSD__)
static void _tf_tls_free(void* ptr)
#else
static void _tf_tls_free(void* ptr, const char* file, int line) static void _tf_tls_free(void* ptr, const char* file, int line)
#endif
{ {
_tf_free(&s_tls_malloc_size, ptr); _tf_free(&s_tls_malloc_size, ptr);
} }

View File

@@ -248,6 +248,8 @@ typedef struct _tf_ssb_t
bool is_replicator; bool is_replicator;
bool is_peer_exchange; bool is_peer_exchange;
bool talk_to_strangers; bool talk_to_strangers;
bool broadcast;
bool discovery;
char* room_name; char* room_name;
char seeds_host[256]; char seeds_host[256];
time_t last_seed_check; time_t last_seed_check;
@@ -3376,6 +3378,12 @@ static void _tf_ssb_update_seeds_after_work(tf_ssb_t* ssb, int status, void* use
static void _tf_ssb_broadcast_timer(uv_timer_t* timer) static void _tf_ssb_broadcast_timer(uv_timer_t* timer)
{ {
tf_ssb_t* ssb = timer->data; tf_ssb_t* ssb = timer->data;
if (!ssb->broadcast)
{
uv_timer_stop(timer);
return;
}
uv_interface_address_t* info = NULL; uv_interface_address_t* info = NULL;
int count = 0; int count = 0;
if (uv_interface_addresses(&info, &count) == 0) if (uv_interface_addresses(&info, &count) == 0)
@@ -3605,13 +3613,13 @@ void tf_ssb_add_broadcast(tf_ssb_t* ssb, const char* connection, tf_ssb_broadcas
static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
{ {
if (nread <= 0) tf_ssb_t* ssb = handle->data;
if (nread <= 0 || !ssb->discovery)
{ {
tf_free(buf->base); tf_free(buf->base);
return; return;
} }
tf_ssb_t* ssb = handle->data;
((char*)buf->base)[nread] = '\0'; ((char*)buf->base)[nread] = '\0';
const char* k_delim = ";"; const char* k_delim = ";";
@@ -3714,7 +3722,7 @@ void tf_ssb_broadcast_listener_start(tf_ssb_t* ssb, bool linger)
void tf_ssb_broadcast_sender_start(tf_ssb_t* ssb) void tf_ssb_broadcast_sender_start(tf_ssb_t* ssb)
{ {
if (ssb->broadcast_sender.data) if (ssb->broadcast_sender.data || !ssb->broadcast)
{ {
return; return;
} }
@@ -4428,6 +4436,8 @@ typedef struct _update_settings_t
bool is_replicator; bool is_replicator;
bool is_peer_exchange; bool is_peer_exchange;
bool talk_to_strangers; bool talk_to_strangers;
bool broadcast;
bool discovery;
char seeds_host[256]; char seeds_host[256];
char room_name[1024]; char room_name[1024];
} update_settings_t; } update_settings_t;
@@ -4440,12 +4450,16 @@ static void _tf_ssb_update_settings_work(tf_ssb_t* ssb, void* user_data)
update->is_replicator = true; update->is_replicator = true;
update->is_peer_exchange = true; update->is_peer_exchange = true;
update->talk_to_strangers = true; update->talk_to_strangers = true;
update->broadcast = true;
update->discovery = true;
tf_ssb_db_get_global_setting_bool(db, "room", &update->is_room); tf_ssb_db_get_global_setting_bool(db, "room", &update->is_room);
tf_ssb_db_get_global_setting_bool(db, "replicator", &update->is_replicator); tf_ssb_db_get_global_setting_bool(db, "replicator", &update->is_replicator);
tf_ssb_db_get_global_setting_bool(db, "peer_exchange", &update->is_peer_exchange); tf_ssb_db_get_global_setting_bool(db, "peer_exchange", &update->is_peer_exchange);
tf_ssb_db_get_global_setting_bool(db, "talk_to_strangers", &update->talk_to_strangers); tf_ssb_db_get_global_setting_bool(db, "talk_to_strangers", &update->talk_to_strangers);
tf_ssb_db_get_global_setting_string(db, "room_name", update->room_name, sizeof(update->room_name)); tf_ssb_db_get_global_setting_string(db, "room_name", update->room_name, sizeof(update->room_name));
tf_ssb_db_get_global_setting_string(db, "seeds_host", update->seeds_host, sizeof(update->seeds_host)); tf_ssb_db_get_global_setting_string(db, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
tf_ssb_db_get_global_setting_bool(db, "broadcast", &update->broadcast);
tf_ssb_db_get_global_setting_bool(db, "discovery", &update->discovery);
tf_ssb_release_db_reader(ssb, db); tf_ssb_release_db_reader(ssb, db);
} }
@@ -4457,6 +4471,12 @@ static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void*
tf_ssb_set_is_peer_exchange(ssb, update->is_peer_exchange); tf_ssb_set_is_peer_exchange(ssb, update->is_peer_exchange);
tf_ssb_set_is_replicator(ssb, update->is_replicator); tf_ssb_set_is_replicator(ssb, update->is_replicator);
ssb->talk_to_strangers = update->talk_to_strangers; ssb->talk_to_strangers = update->talk_to_strangers;
ssb->broadcast = update->broadcast;
if (ssb->broadcast && tf_ssb_server_get_port(ssb) && !uv_timer_get_due_in(&ssb->broadcast_timer))
{
uv_timer_start(&ssb->broadcast_timer, _tf_ssb_broadcast_timer, 2000, 2000);
}
ssb->discovery = update->discovery;
snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host); snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host);
_tf_ssb_start_update_settings(ssb); _tf_ssb_start_update_settings(ssb);
tf_free(update); tf_free(update);
@@ -4630,6 +4650,10 @@ void tf_ssb_sync_start(tf_ssb_t* ssb)
bool tf_ssb_tunnel_create(tf_ssb_t* ssb, const char* portal_id, const char* target_id, int connect_flags) bool tf_ssb_tunnel_create(tf_ssb_t* ssb, const char* portal_id, const char* target_id, int connect_flags)
{ {
if (!portal_id || !target_id)
{
return false;
}
tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id); tf_ssb_connection_t* connection = tf_ssb_connection_get(ssb, portal_id);
if (connection && !tf_ssb_connection_get(ssb, target_id)) if (connection && !tf_ssb_connection_get(ssb, target_id))
{ {

View File

@@ -1398,6 +1398,34 @@ void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* id
tf_ssb_release_db_reader(ssb, db); tf_ssb_release_db_reader(ssb, db);
} }
const char* tf_ssb_db_get_user_for_identity(tf_ssb_t* ssb, const char* public_key)
{
const char* result = NULL;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement = NULL;
if (sqlite3_prepare(db, "SELECT user FROM identities WHERE public_key = ?", -1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, (public_key && *public_key == '@') ? public_key + 1 : public_key, -1, NULL) == SQLITE_OK)
{
if (sqlite3_step(statement) == SQLITE_ROW)
{
result = tf_strdup((const char*)sqlite3_column_text(statement, 0));
}
}
else
{
tf_printf("Bind failed: %s.\n", sqlite3_errmsg(db));
}
sqlite3_finalize(statement);
}
else
{
tf_printf("Prepare failed: %s.\n", sqlite3_errmsg(db));
}
tf_ssb_release_db_reader(ssb, db);
return result;
}
bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size) bool tf_ssb_db_identity_get_private_key(tf_ssb_t* ssb, const char* user, const char* public_key, uint8_t* out_private_key, size_t private_key_size)
{ {
bool success = false; bool success = false;
@@ -1549,17 +1577,9 @@ static following_t* _make_following_node(const char* id, following_t*** followin
return entry; return entry;
} }
static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, block_node_t* active_blocks, bool include_blocks) static void _populate_follows_and_blocks(
sqlite3* db, sqlite3_stmt* statement, following_t* entry, following_t*** following, int* following_count, block_node_t* active_blocks, bool include_blocks)
{ {
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement = NULL;
if (sqlite3_prepare(db,
"SELECT content ->> '$.contact' AS contact, content ->> '$.following', content ->> '$.blocking' "
"FROM messages "
"WHERE contact IS NOT NULL AND author = ? AND content ->> '$.type' = 'contact' "
"ORDER BY sequence",
-1, &statement, NULL) == SQLITE_OK)
{
if (sqlite3_bind_text(statement, 1, entry->id, -1, NULL) == SQLITE_OK) if (sqlite3_bind_text(statement, 1, entry->id, -1, NULL) == SQLITE_OK)
{ {
while (sqlite3_step(statement) == SQLITE_ROW) while (sqlite3_step(statement) == SQLITE_ROW)
@@ -1611,13 +1631,11 @@ static void _populate_follows_and_blocks(tf_ssb_t* ssb, following_t* entry, foll
} }
} }
} }
sqlite3_finalize(statement); sqlite3_reset(statement);
}
tf_ssb_release_db_reader(ssb, db);
} }
static void _get_following( static void _get_following(sqlite3* db, sqlite3_stmt* statement, following_t* entry, following_t*** following, int* following_count, int depth, int max_depth,
tf_ssb_t* ssb, following_t* entry, following_t*** following, int* following_count, int depth, int max_depth, block_node_t* active_blocks, bool include_blocks) block_node_t* active_blocks, bool include_blocks)
{ {
int old_depth = entry->depth; int old_depth = entry->depth;
entry->depth = tf_min(depth, entry->depth); entry->depth = tf_min(depth, entry->depth);
@@ -1628,28 +1646,47 @@ static void _get_following(
if (!entry->populated) if (!entry->populated)
{ {
entry->populated = true; entry->populated = true;
_populate_follows_and_blocks(ssb, entry, following, following_count, active_blocks, include_blocks); _populate_follows_and_blocks(db, statement, entry, following, following_count, active_blocks, include_blocks);
} }
block_node_t blocks = { .entry = entry, .parent = active_blocks }; block_node_t blocks = { .entry = entry, .parent = active_blocks };
for (int i = 0; i < entry->following_count; i++) for (int i = 0; i < entry->following_count; i++)
{ {
_get_following(ssb, entry->following[i], following, following_count, depth + 1, max_depth, &blocks, include_blocks); _get_following(db, statement, entry->following[i], following, following_count, depth + 1, max_depth, &blocks, include_blocks);
} }
} }
} }
} }
static sqlite3_stmt* _make_following_statement(sqlite3* db)
{
sqlite3_stmt* statement = NULL;
if (sqlite3_prepare(db,
"SELECT content ->> '$.contact' AS contact, content ->> '$.following', content ->> '$.blocking' "
"FROM messages "
"WHERE contact IS NOT NULL AND author = ? AND content ->> '$.type' = 'contact' "
"ORDER BY sequence",
-1, &statement, NULL) != SQLITE_OK)
{
tf_printf("prepare failed: %s", sqlite3_errmsg(db));
}
return statement;
}
tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth, bool include_blocks) tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, int count, int depth, bool include_blocks)
{ {
following_t** following = NULL; following_t** following = NULL;
int following_count = 0; int following_count = 0;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement = _make_following_statement(db);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL, include_blocks); following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL, include_blocks);
_get_following(ssb, entry, &following, &following_count, 0, depth, NULL, include_blocks); _get_following(db, statement, entry, &following, &following_count, 0, depth, NULL, include_blocks);
entry->ref_count++; entry->ref_count++;
} }
sqlite3_finalize(statement);
tf_ssb_release_db_reader(ssb, db);
int actual_following_count = 0; int actual_following_count = 0;
for (int i = 0; i < following_count; i++) for (int i = 0; i < following_count; i++)
@@ -1693,12 +1730,17 @@ const char** tf_ssb_db_following_deep_ids(tf_ssb_t* ssb, const char** ids, int c
{ {
following_t** following = NULL; following_t** following = NULL;
int following_count = 0; int following_count = 0;
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
sqlite3_stmt* statement = _make_following_statement(db);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL, false); following_t* entry = _make_following_node(ids[i], &following, &following_count, NULL, false);
_get_following(ssb, entry, &following, &following_count, 0, depth, NULL, false); _get_following(db, statement, entry, &following, &following_count, 0, depth, NULL, false);
entry->ref_count++; entry->ref_count++;
} }
sqlite3_finalize(statement);
tf_ssb_release_db_reader(ssb, db);
int actual_following_count = 0; int actual_following_count = 0;
for (int i = 0; i < following_count; i++) for (int i = 0; i < following_count; i++)

View File

@@ -249,6 +249,14 @@ void tf_ssb_db_identity_visit(tf_ssb_t* ssb, const char* user, void (*callback)(
*/ */
void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data); void tf_ssb_db_identity_visit_all(tf_ssb_t* ssb, void (*callback)(const char* identity, void* user_data), void* user_data);
/**
** Get the user owning an identity.
** @param ssb The SSB instance.
** @param public_key the identity.
** @return The username of the owner of the identity or NULL.
*/
const char* tf_ssb_db_get_user_for_identity(tf_ssb_t* ssb, const char* public_key);
/** /**
** Get the private key for an identity in the database. ** Get the private key for an identity in the database.
** @param ssb The SSB instance. ** @param ssb The SSB instance.

View File

@@ -1788,7 +1788,7 @@ static JSValue _tf_ssb_createTunnel(JSContext* context, JSValueConst this_val, i
const char* portal_id = JS_ToCString(context, argv[0]); const char* portal_id = JS_ToCString(context, argv[0]);
const char* target_id = JS_ToCString(context, argv[1]); const char* target_id = JS_ToCString(context, argv[1]);
bool result = tf_ssb_tunnel_create(ssb, portal_id, target_id, 0); bool result = portal_id && target_id && tf_ssb_tunnel_create(ssb, portal_id, target_id, 0);
JS_FreeCString(context, target_id); JS_FreeCString(context, target_id);
JS_FreeCString(context, portal_id); JS_FreeCString(context, portal_id);

View File

@@ -1469,9 +1469,9 @@ static void _tf_ssb_rpc_checkpoint(tf_ssb_t* ssb)
sqlite3* db = tf_ssb_acquire_db_writer(ssb); sqlite3* db = tf_ssb_acquire_db_writer(ssb);
int log = 0; int log = 0;
int checkpointed = 0; int checkpointed = 0;
if (sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_TRUNCATE, &log, &checkpointed) == SQLITE_OK) if (sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_PASSIVE, &log, &checkpointed) == SQLITE_OK)
{ {
tf_printf("Checkpointed %d frames in %d ms. Log is now %d frames.\n", (int)((uv_hrtime() - checkpoint_start_ms) / 1000000LL), checkpointed, log); tf_printf("Checkpointed %d frames in %d ms. Log is now %d frames.\n", checkpointed, (int)((uv_hrtime() - checkpoint_start_ms) / 1000000LL), log);
} }
else else
{ {
@@ -1541,7 +1541,7 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
static void _tf_ssb_rpc_delete_blobs_after_work(tf_ssb_t* ssb, int status, void* user_data) static void _tf_ssb_rpc_delete_blobs_after_work(tf_ssb_t* ssb, int status, void* user_data)
{ {
delete_t* delete = user_data; delete_t* delete = user_data;
_tf_ssb_rpc_start_delete_blobs(ssb, delete->deleted ? (int)delete->duration_ms : (15 * 60 * 1000)); _tf_ssb_rpc_start_delete_blobs(ssb, delete->deleted ? (int)delete->duration_ms : (5 * 60 * 1000));
tf_free(delete); tf_free(delete);
} }

View File

@@ -1478,4 +1478,133 @@ void tf_ssb_test_triggers(const tf_test_options_t* options)
uv_loop_close(&loop); uv_loop_close(&loop);
} }
static void _subprocess_check_call(const char* command, int expected)
{
int result = system(command);
if (!WIFEXITED(result))
{
tf_printf("Command did not report exit: %s.\n", command);
abort();
}
if (WEXITSTATUS(result) != expected)
{
tf_printf("Command returned %d (expected %d): %s.\n", WEXITSTATUS(result), expected, command);
abort();
}
}
static char* _subprocess_check_output(const char* command)
{
FILE* proc = popen(command, "r");
if (!proc)
{
tf_printf("Command failed (%s): %s.\n", strerror(errno), command);
abort();
}
char* result = NULL;
size_t size = 0;
if (proc)
{
const int k_block_size = 1024;
result = tf_realloc(result, size + k_block_size);
while (true)
{
size_t bytes = fread(result + size, 1, k_block_size, proc);
if (bytes > 0)
{
size += bytes;
}
else
{
break;
}
}
pclose(proc);
}
result = tf_realloc(result, size + 1);
if (result)
{
result[size] = '\0';
}
return result;
}
static bool _isspace(char c)
{
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
static char* _trim(char* p)
{
if (!p)
{
return NULL;
}
size_t length = strlen(p);
while (length > 0 && _isspace(p[length - 1]))
{
p[length - 1] = '\0';
length--;
}
return p;
}
void tf_ssb_test_cli(const tf_test_options_t* options)
{
tf_printf("Testing CLI.\n");
unlink("out/test_db0.sqlite");
char command[1024];
snprintf(command, sizeof(command), "%s get_identity -d out/test_db0.sqlite", options->exe_path);
_subprocess_check_call(command, 0);
char* id = _trim(_subprocess_check_output(command));
tf_printf("id = [%s]\n", id);
snprintf(command, sizeof(command), "%s publish -i %s -d out/test_db0.sqlite -c '{\"type\": \"about\", \"about\": \"%s\", \"name\": \"test_user\"}'", options->exe_path, id, id);
_subprocess_check_call(command, 0);
snprintf(command, sizeof(command), "%s private -i %s -r %s -d out/test_db0.sqlite -t '{\"type\": \"post\", \"text\": \"hello world\"}'", options->exe_path, id, id);
_subprocess_check_call(command, 0);
snprintf(command, sizeof(command), "%s verify -i %s -d out/test_db0.sqlite", options->exe_path, id);
_subprocess_check_call(command, 0);
snprintf(command, sizeof(command), "%s store_blob -f GNUmakefile -d out/test_db0.sqlite", options->exe_path);
char* blob = _trim(_subprocess_check_output(command));
snprintf(command, sizeof(command), "%s has_blob -b '%s' -d out/test_db0.sqlite", options->exe_path, blob);
_subprocess_check_call(command, 0);
snprintf(command, sizeof(command), "%s has_blob -b '&nonexistentid.sha256' -d out/test_db0.sqlite", options->exe_path);
_subprocess_check_call(command, EXIT_FAILURE);
snprintf(command, sizeof(command), "%s get_sequence -i %s -d out/test_db0.sqlite", options->exe_path, id);
char* sequence = _trim(_subprocess_check_output(command));
if (!sequence || strcmp(sequence, "2") != 0)
{
tf_printf("sequence = %s (expected 1)\n", sequence);
abort();
}
tf_free(sequence);
snprintf(command, sizeof(command), "%s get_profile -i %s -d out/test_db0.sqlite", options->exe_path, id);
char* profile = _trim(_subprocess_check_output(command));
const char* k_expected_profile = "{\"name\":\"test_user\"}";
if (!profile || strcmp(profile, k_expected_profile) != 0)
{
tf_printf("profile = %s (expected \"%s\")\n", profile, k_expected_profile);
abort();
}
tf_free(profile);
snprintf(command, sizeof(command), "%s get_contacts -i %s -d out/test_db0.sqlite", options->exe_path, id);
char* contacts = _trim(_subprocess_check_output(command));
tf_printf("contacts = %s\n", contacts);
tf_free(contacts);
tf_free(blob);
tf_free(id);
}
#endif #endif

View File

@@ -89,4 +89,10 @@ void tf_ssb_test_invite(const tf_test_options_t* options);
*/ */
void tf_ssb_test_triggers(const tf_test_options_t* options); void tf_ssb_test_triggers(const tf_test_options_t* options);
/**
** Test command-line interface.
** @param options The test options.
*/
void tf_ssb_test_cli(const tf_test_options_t* options);
/** @} */ /** @} */

View File

@@ -1869,15 +1869,15 @@ void tf_task_destroy(tf_task_t* task)
uv_close((uv_handle_t*)&timeout->_timer, _timeout_closed); uv_close((uv_handle_t*)&timeout->_timer, _timeout_closed);
} }
if (task->_ssb)
{
tf_ssb_destroy(task->_ssb);
}
if (task->_http) if (task->_http)
{ {
tf_httpd_destroy(task->_http); tf_httpd_destroy(task->_http);
task->_http = NULL; task->_http = NULL;
} }
if (task->_ssb)
{
tf_ssb_destroy(task->_ssb);
}
JS_FreeContext(task->_context); JS_FreeContext(task->_context);
JS_FreeRuntime(task->_runtime); JS_FreeRuntime(task->_runtime);

View File

@@ -1079,6 +1079,7 @@ void tf_tests(const tf_test_options_t* options)
_tf_test_run(options, "connect_str", tf_ssb_test_connect_str, false); _tf_test_run(options, "connect_str", tf_ssb_test_connect_str, false);
_tf_test_run(options, "invite", tf_ssb_test_invite, false); _tf_test_run(options, "invite", tf_ssb_test_invite, false);
_tf_test_run(options, "triggers", tf_ssb_test_triggers, false); _tf_test_run(options, "triggers", tf_ssb_test_triggers, false);
_tf_test_run(options, "cli", tf_ssb_test_cli, false);
tf_printf("Tests completed.\n"); tf_printf("Tests completed.\n");
#endif #endif
} }

View File

@@ -398,6 +398,8 @@ static const setting_t k_settings[] = {
.description = "Whether connections are accepted from accounts that aren't in the replication range or otherwise already known.", .description = "Whether connections are accepted from accounts that aren't in the replication range or otherwise already known.",
.default_value = { .kind = k_kind_bool, .bool_value = true } }, .default_value = { .kind = k_kind_bool, .bool_value = true } },
{ .name = "autologin", .type = "boolean", .description = "Whether mobile autologin is supported.", .default_value = { .kind = k_kind_bool, .bool_value = TF_IS_MOBILE != 0 } }, { .name = "autologin", .type = "boolean", .description = "Whether mobile autologin is supported.", .default_value = { .kind = k_kind_bool, .bool_value = TF_IS_MOBILE != 0 } },
{ .name = "broadcast", .type = "boolean", .description = "Send network discovery broadcasts.", .default_value = { .kind = k_kind_bool, .bool_value = true } },
{ .name = "discovery", .type = "boolean", .description = "Receive network discovery broadcasts.", .default_value = { .kind = k_kind_bool, .bool_value = true } },
}; };
static const setting_t* _util_get_setting(const char* name, tf_setting_kind_t kind) static const setting_t* _util_get_setting(const char* name, tf_setting_kind_t kind)

View File

@@ -1,2 +1,2 @@
#define VERSION_NUMBER "0.0.30" #define VERSION_NUMBER "0.0.31-wip"
#define VERSION_NAME "This program kills fascists." #define VERSION_NAME "This program kills fascists."