Compare commits
51 Commits
8b546c7e02
...
latest_rel
Author | SHA1 | Date | |
---|---|---|---|
c550f92003 | |||
ed836b3ee0 | |||
ac7a43abf4 | |||
49f19fce91 | |||
b2197eb8e9 | |||
5fbc2cae1c | |||
730abb49ce | |||
edccab054a | |||
e8210c6fdd | |||
55d69d7c13 | |||
50fb18d4ff | |||
77b1ea1fc8 | |||
61501a9b64 | |||
c1507adac5 | |||
45fb9eda1c | |||
982a61f4bf | |||
18e5b41663 | |||
910c39cbd0 | |||
9952dfd49d | |||
00f75d5382 | |||
d78828554b | |||
b84b561109 | |||
a618815500 | |||
e1f3dc6ae4 | |||
f378db6c6f | |||
7cec0f7d61 | |||
f902d0374c | |||
b5f0a0c4f7 | |||
00623cea09 | |||
ed4f1d6f2c | |||
73f4a3407f | |||
6f11318e84 | |||
e88ee91f0e | |||
3f8daf257c | |||
dc387acadc | |||
68aa41ab96 | |||
85b23437b3 | |||
c59fba817d | |||
c3415ab75c | |||
f1d0151d71 | |||
3c5c1756d1 | |||
6a6b65d1b3 | |||
81bd54dbe6 | |||
6a1bb0d3bc | |||
705e8b553f | |||
e4729b22f2 | |||
662112551a | |||
38fe88aab8 | |||
578c51faa0 | |||
a3ccc73b81 | |||
7312f4d43a |
8
Doxyfile
8
Doxyfile
@@ -342,7 +342,7 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
|||||||
#
|
#
|
||||||
# Note see also the list of default file extension mappings.
|
# Note see also the list of default file extension mappings.
|
||||||
|
|
||||||
EXTENSION_MAPPING =
|
EXTENSION_MAPPING = js=javascript
|
||||||
|
|
||||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||||
# according to the Markdown format, which allows for more readable
|
# according to the Markdown format, which allows for more readable
|
||||||
@@ -944,6 +944,11 @@ WARN_LOGFILE =
|
|||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = README.md \
|
INPUT = README.md \
|
||||||
|
core/app.js \
|
||||||
|
core/client.js \
|
||||||
|
core/core.js \
|
||||||
|
core/http.js \
|
||||||
|
core/tfrpc.js \
|
||||||
docs/ \
|
docs/ \
|
||||||
src/
|
src/
|
||||||
|
|
||||||
@@ -986,6 +991,7 @@ INPUT_FILE_ENCODING =
|
|||||||
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||||
|
|
||||||
FILE_PATTERNS = *.h \
|
FILE_PATTERNS = *.h \
|
||||||
|
*.js \
|
||||||
*.md
|
*.md
|
||||||
|
|
||||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||||
|
18
GNUmakefile
18
GNUmakefile
@@ -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 := 40
|
VERSION_CODE := 42
|
||||||
VERSION_CODE_IOS := 15
|
VERSION_CODE_IOS := 16
|
||||||
VERSION_NUMBER := 0.0.33-wip
|
VERSION_NUMBER := 0.2025.8
|
||||||
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-3500300.zip
|
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3500400.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
|
||||||
@@ -253,7 +253,10 @@ $(ANDROID_TARGETS): CFLAGS += \
|
|||||||
-fno-asynchronous-unwind-tables \
|
-fno-asynchronous-unwind-tables \
|
||||||
-funwind-tables \
|
-funwind-tables \
|
||||||
-Wno-unknown-warning-option
|
-Wno-unknown-warning-option
|
||||||
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
$(ANDROID_TARGETS): LDFLAGS += \
|
||||||
|
--sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
|
||||||
|
-Wl,-z,max-page-size=16384 \
|
||||||
|
-fPIC
|
||||||
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
||||||
$(DEBUG_TARGETS): LDFLAGS += -Og
|
$(DEBUG_TARGETS): LDFLAGS += -Og
|
||||||
$(RELEASE_TARGETS): CFLAGS += \
|
$(RELEASE_TARGETS): CFLAGS += \
|
||||||
@@ -1140,6 +1143,11 @@ releaseapkgo: out/TildeFriends-arm-release.apk ## Build, install, and run a rele
|
|||||||
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
.PHONY: releaseapkgo
|
.PHONY: releaseapkgo
|
||||||
|
|
||||||
|
x86releaseapkgo: out/TildeFriends-x86-release.apk ## Build, install, and run an x86 release Android APK.
|
||||||
|
@adb install -r $<
|
||||||
|
@adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity
|
||||||
|
.PHONY: x86releaseapkgo
|
||||||
|
|
||||||
apklog: ## Display Android log output.
|
apklog: ## Display Android log output.
|
||||||
@adb logcat *:S tildefriends
|
@adb logcat *:S tildefriends
|
||||||
.PHONY: apklog
|
.PHONY: apklog
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🦀",
|
"emoji": "🦀",
|
||||||
"previous": "&DGtlnm5wWRZCgJMF8JsP6VtzNRrd4KLoERJRpFULqOY=.sha256"
|
"previous": "&Hd6CuhhnZIf13PdFJYZBUYLYZO84WdaKvWXLC29M7Ac=.sha256"
|
||||||
}
|
}
|
||||||
|
@@ -21,10 +21,13 @@ class TfElement extends LitElement {
|
|||||||
channels_latest: {type: Object},
|
channels_latest: {type: Object},
|
||||||
guest: {type: Boolean},
|
guest: {type: Boolean},
|
||||||
url: {type: String},
|
url: {type: String},
|
||||||
|
private_closed: {type: Object},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
grouped_private_messages: {type: Object},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
is_administrator: {type: Boolean},
|
is_administrator: {type: Boolean},
|
||||||
stay_connected: {type: Boolean},
|
stay_connected: {type: Boolean},
|
||||||
|
progress: {type: Number},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +50,7 @@ class TfElement extends LitElement {
|
|||||||
this.loading_latest = 0;
|
this.loading_latest = 0;
|
||||||
this.loading_latest_scheduled = 0;
|
this.loading_latest_scheduled = 0;
|
||||||
this.recent_reactions = [];
|
this.recent_reactions = [];
|
||||||
|
this.private_closed = {};
|
||||||
tfrpc.rpc.getBroadcasts().then((b) => {
|
tfrpc.rpc.getBroadcasts().then((b) => {
|
||||||
self.broadcasts = b || [];
|
self.broadcasts = b || [];
|
||||||
});
|
});
|
||||||
@@ -56,6 +60,7 @@ class TfElement extends LitElement {
|
|||||||
tfrpc.rpc.getHash().then((hash) => self.set_hash(hash));
|
tfrpc.rpc.getHash().then((hash) => self.set_hash(hash));
|
||||||
tfrpc.register(function hashChanged(hash) {
|
tfrpc.register(function hashChanged(hash) {
|
||||||
self.set_hash(hash);
|
self.set_hash(hash);
|
||||||
|
self.reset_progress();
|
||||||
});
|
});
|
||||||
tfrpc.register(async function notifyNewMessage(id) {
|
tfrpc.register(async function notifyNewMessage(id) {
|
||||||
await self.fetch_new_message(id);
|
await self.fetch_new_message(id);
|
||||||
@@ -83,9 +88,22 @@ class TfElement extends LitElement {
|
|||||||
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
|
this.whoami = whoami ?? (ids.length ? ids[0] : undefined);
|
||||||
this.guest = !this.whoami?.length;
|
this.guest = !this.whoami?.length;
|
||||||
this.ids = ids;
|
this.ids = ids;
|
||||||
|
let private_closed =
|
||||||
|
(await tfrpc.rpc.databaseGet('private_closed')) ?? '{}';
|
||||||
|
this.private_closed = JSON.parse(private_closed);
|
||||||
await this.load_channels();
|
await this.load_channels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async close_private_chat(event) {
|
||||||
|
let update = {};
|
||||||
|
update[event.detail.key] = true;
|
||||||
|
this.private_closed = Object.assign(update, this.private_closed);
|
||||||
|
await tfrpc.rpc.databaseSet(
|
||||||
|
'private_closed',
|
||||||
|
JSON.stringify(this.private_closed)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async load_channels() {
|
async load_channels() {
|
||||||
let channels = await tfrpc.rpc.query(
|
let channels = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
@@ -133,12 +151,32 @@ class TfElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visible_private() {
|
||||||
|
if (!this.grouped_private_messages || !this.private_closed) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let self = this;
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(this.grouped_private_messages).filter(([key, value]) => {
|
||||||
|
let channel = '🔐' + [...new Set(JSON.parse(key))].sort().join(',');
|
||||||
|
let grouped_latest = Math.max(...value.map((x) => x.rowid));
|
||||||
|
return (
|
||||||
|
!self.private_closed[key] ||
|
||||||
|
self.channels_unread[channel] === undefined ||
|
||||||
|
grouped_latest > self.channels_unread[channel]
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
next_channel(delta) {
|
next_channel(delta) {
|
||||||
let channel_names = [
|
let channel_names = [
|
||||||
'',
|
'',
|
||||||
'@',
|
'@',
|
||||||
'👍',
|
'👍',
|
||||||
'🔐',
|
...Object.keys(this.visible_private())
|
||||||
|
.sort()
|
||||||
|
.map((x) => '🔐' + JSON.parse(x).join(',')),
|
||||||
...this.channels.map((x) => '#' + x),
|
...this.channels.map((x) => '#' + x),
|
||||||
];
|
];
|
||||||
let index = channel_names.indexOf(this.hash.substring(1));
|
let index = channel_names.indexOf(this.hash.substring(1));
|
||||||
@@ -364,6 +402,36 @@ class TfElement extends LitElement {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async group_private_messages(messages) {
|
||||||
|
let groups = {};
|
||||||
|
let result = await this.decrypt(
|
||||||
|
await tfrpc.rpc.query(
|
||||||
|
`
|
||||||
|
SELECT messages.rowid, messages.id, author, timestamp, json(content) AS content
|
||||||
|
FROM messages
|
||||||
|
JOIN json_each(?) AS ids
|
||||||
|
WHERE messages.id = ids.value
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
`,
|
||||||
|
[JSON.stringify(messages)]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (let message of result) {
|
||||||
|
let key = JSON.stringify(
|
||||||
|
[
|
||||||
|
...new Set(
|
||||||
|
message?.decrypted?.recps?.filter((x) => x != this.whoami)
|
||||||
|
),
|
||||||
|
].sort() ?? []
|
||||||
|
);
|
||||||
|
if (!groups[key]) {
|
||||||
|
groups[key] = [];
|
||||||
|
}
|
||||||
|
groups[key].push(message);
|
||||||
|
}
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
async load_channels_latest(following) {
|
async load_channels_latest(following) {
|
||||||
let start_time = new Date();
|
let start_time = new Date();
|
||||||
let latest_private = this.get_latest_private(following);
|
let latest_private = this.get_latest_private(following);
|
||||||
@@ -436,12 +504,15 @@ class TfElement extends LitElement {
|
|||||||
console.log('channels took', (new Date() - start_time) / 1000.0);
|
console.log('channels took', (new Date() - start_time) / 1000.0);
|
||||||
let self = this;
|
let self = this;
|
||||||
start_time = new Date();
|
start_time = new Date();
|
||||||
latest_private.then(function (latest) {
|
latest_private.then(async function (latest) {
|
||||||
self.channels_latest = Object.assign({}, self.channels_latest, {
|
self.channels_latest = Object.assign({}, self.channels_latest, {
|
||||||
'🔐': latest[0],
|
'🔐': latest[0],
|
||||||
});
|
});
|
||||||
console.log('private took', (new Date() - start_time) / 1000.0);
|
console.log('private took', (new Date() - start_time) / 1000.0);
|
||||||
self.private_messages = latest[1];
|
self.private_messages = latest[1];
|
||||||
|
self.grouped_private_messages = await self.group_private_messages(
|
||||||
|
latest[1]
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +521,28 @@ class TfElement extends LitElement {
|
|||||||
this.schedule_load_latest();
|
this.schedule_load_latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset_progress() {
|
||||||
|
if (this.progress === undefined) {
|
||||||
|
this._progress_start = new Date();
|
||||||
|
requestAnimationFrame(this.update_progress.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_progress() {
|
||||||
|
if (
|
||||||
|
!this.loading_latest &&
|
||||||
|
!this.loading_latest_scheduled &&
|
||||||
|
!this.shadowRoot.getElementById('tf-tab-news')?.is_loading()
|
||||||
|
) {
|
||||||
|
this.progress = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.progress = (new Date() - this._progress_start).valueOf();
|
||||||
|
requestAnimationFrame(this.update_progress.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
schedule_load_latest() {
|
schedule_load_latest() {
|
||||||
|
this.reset_progress();
|
||||||
if (!this.loading_latest) {
|
if (!this.loading_latest) {
|
||||||
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
|
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
|
||||||
this.load();
|
this.load();
|
||||||
@@ -495,6 +587,7 @@ class TfElement extends LitElement {
|
|||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.loading_latest = true;
|
this.loading_latest = true;
|
||||||
|
this.reset_progress();
|
||||||
try {
|
try {
|
||||||
let start_time = new Date();
|
let start_time = new Date();
|
||||||
let whoami = this.whoami;
|
let whoami = this.whoami;
|
||||||
@@ -603,8 +696,11 @@ class TfElement extends LitElement {
|
|||||||
@channelsetunread=${this.channel_set_unread}
|
@channelsetunread=${this.channel_set_unread}
|
||||||
@refresh=${this.refresh}
|
@refresh=${this.refresh}
|
||||||
@toggle_stay_connected=${this.toggle_stay_connected}
|
@toggle_stay_connected=${this.toggle_stay_connected}
|
||||||
|
@loadmessages=${this.reset_progress}
|
||||||
|
@closeprivatechat=${this.close_private_chat}
|
||||||
.connections=${this.connections}
|
.connections=${this.connections}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
|
.grouped_private_messages=${this.visible_private()}
|
||||||
.recent_reactions=${this.recent_reactions}
|
.recent_reactions=${this.recent_reactions}
|
||||||
?is_administrator=${this.is_administrator}
|
?is_administrator=${this.is_administrator}
|
||||||
?stay_connected=${this.stay_connected}
|
?stay_connected=${this.stay_connected}
|
||||||
@@ -646,6 +742,7 @@ class TfElement extends LitElement {
|
|||||||
async set_tab(tab) {
|
async set_tab(tab) {
|
||||||
this.tab = tab;
|
this.tab = tab;
|
||||||
if (tab === 'news') {
|
if (tab === 'news') {
|
||||||
|
this.schedule_load_latest();
|
||||||
await tfrpc.rpc.setHash('#');
|
await tfrpc.rpc.setHash('#');
|
||||||
} else if (tab === 'connections') {
|
} else if (tab === 'connections') {
|
||||||
await tfrpc.rpc.setHash('#connections');
|
await tfrpc.rpc.setHash('#connections');
|
||||||
@@ -751,11 +848,23 @@ class TfElement extends LitElement {
|
|||||||
Loading...
|
Loading...
|
||||||
</div>`
|
</div>`
|
||||||
: this.render_tab();
|
: this.render_tab();
|
||||||
|
let progress =
|
||||||
|
this.progress !== undefined
|
||||||
|
? html`
|
||||||
|
<div style="position: absolute; width: 100%" id="progress">
|
||||||
|
<div
|
||||||
|
class="w3-theme-l3"
|
||||||
|
style=${`height: 4px; position: absolute; right: ${Math.cos(this.progress / 250) > 0 ? 'auto' : '0'}; width: ${50 * Math.sin(this.progress / 250) + 50}%`}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: undefined;
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
|
style="width: 100vw; min-height: 100vh; height: 100vh; display: flex; flex-direction: column"
|
||||||
class="w3-theme-dark"
|
class="w3-theme-dark"
|
||||||
>
|
>
|
||||||
|
${progress}
|
||||||
<div style="flex: 0 0">${tabs}</div>
|
<div style="flex: 0 0">${tabs}</div>
|
||||||
<div style="flex: 1 1; overflow: auto; contain: layout">
|
<div style="flex: 1 1; overflow: auto; contain: layout">
|
||||||
${contents}
|
${contents}
|
||||||
|
@@ -16,6 +16,7 @@ class TfComposeElement extends LitElement {
|
|||||||
author: {type: String},
|
author: {type: String},
|
||||||
channel: {type: String},
|
channel: {type: String},
|
||||||
new_thread: {type: Boolean},
|
new_thread: {type: Boolean},
|
||||||
|
recipients: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +92,9 @@ class TfComposeElement extends LitElement {
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
detail: {
|
detail: {
|
||||||
id: this.branch,
|
id:
|
||||||
|
this.branch ??
|
||||||
|
(this.recipients ? this.recipients.join(',') : undefined),
|
||||||
draft: draft,
|
draft: draft,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -291,7 +294,7 @@ class TfComposeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
get_values() {
|
||||||
let values = Object.entries(this.users).map((x) => ({
|
let values = Object.entries(this.users).map((x) => ({
|
||||||
key: x[1].name ?? x[0],
|
key: x[1].name ?? x[0],
|
||||||
value: x[0],
|
value: x[0],
|
||||||
@@ -307,11 +310,15 @@ class TfComposeElement extends LitElement {
|
|||||||
values
|
values
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
let tribute = new Tribute({
|
let tribute = new Tribute({
|
||||||
iframe: this.shadowRoot,
|
iframe: this.shadowRoot,
|
||||||
collection: [
|
collection: [
|
||||||
{
|
{
|
||||||
values: values,
|
values: this.get_values(),
|
||||||
selectTemplate: function (item) {
|
selectTemplate: function (item) {
|
||||||
return item
|
return item
|
||||||
? `[@${item.original.key}](${item.original.value})`
|
? `[@${item.original.key}](${item.original.value})`
|
||||||
@@ -330,6 +337,7 @@ class TfComposeElement extends LitElement {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
tribute.attach(this.renderRoot.getElementById('edit'));
|
tribute.attach(this.renderRoot.getElementById('edit'));
|
||||||
|
this._tribute = tribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
@@ -340,6 +348,7 @@ class TfComposeElement extends LitElement {
|
|||||||
preview.innerHTML = this.process_text(edit.innerText);
|
preview.innerHTML = this.process_text(edit.innerText);
|
||||||
this.last_updated_text = edit.innerText;
|
this.last_updated_text = edit.innerText;
|
||||||
}
|
}
|
||||||
|
this._tribute.collection[0].values = this.get_values();
|
||||||
let encrypt = this.renderRoot.getElementById('encrypt_to');
|
let encrypt = this.renderRoot.getElementById('encrypt_to');
|
||||||
if (encrypt) {
|
if (encrypt) {
|
||||||
let tribute = new Tribute({
|
let tribute = new Tribute({
|
||||||
@@ -496,7 +505,17 @@ class TfComposeElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_draft() {
|
get_draft() {
|
||||||
return this.drafts[this.branch || ''] || {};
|
let key =
|
||||||
|
this.branch ||
|
||||||
|
(this.recipients ? this.recipients.join(',') : undefined) ||
|
||||||
|
'';
|
||||||
|
let draft = this.drafts[key] || {};
|
||||||
|
if (this.recipients && !draft.encrypt_to?.length) {
|
||||||
|
draft.encrypt_to = [
|
||||||
|
...new Set(this.recipients).union(new Set(draft.encrypt_to ?? [])),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return draft;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_encrypt(event) {
|
update_encrypt(event) {
|
||||||
|
@@ -789,10 +789,16 @@ class TfMessageElement extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
} else if (content.type == 'contact') {
|
} else if (content.type == 'contact') {
|
||||||
|
switch (this.format) {
|
||||||
|
case 'message':
|
||||||
|
default:
|
||||||
return this.render_frame(html`
|
return this.render_frame(html`
|
||||||
<div class="w3-bar">
|
<div class="w3-bar">
|
||||||
<div class="w3-bar-item">
|
<div class="w3-bar-item">
|
||||||
<tf-user id=${this.message.author} .users=${this.users}></tf-user>
|
<tf-user
|
||||||
|
id=${this.message.author}
|
||||||
|
.users=${this.users}
|
||||||
|
></tf-user>
|
||||||
is
|
is
|
||||||
${content.blocking === true
|
${content.blocking === true
|
||||||
? 'blocking'
|
? 'blocking'
|
||||||
@@ -808,41 +814,20 @@ class TfMessageElement extends LitElement {
|
|||||||
.users=${this.users}
|
.users=${this.users}
|
||||||
></tf-user>
|
></tf-user>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-bar-item w3-right">
|
${this.render_menu()} ${this.render_votes()}
|
||||||
<button class="w3-button w3-theme-d1" @click=${this.toggle_menu}>
|
${this.render_actions()}
|
||||||
%
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
class="w3-dropdown-content w3-bar-block w3-card-4 w3-theme-l1"
|
|
||||||
style="right: 48px"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
target="_top"
|
|
||||||
class="w3-button w3-bar-item"
|
|
||||||
href=${'#' + encodeURIComponent(this.message?.id)}
|
|
||||||
>View Message</a
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item w3-border-bottom"
|
|
||||||
@click=${this.copy_id}
|
|
||||||
>
|
|
||||||
Copy ID
|
|
||||||
</button>
|
|
||||||
${this.drafts[this.message?.id] === undefined
|
|
||||||
? html`
|
|
||||||
<button
|
|
||||||
class="w3-button w3-bar-item"
|
|
||||||
@click=${this.show_reply}
|
|
||||||
>
|
|
||||||
↩️ Reply
|
|
||||||
</button>
|
|
||||||
`
|
|
||||||
: undefined}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
`);
|
||||||
|
break;
|
||||||
|
case 'raw':
|
||||||
|
return this.render_frame(html`
|
||||||
|
${this.render_header()}
|
||||||
|
<div class="w3-container">${this.render_raw()}</div>
|
||||||
${this.render_votes()} ${this.render_actions()}
|
${this.render_votes()} ${this.render_actions()}
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else if (content.type == 'post') {
|
} else if (content.type == 'post') {
|
||||||
let self = this;
|
let self = this;
|
||||||
let body;
|
let body;
|
||||||
|
@@ -349,6 +349,9 @@ class TfProfileElement extends LitElement {
|
|||||||
${until(this.load_follows(), html`<p>Loading accounts followed...</p>`)}
|
${until(this.load_follows(), html`<p>Loading accounts followed...</p>`)}
|
||||||
<footer class="w3-container">
|
<footer class="w3-container">
|
||||||
<p>
|
<p>
|
||||||
|
<a class="w3-button w3-theme-d1" href=${'#🔐' + (this.id != this.whoami ? this.id : '')}>
|
||||||
|
Open Private Chat
|
||||||
|
</a>
|
||||||
${edit}
|
${edit}
|
||||||
${follow}
|
${follow}
|
||||||
${block}
|
${block}
|
||||||
|
@@ -43,6 +43,8 @@ const tf = css`
|
|||||||
border-left: 4px solid #fff;
|
border-left: 4px solid #fff;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
time_range: {type: Array},
|
time_range: {type: Array},
|
||||||
time_loading: {type: Array},
|
time_loading: {type: Array},
|
||||||
private_messages: {type: Array},
|
private_messages: {type: Array},
|
||||||
|
grouped_private_messages: {type: Object},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -106,6 +107,12 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetch_messages(start_time, end_time) {
|
async fetch_messages(start_time, end_time) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('loadmessages', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
this.time_loading = [start_time, end_time];
|
this.time_loading = [start_time, end_time];
|
||||||
let result;
|
let result;
|
||||||
const k_max_results = 64;
|
const k_max_results = 64;
|
||||||
@@ -202,7 +209,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
console.log(
|
console.log(
|
||||||
`load of ${result.length} rows took ${(t2 - t0) / 1000} (${(t1 - t0) / 1000} to find ${initial_messages.length} initial messages, ${(t2 - t1) / 1000} to find ${result.length} total messages) following=${this.following.length} st=${start_time} et=${end_time}`
|
`load of ${result.length} rows took ${(t2 - t0) / 1000} (${(t1 - t0) / 1000} to find ${initial_messages.length} initial messages, ${(t2 - t1) / 1000} to find ${result.length} total messages) following=${this.following.length} st=${start_time} et=${end_time}`
|
||||||
);
|
);
|
||||||
} else if (this.hash == '#🔐') {
|
} else if (this.hash.startsWith('#🔐')) {
|
||||||
|
let ids =
|
||||||
|
this.hash == '#🔐' ? [] : this.hash.substring('#🔐'.length).split(',');
|
||||||
result = await tfrpc.rpc.query(
|
result = await tfrpc.rpc.query(
|
||||||
`
|
`
|
||||||
SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
SELECT TRUE AS is_primary, messages.rowid, messages.id, previous, author, sequence, timestamp, hash, json(content) AS content, signature
|
||||||
@@ -214,7 +223,11 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
ORDER BY messages.rowid DESC LIMIT ?4
|
ORDER BY messages.rowid DESC LIMIT ?4
|
||||||
`,
|
`,
|
||||||
[
|
[
|
||||||
JSON.stringify(this.private_messages),
|
JSON.stringify(
|
||||||
|
this.grouped_private_messages?.[JSON.stringify(ids)]?.map(
|
||||||
|
(x) => x.id
|
||||||
|
) ?? []
|
||||||
|
),
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
k_max_results,
|
k_max_results,
|
||||||
@@ -373,12 +386,16 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
let self = this;
|
let self = this;
|
||||||
this.loading++;
|
this.loading++;
|
||||||
let messages = [];
|
let messages = [];
|
||||||
|
let original_hash = this.hash;
|
||||||
try {
|
try {
|
||||||
if (this._messages_hash !== this.hash) {
|
if (this._messages_hash !== this.hash) {
|
||||||
this.messages = [];
|
this.messages = [];
|
||||||
this._messages_hash = this.hash;
|
this._messages_hash = this.hash;
|
||||||
}
|
}
|
||||||
this._messages_following = this.following;
|
this._messages_following = JSON.stringify(this.following);
|
||||||
|
this._private_messages =
|
||||||
|
JSON.stringify(this.private_messages) +
|
||||||
|
JSON.stringify(this.grouped_private_messages);
|
||||||
let now = new Date().valueOf();
|
let now = new Date().valueOf();
|
||||||
let start_time = now - 24 * 60 * 60 * 1000;
|
let start_time = now - 24 * 60 * 60 * 1000;
|
||||||
this.start_time = start_time;
|
this.start_time = start_time;
|
||||||
@@ -391,7 +408,9 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
} finally {
|
} finally {
|
||||||
this.loading--;
|
this.loading--;
|
||||||
}
|
}
|
||||||
|
if (this.hash == original_hash) {
|
||||||
this.messages = this.merge_messages(this.messages, messages);
|
this.messages = this.merge_messages(this.messages, messages);
|
||||||
|
}
|
||||||
this.time_loading = undefined;
|
this.time_loading = undefined;
|
||||||
console.log(
|
console.log(
|
||||||
`loading ${messages.length} messages done for ${self.whoami} in ${(new Date() - start_time) / 1000}s`
|
`loading ${messages.length} messages done for ${self.whoami} in ${(new Date() - start_time) / 1000}s`
|
||||||
@@ -417,12 +436,42 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close_private_chat() {
|
||||||
|
this.mark_all_read();
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('closeprivatechat', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: {
|
||||||
|
key: JSON.stringify(
|
||||||
|
this.hash == '#🔐'
|
||||||
|
? []
|
||||||
|
: this.hash.substring('#🔐'.length).split(',')
|
||||||
|
),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
tfrpc.rpc.setHash('#');
|
||||||
|
}
|
||||||
|
|
||||||
|
render_close_chat_button() {
|
||||||
|
if (this.hash.startsWith('#🔐')) {
|
||||||
|
return html`
|
||||||
|
<button class="w3-button w3-theme-d1" @click=${this.close_private_chat}>
|
||||||
|
Close Chat
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (
|
if (
|
||||||
!this.messages ||
|
!this.messages ||
|
||||||
this._messages_hash !== this.hash ||
|
this._messages_hash !== this.hash ||
|
||||||
JSON.stringify(this._messages_following) !==
|
this._messages_following !== JSON.stringify(this.following) ||
|
||||||
JSON.stringify(this.following)
|
this._private_messages !==
|
||||||
|
JSON.stringify(this.private_messages) +
|
||||||
|
JSON.stringify(this.grouped_private_messages)
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
`loading messages for ${this.whoami} (following ${this.following.length})`
|
`loading messages for ${this.whoami} (following ${this.following.length})`
|
||||||
@@ -482,6 +531,7 @@ class TfTabNewsFeedElement extends LitElement {
|
|||||||
Mark All Read
|
Mark All Read
|
||||||
</button>`
|
</button>`
|
||||||
: undefined}
|
: undefined}
|
||||||
|
${this.render_close_chat_button()}
|
||||||
<tf-news
|
<tf-news
|
||||||
id="news"
|
id="news"
|
||||||
whoami=${this.whoami}
|
whoami=${this.whoami}
|
||||||
|
@@ -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},
|
||||||
|
grouped_private_messages: {type: Object},
|
||||||
recent_reactions: {type: Array},
|
recent_reactions: {type: Array},
|
||||||
peer_exchange: {type: Boolean},
|
peer_exchange: {type: Boolean},
|
||||||
is_administrator: {type: Boolean},
|
is_administrator: {type: Boolean},
|
||||||
@@ -115,6 +116,19 @@ class TfTabNewsElement extends LitElement {
|
|||||||
) {
|
) {
|
||||||
return '✉️ ';
|
return '✉️ ';
|
||||||
}
|
}
|
||||||
|
} else if (channel?.startsWith('🔐')) {
|
||||||
|
let key = JSON.stringify(channel.substring('🔐'.length).split(','));
|
||||||
|
if (this.grouped_private_messages?.[key]) {
|
||||||
|
let grouped_latest = Math.max(
|
||||||
|
...this.grouped_private_messages?.[key]?.map((x) => x.rowid)
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
this.channels_unread[channel] === undefined ||
|
||||||
|
grouped_latest > this.channels_unread[channel]
|
||||||
|
) {
|
||||||
|
return '✉️ ';
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
this.channels_latest[channel] &&
|
this.channels_latest[channel] &&
|
||||||
this.channels_latest[channel] > 0 &&
|
this.channels_latest[channel] > 0 &&
|
||||||
@@ -180,6 +194,10 @@ class TfTabNewsElement extends LitElement {
|
|||||||
await this.check_peer_exchange();
|
await this.check_peer_exchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_loading() {
|
||||||
|
return this.shadowRoot?.getElementById('news')?.loading;
|
||||||
|
}
|
||||||
|
|
||||||
render_sidebar() {
|
render_sidebar() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
@@ -253,12 +271,29 @@ class TfTabNewsElement extends LitElement {
|
|||||||
style=${this.hash == '#👍' ? 'font-weight: bold' : undefined}
|
style=${this.hash == '#👍' ? 'font-weight: bold' : undefined}
|
||||||
>${this.unread_status('👍')}👍votes</a
|
>${this.unread_status('👍')}👍votes</a
|
||||||
>
|
>
|
||||||
|
${Object.keys(this?.grouped_private_messages ?? [])
|
||||||
|
?.sort()
|
||||||
|
?.map(
|
||||||
|
(key) => html`
|
||||||
<a
|
<a
|
||||||
href="#🔐"
|
href=${'#🔐' + JSON.parse(key).join(',')}
|
||||||
class="w3-bar-item w3-button"
|
class="w3-bar-item w3-button"
|
||||||
style=${this.hash == '#🔐' ? 'font-weight: bold' : undefined}
|
style=${this.hash == '#🔐' + JSON.parse(key).join(',')
|
||||||
>${this.unread_status('🔐')}🔐private</a
|
? 'font-weight: bold'
|
||||||
|
: undefined}
|
||||||
|
>${this.unread_status('🔐' + JSON.parse(key).join(','))}
|
||||||
|
${(key != '[]' ? JSON.parse(key) : [this.whoami]).map(
|
||||||
|
(id) => html`
|
||||||
|
<tf-user
|
||||||
|
id=${id}
|
||||||
|
nolink="true"
|
||||||
|
.users=${this.users}
|
||||||
|
></tf-user>
|
||||||
|
`
|
||||||
|
)}</a
|
||||||
>
|
>
|
||||||
|
`
|
||||||
|
)}
|
||||||
${Object.keys(this.drafts)
|
${Object.keys(this.drafts)
|
||||||
.sort()
|
.sort()
|
||||||
.map(
|
.map(
|
||||||
@@ -414,6 +449,9 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.drafts=${this.drafts}
|
.drafts=${this.drafts}
|
||||||
@tf-draft=${this.draft}
|
@tf-draft=${this.draft}
|
||||||
.channel=${this.channel()}
|
.channel=${this.channel()}
|
||||||
|
.recipients=${this.hash.startsWith('#🔐')
|
||||||
|
? this.hash.substring('#🔐'.length).split(',')
|
||||||
|
: undefined}
|
||||||
></tf-compose>
|
></tf-compose>
|
||||||
</div>
|
</div>
|
||||||
${profile}
|
${profile}
|
||||||
@@ -430,6 +468,7 @@ class TfTabNewsElement extends LitElement {
|
|||||||
.channels_unread=${this.channels_unread}
|
.channels_unread=${this.channels_unread}
|
||||||
.channels_latest=${this.channels_latest}
|
.channels_latest=${this.channels_latest}
|
||||||
.private_messages=${this.private_messages}
|
.private_messages=${this.private_messages}
|
||||||
|
.grouped_private_messages=${this.grouped_private_messages}
|
||||||
.recent_reactions=${this.recent_reactions}
|
.recent_reactions=${this.recent_reactions}
|
||||||
></tf-tab-news-feed>
|
></tf-tab-news-feed>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -9,6 +9,7 @@ class TfUserElement extends LitElement {
|
|||||||
fallback_name: {type: String},
|
fallback_name: {type: String},
|
||||||
icon_only: {type: Boolean},
|
icon_only: {type: Boolean},
|
||||||
users: {type: Object},
|
users: {type: Object},
|
||||||
|
nolink: {type: Boolean},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +38,9 @@ class TfUserElement extends LitElement {
|
|||||||
let name_string = name ?? this.fallback_name ?? this.id;
|
let name_string = name ?? this.fallback_name ?? this.id;
|
||||||
name = this.icon_only
|
name = this.icon_only
|
||||||
? undefined
|
? undefined
|
||||||
: html`<a target="_top" href=${'#' + this.id}>${name_string}</a>`;
|
: !this.nolink
|
||||||
|
? html`<a target="_top" href=${'#' + this.id}>${name_string}</a>`
|
||||||
|
: html`<span>${name_string}</span>`;
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
let image_link = user.image;
|
let image_link = user.image;
|
||||||
@@ -56,7 +59,8 @@ class TfUserElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return html` <div
|
return html` <div
|
||||||
style="display: inline-block; vertical-align: middle; font-weight: bold; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis"
|
style=${'display: inline-block; vertical-align: middle; text-wrap: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis' +
|
||||||
|
(this.nolink ? '' : '; font-weight: bold')}
|
||||||
>
|
>
|
||||||
${image} ${name}
|
${image} ${name}
|
||||||
</div>`;
|
</div>`;
|
||||||
|
37
core/app.js
37
core/app.js
@@ -1,7 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfapp Tilde Friends App JS
|
||||||
|
* Tilde Friends server-side app wrapper.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
import * as core from './core.js';
|
import * as core from './core.js';
|
||||||
|
|
||||||
let gSessionIndex = 0;
|
export {App};
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
|
/** A sequence number of apps. */
|
||||||
|
let g_session_index = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
** App constructor.
|
||||||
|
** @return An app instance.
|
||||||
|
*/
|
||||||
function App() {
|
function App() {
|
||||||
this._send_queue = [];
|
this._send_queue = [];
|
||||||
this.calls = {};
|
this.calls = {};
|
||||||
@@ -9,6 +25,12 @@ function App() {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Create a function wrapper that when called invokes a function on the app
|
||||||
|
** itself.
|
||||||
|
** @param api The function and argument names.
|
||||||
|
** @return A function.
|
||||||
|
*/
|
||||||
App.prototype.makeFunction = function (api) {
|
App.prototype.makeFunction = function (api) {
|
||||||
let self = this;
|
let self = this;
|
||||||
let result = function () {
|
let result = function () {
|
||||||
@@ -32,6 +54,10 @@ App.prototype.makeFunction = function (api) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Send a message to the app.
|
||||||
|
** @param message The message to send.
|
||||||
|
*/
|
||||||
App.prototype.send = function (message) {
|
App.prototype.send = function (message) {
|
||||||
if (this._send_queue) {
|
if (this._send_queue) {
|
||||||
if (this._on_output) {
|
if (this._on_output) {
|
||||||
@@ -46,6 +72,11 @@ App.prototype.send = function (message) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
** App socket handler.
|
||||||
|
** @param request The HTTP request of the WebSocket connection.
|
||||||
|
** @param response The HTTP response.
|
||||||
|
*/
|
||||||
exports.app_socket = async function socket(request, response) {
|
exports.app_socket = async function socket(request, response) {
|
||||||
let process;
|
let process;
|
||||||
let options = {};
|
let options = {};
|
||||||
@@ -133,7 +164,7 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
options.packageOwner = packageOwner;
|
options.packageOwner = packageOwner;
|
||||||
options.packageName = packageName;
|
options.packageName = packageName;
|
||||||
options.url = message.url;
|
options.url = message.url;
|
||||||
let sessionId = 'session_' + (gSessionIndex++).toString();
|
let sessionId = 'session_' + (g_session_index++).toString();
|
||||||
if (blobId) {
|
if (blobId) {
|
||||||
if (message.edit_only) {
|
if (message.edit_only) {
|
||||||
response.send(
|
response.send(
|
||||||
@@ -218,4 +249,4 @@ exports.app_socket = async function socket(request, response) {
|
|||||||
response.upgrade(100, {});
|
response.upgrade(100, {});
|
||||||
};
|
};
|
||||||
|
|
||||||
export {App};
|
/** @} */
|
||||||
|
406
core/client.js
406
core/client.js
@@ -1,3 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfclient Tilde Friends Client JS
|
||||||
|
* Tilde Friends client-side browser JavaScript.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
import {LitElement, html, css, svg} from '/lit/lit-all.min.js';
|
import {LitElement, html, css, svg} from '/lit/lit-all.min.js';
|
||||||
|
|
||||||
let cm6;
|
let cm6;
|
||||||
@@ -13,8 +21,9 @@ let gUnloading;
|
|||||||
let kErrorColor = '#dc322f';
|
let kErrorColor = '#dc322f';
|
||||||
let kDisconnectColor = '#f00';
|
let kDisconnectColor = '#f00';
|
||||||
let kStatusColor = '#fff';
|
let kStatusColor = '#fff';
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
// Functions that server-side app code can call through the app object.
|
/** Functions that server-side app code can call through the app object. */
|
||||||
const k_api = {
|
const k_api = {
|
||||||
setDocument: {args: ['content'], func: api_setDocument},
|
setDocument: {args: ['content'], func: api_setDocument},
|
||||||
postMessage: {args: ['message'], func: api_postMessage},
|
postMessage: {args: ['message'], func: api_postMessage},
|
||||||
@@ -26,29 +35,14 @@ const k_api = {
|
|||||||
setHash: {args: ['hash'], func: api_setHash},
|
setHash: {args: ['hash'], func: api_setHash},
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(tasiaiso): this is only used once, move it down ?
|
|
||||||
const k_global_style = css`
|
|
||||||
a:link {
|
|
||||||
color: #268bd2;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: #6c71c4;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #859900;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:active {
|
|
||||||
color: #2aa198;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that represents the top bar
|
* Class that represents the top bar
|
||||||
*/
|
*/
|
||||||
class TfNavigationElement extends LitElement {
|
class TfNavigationElement extends LitElement {
|
||||||
|
/**
|
||||||
|
* Get Lit Html properties.
|
||||||
|
* @return The properties.
|
||||||
|
*/
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
credentials: {type: Object},
|
credentials: {type: Object},
|
||||||
@@ -64,6 +58,9 @@ class TfNavigationElement extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TfNavigationElement instance.
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.permissions = {};
|
this.permissions = {};
|
||||||
@@ -75,8 +72,8 @@ class TfNavigationElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Toggle editor visibility.
|
||||||
* @param {*} event
|
* @param event The HTML event.
|
||||||
*/
|
*/
|
||||||
toggle_edit(event) {
|
toggle_edit(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -88,18 +85,18 @@ class TfNavigationElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Remove a stored permission.
|
||||||
* @param {*} key
|
* @param key The permission to reset.
|
||||||
*/
|
*/
|
||||||
reset_permission(key) {
|
reset_permission(key) {
|
||||||
send({action: 'resetPermission', permission: key});
|
send({action: 'resetPermission', permission: key});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Get or create a spark line.
|
||||||
* @param {*} key
|
* @param key The spark line identifier.
|
||||||
* @param {*} options
|
* @param options Spark line options.
|
||||||
* @returns
|
* @return A spark line HTML element.
|
||||||
*/
|
*/
|
||||||
get_spark_line(key, options) {
|
get_spark_line(key, options) {
|
||||||
if (!this.spark_lines[key]) {
|
if (!this.spark_lines[key]) {
|
||||||
@@ -118,29 +115,49 @@ class TfNavigationElement extends LitElement {
|
|||||||
return this.spark_lines[key];
|
return this.spark_lines[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the active SSB identity for the current application.
|
||||||
|
* @param id The identity.
|
||||||
|
*/
|
||||||
set_active_identity(id) {
|
set_active_identity(id) {
|
||||||
send({action: 'setActiveIdentity', identity: id});
|
send({action: 'setActiveIdentity', identity: id});
|
||||||
this.renderRoot.getElementById('id_dropdown').classList.remove('w3-show');
|
this.renderRoot.getElementById('id_dropdown').classList.remove('w3-show');
|
||||||
}
|
}
|
||||||
|
|
||||||
create_identity(event) {
|
/**
|
||||||
|
* Create a new SSB identity.
|
||||||
|
*/
|
||||||
|
create_identity() {
|
||||||
if (confirm('Are you sure you want to create a new identity?')) {
|
if (confirm('Are you sure you want to create a new identity?')) {
|
||||||
send({action: 'createIdentity'});
|
send({action: 'createIdentity'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle visibility of the ID dropdown.
|
||||||
|
*/
|
||||||
toggle_id_dropdown() {
|
toggle_id_dropdown() {
|
||||||
this.renderRoot.getElementById('id_dropdown').classList.toggle('w3-show');
|
this.renderRoot.getElementById('id_dropdown').classList.toggle('w3-show');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit the current identity's SSB profile.
|
||||||
|
*/
|
||||||
edit_profile() {
|
edit_profile() {
|
||||||
window.location.href = '/~core/ssb/#' + this.identity;
|
window.location.href = '/~core/ssb/#' + this.identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign out of the current Tilde Friends user.
|
||||||
|
*/
|
||||||
logout() {
|
logout() {
|
||||||
window.location.href = `/login/logout?return=${encodeURIComponent(url() + hash())}`;
|
window.location.href = `/login/logout?return=${encodeURIComponent(url() + hash())}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the identity dropdown.
|
||||||
|
* @return Lit HTML.
|
||||||
|
*/
|
||||||
render_identity() {
|
render_identity() {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
@@ -245,8 +262,8 @@ class TfNavigationElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render the permissions popup.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render_permissions() {
|
render_permissions() {
|
||||||
if (this.show_permissions) {
|
if (this.show_permissions) {
|
||||||
@@ -287,16 +304,36 @@ class TfNavigationElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the current error.
|
||||||
|
*/
|
||||||
clear_error() {
|
clear_error() {
|
||||||
this.status = {};
|
this.status = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render the navigation bar.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
|
const k_global_style = css`
|
||||||
|
a:link {
|
||||||
|
color: #268bd2;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: #6c71c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #859900;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active {
|
||||||
|
color: #2aa198;
|
||||||
|
}
|
||||||
|
`;
|
||||||
return html`
|
return html`
|
||||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||||
<style>
|
<style>
|
||||||
@@ -404,9 +441,13 @@ class TfNavigationElement extends LitElement {
|
|||||||
customElements.define('tf-navigation', TfNavigationElement);
|
customElements.define('tf-navigation', TfNavigationElement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* A file in the files sidebar.
|
||||||
*/
|
*/
|
||||||
class TfFilesElement extends LitElement {
|
class TfFilesElement extends LitElement {
|
||||||
|
/**
|
||||||
|
* LitElement properties.
|
||||||
|
* @return The properties.
|
||||||
|
*/
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
current: {type: String},
|
current: {type: String},
|
||||||
@@ -416,6 +457,9 @@ class TfFilesElement extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TfFilesElement instance.
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.files = {};
|
this.files = {};
|
||||||
@@ -423,8 +467,8 @@ class TfFilesElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Select a clicked file.
|
||||||
* @param {*} file
|
* @param file The file.
|
||||||
*/
|
*/
|
||||||
file_click(file) {
|
file_click(file) {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
@@ -439,9 +483,9 @@ class TfFilesElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render a single file in the file list.
|
||||||
* @param {*} file
|
* @param file The file.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render_file(file) {
|
render_file(file) {
|
||||||
let classes = ['file'];
|
let classes = ['file'];
|
||||||
@@ -463,8 +507,8 @@ class TfFilesElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Create a file entry for a dropped file.
|
||||||
* @param {*} event
|
* @param event The event.
|
||||||
*/
|
*/
|
||||||
async drop(event) {
|
async drop(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -489,8 +533,8 @@ class TfFilesElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Called when a file starts being dragged over the file.
|
||||||
* @param {*} event
|
* @param event The event.
|
||||||
*/
|
*/
|
||||||
drag_enter(event) {
|
drag_enter(event) {
|
||||||
this.dropping++;
|
this.dropping++;
|
||||||
@@ -499,8 +543,8 @@ class TfFilesElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Called when a file stops being dragged over the file.
|
||||||
* @param {*} event
|
* @param event The event.
|
||||||
*/
|
*/
|
||||||
drag_leave(event) {
|
drag_leave(event) {
|
||||||
this.dropping--;
|
this.dropping--;
|
||||||
@@ -509,13 +553,17 @@ class TfFilesElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a file is being dragged over the file.
|
||||||
|
* @param event The event.
|
||||||
|
*/
|
||||||
drag_over(event) {
|
drag_over(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render the file.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
@@ -562,9 +610,13 @@ class TfFilesElement extends LitElement {
|
|||||||
customElements.define('tf-files', TfFilesElement);
|
customElements.define('tf-files', TfFilesElement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* The files pane element.
|
||||||
*/
|
*/
|
||||||
class TfFilesPaneElement extends LitElement {
|
class TfFilesPaneElement extends LitElement {
|
||||||
|
/**
|
||||||
|
* Get Lit Html properties.
|
||||||
|
* @return The properties.
|
||||||
|
*/
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
expanded: {type: Boolean},
|
expanded: {type: Boolean},
|
||||||
@@ -573,6 +625,9 @@ class TfFilesPaneElement extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TfFilesPaneElement instance.
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.expanded = window.localStorage.getItem('files') != '0';
|
this.expanded = window.localStorage.getItem('files') != '0';
|
||||||
@@ -580,8 +635,8 @@ class TfFilesPaneElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Set whether the files pane is expanded.
|
||||||
* @param {*} expanded
|
* @param expanded Whether the files pane is expanded.
|
||||||
*/
|
*/
|
||||||
set_expanded(expanded) {
|
set_expanded(expanded) {
|
||||||
this.expanded = expanded;
|
this.expanded = expanded;
|
||||||
@@ -589,8 +644,8 @@ class TfFilesPaneElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render the files pane element.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let self = this;
|
let self = this;
|
||||||
@@ -649,7 +704,7 @@ class TfFilesPaneElement extends LitElement {
|
|||||||
customElements.define('tf-files-pane', TfFilesPaneElement);
|
customElements.define('tf-files-pane', TfFilesPaneElement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* A tiny graph.
|
||||||
*/
|
*/
|
||||||
class TfSparkLineElement extends LitElement {
|
class TfSparkLineElement extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@@ -669,9 +724,9 @@ class TfSparkLineElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Add a data point to the graph.
|
||||||
* @param {*} key
|
* @param key The line to which the point applies.
|
||||||
* @param {*} value
|
* @param value The numeric value of the data point.
|
||||||
*/
|
*/
|
||||||
append(key, value) {
|
append(key, value) {
|
||||||
let line = null;
|
let line = null;
|
||||||
@@ -698,9 +753,9 @@ class TfSparkLineElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render a single series line.
|
||||||
* @param {*} line
|
* @param line The line data.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render_line(line) {
|
render_line(line) {
|
||||||
if (line?.values?.length >= 2) {
|
if (line?.values?.length >= 2) {
|
||||||
@@ -716,8 +771,8 @@ class TfSparkLineElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Render the graph.
|
||||||
* @returns
|
* @return Lit HTML.
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
let max =
|
let max =
|
||||||
@@ -744,7 +799,9 @@ class TfSparkLineElement extends LitElement {
|
|||||||
|
|
||||||
customElements.define('tf-sparkline', TfSparkLineElement);
|
customElements.define('tf-sparkline', TfSparkLineElement);
|
||||||
|
|
||||||
// TODOC
|
/**
|
||||||
|
* A keyboard key is pressed down.
|
||||||
|
*/
|
||||||
window.addEventListener('keydown', function (event) {
|
window.addEventListener('keydown', function (event) {
|
||||||
if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) {
|
if (event.keyCode == 83 && (event.altKey || event.ctrlKey)) {
|
||||||
if (editing()) {
|
if (editing()) {
|
||||||
@@ -760,10 +817,9 @@ window.addEventListener('keydown', function (event) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Make sure a set of dependencies are loaded
|
||||||
* @param {*} nodes
|
* @param nodes An array of descriptions of dependencies to load.
|
||||||
* @param {*} callback
|
* @param callback Called when all dependencies are loaded.
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
function ensureLoaded(nodes, callback) {
|
function ensureLoaded(nodes, callback) {
|
||||||
if (!nodes.length) {
|
if (!nodes.length) {
|
||||||
@@ -806,24 +862,23 @@ function ensureLoaded(nodes, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Check whether the editior is currently visible.
|
||||||
* @returns
|
* @return true if the editor is visible.
|
||||||
*/
|
*/
|
||||||
function editing() {
|
function editing() {
|
||||||
return document.getElementById('editPane').style.display != 'none';
|
return document.getElementById('editPane').style.display != 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Check whether only the editor is visible and the app is hidden.
|
||||||
* @returns
|
* @return true if the editor is visible and the app is not.
|
||||||
*/
|
*/
|
||||||
function is_edit_only() {
|
function is_edit_only() {
|
||||||
return window.location.search == '?editonly=1' || window.innerWidth < 1024;
|
return window.location.search == '?editonly=1' || window.innerWidth < 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Show the editor.
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
async function edit() {
|
async function edit() {
|
||||||
if (editing()) {
|
if (editing()) {
|
||||||
@@ -850,30 +905,17 @@ async function edit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Open a performance trace.
|
||||||
*/
|
*/
|
||||||
function trace() {
|
function trace() {
|
||||||
window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`);
|
window.open(`/speedscope/#profileURL=${encodeURIComponent('/trace')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Load a single file.
|
||||||
* @param {*} name
|
* @param name The name by which the file is known.
|
||||||
* @returns
|
* @param id The file's ID.
|
||||||
*/
|
* @return A promise resolved with the file's contents.
|
||||||
function guessMode(name) {
|
|
||||||
return name.endsWith('.js')
|
|
||||||
? 'javascript'
|
|
||||||
: name.endsWith('.html')
|
|
||||||
? 'htmlmixed'
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} name
|
|
||||||
* @param {*} id
|
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
function loadFile(name, id) {
|
function loadFile(name, id) {
|
||||||
return fetch('/' + id + '/view')
|
return fetch('/' + id + '/view')
|
||||||
@@ -899,9 +941,9 @@ function loadFile(name, id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Load files for the app.
|
||||||
* @param {*} path
|
* @param path The app path to load.
|
||||||
* @returns
|
* @return A promise resolved when the app is laoded.
|
||||||
*/
|
*/
|
||||||
async function load(path) {
|
async function load(path) {
|
||||||
let response = await fetch((path || url()) + 'view');
|
let response = await fetch((path || url()) + 'view');
|
||||||
@@ -941,7 +983,7 @@ async function load(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Hide the editor.
|
||||||
*/
|
*/
|
||||||
function closeEditor() {
|
function closeEditor() {
|
||||||
window.localStorage.setItem('editing', '0');
|
window.localStorage.setItem('editing', '0');
|
||||||
@@ -950,17 +992,9 @@ function closeEditor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Save the app.
|
||||||
* @returns
|
* @param save_to An optional path to which to save the app.
|
||||||
*/
|
* @return A promise resoled when the app is saved.
|
||||||
function explodePath() {
|
|
||||||
return /^\/~([^\/]+)\/([^\/]+)(.*)/.exec(window.location.pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} save_to
|
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
function save(save_to) {
|
function save(save_to) {
|
||||||
document.getElementById('save').disabled = true;
|
document.getElementById('save').disabled = true;
|
||||||
@@ -1070,7 +1104,7 @@ function save(save_to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Prompt to set the app icon.
|
||||||
*/
|
*/
|
||||||
function changeIcon() {
|
function changeIcon() {
|
||||||
let value = prompt('Enter a new app icon emoji:');
|
let value = prompt('Enter a new app icon emoji:');
|
||||||
@@ -1081,7 +1115,7 @@ function changeIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Prompt to delete the current app.
|
||||||
*/
|
*/
|
||||||
function deleteApp() {
|
function deleteApp() {
|
||||||
let name = document.getElementById('name');
|
let name = document.getElementById('name');
|
||||||
@@ -1102,8 +1136,8 @@ function deleteApp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Get the current app URL.
|
||||||
* @returns
|
* @return The app URL.
|
||||||
*/
|
*/
|
||||||
function url() {
|
function url() {
|
||||||
let hash = window.location.href.indexOf('#');
|
let hash = window.location.href.indexOf('#');
|
||||||
@@ -1121,16 +1155,16 @@ function url() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Get the window hash without the lone '#' if it is empty.
|
||||||
* @returns
|
* @return The hash.
|
||||||
*/
|
*/
|
||||||
function hash() {
|
function hash() {
|
||||||
return window.location.hash != '#' ? window.location.hash : '';
|
return window.location.hash != '#' ? window.location.hash : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Set the iframe document contents.
|
||||||
* @param {*} content
|
* @param content The contents.
|
||||||
*/
|
*/
|
||||||
function api_setDocument(content) {
|
function api_setDocument(content) {
|
||||||
let iframe = document.getElementById('document');
|
let iframe = document.getElementById('document');
|
||||||
@@ -1138,8 +1172,8 @@ function api_setDocument(content) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Send a message to the sandboxed iframe.
|
||||||
* @param {*} message
|
* @param message The message.
|
||||||
*/
|
*/
|
||||||
function api_postMessage(message) {
|
function api_postMessage(message) {
|
||||||
let iframe = document.getElementById('document');
|
let iframe = document.getElementById('document');
|
||||||
@@ -1147,8 +1181,8 @@ function api_postMessage(message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Show an error.
|
||||||
* @param {*} error
|
* @param error The error.
|
||||||
*/
|
*/
|
||||||
function api_error(error) {
|
function api_error(error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -1162,28 +1196,28 @@ function api_error(error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
et a value in local storage.
|
||||||
* @param {*} key
|
* @param key The key.
|
||||||
* @param {*} value
|
* @param value The value.
|
||||||
*/
|
*/
|
||||||
function api_localStorageSet(key, value) {
|
function api_localStorageSet(key, value) {
|
||||||
window.localStorage.setItem('app:' + key, value);
|
window.localStorage.setItem('app:' + key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Get a value from local storage.
|
||||||
* @param {*} key
|
* @param key The key.
|
||||||
* @returns
|
* @return The value.
|
||||||
*/
|
*/
|
||||||
function api_localStorageGet(key) {
|
function api_localStorageGet(key) {
|
||||||
return window.localStorage.getItem('app:' + key);
|
return window.localStorage.getItem('app:' + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Request a permission
|
||||||
* @param {*} permission
|
* @param permission The permission to request.
|
||||||
* @param {*} id
|
* @param id The id requeesting the permission.
|
||||||
* @returns
|
* @return A promise fulfilled if the permission was granted.
|
||||||
*/
|
*/
|
||||||
function api_requestPermission(permission, id) {
|
function api_requestPermission(permission, id) {
|
||||||
let outer = document.createElement('div');
|
let outer = document.createElement('div');
|
||||||
@@ -1252,23 +1286,23 @@ function api_requestPermission(permission, id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Log from the app to the console.
|
||||||
*/
|
*/
|
||||||
function api_print() {
|
function api_print() {
|
||||||
console.log('app>', ...arguments);
|
console.log('app>', ...arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Set the window's location hash.
|
||||||
* @param {*} hash
|
* @param hash The new hash.
|
||||||
*/
|
*/
|
||||||
function api_setHash(hash) {
|
function api_setHash(hash) {
|
||||||
window.location.hash = hash;
|
window.location.hash = hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Process an incoming WebSocket message.
|
||||||
* @param {*} message
|
* @param message The message.
|
||||||
*/
|
*/
|
||||||
function _receive_websocket_message(message) {
|
function _receive_websocket_message(message) {
|
||||||
if (message && message.action == 'session') {
|
if (message && message.action == 'session') {
|
||||||
@@ -1364,9 +1398,9 @@ function _receive_websocket_message(message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Set the status message.
|
||||||
* @param {*} message
|
* @param message The message.
|
||||||
* @param {*} color
|
* @param color The message's color.
|
||||||
*/
|
*/
|
||||||
function setStatusMessage(message, color) {
|
function setStatusMessage(message, color) {
|
||||||
document.getElementsByTagName('tf-navigation')[0].status = {
|
document.getElementsByTagName('tf-navigation')[0].status = {
|
||||||
@@ -1377,8 +1411,8 @@ function setStatusMessage(message, color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Send a message to the app.
|
||||||
* @param {*} value
|
* @param value The message.
|
||||||
*/
|
*/
|
||||||
function send(value) {
|
function send(value) {
|
||||||
try {
|
try {
|
||||||
@@ -1391,57 +1425,14 @@ function send(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Notify the app of the window hash changing.
|
||||||
* @param {*} sourceData
|
|
||||||
* @param {*} maxWidth
|
|
||||||
* @param {*} maxHeight
|
|
||||||
* @param {*} callback
|
|
||||||
*/
|
|
||||||
function fixImage(sourceData, maxWidth, maxHeight, callback) {
|
|
||||||
let result = sourceData;
|
|
||||||
let image = new Image();
|
|
||||||
image.crossOrigin = 'anonymous';
|
|
||||||
image.referrerPolicy = 'no-referrer';
|
|
||||||
image.onload = function () {
|
|
||||||
if (image.width > maxWidth || image.height > maxHeight) {
|
|
||||||
let downScale = Math.min(
|
|
||||||
maxWidth / image.width,
|
|
||||||
maxHeight / image.height
|
|
||||||
);
|
|
||||||
let canvas = document.createElement('canvas');
|
|
||||||
canvas.width = image.width * downScale;
|
|
||||||
canvas.height = image.height * downScale;
|
|
||||||
let context = canvas.getContext('2d');
|
|
||||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
image.width = canvas.width;
|
|
||||||
image.height = canvas.height;
|
|
||||||
context.drawImage(image, 0, 0, image.width, image.height);
|
|
||||||
result = canvas.toDataURL();
|
|
||||||
}
|
|
||||||
callback(result);
|
|
||||||
};
|
|
||||||
image.src = sourceData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
* @param {*} image
|
|
||||||
*/
|
|
||||||
function sendImage(image) {
|
|
||||||
fixImage(image, 320, 240, function (result) {
|
|
||||||
send({image: result});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODOC
|
|
||||||
*/
|
*/
|
||||||
function hashChange() {
|
function hashChange() {
|
||||||
send({event: 'hashChange', hash: window.location.hash});
|
send({event: 'hashChange', hash: window.location.hash});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Make sure the app is connected on window focus, and notify the app.
|
||||||
*/
|
*/
|
||||||
function focus() {
|
function focus() {
|
||||||
if (gSocket && gSocket.readyState == gSocket.CLOSED) {
|
if (gSocket && gSocket.readyState == gSocket.CLOSED) {
|
||||||
@@ -1452,7 +1443,7 @@ function focus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Notify the app of lost focus.
|
||||||
*/
|
*/
|
||||||
function blur() {
|
function blur() {
|
||||||
if (gSocket && gSocket.readyState == gSocket.OPEN) {
|
if (gSocket && gSocket.readyState == gSocket.OPEN) {
|
||||||
@@ -1461,8 +1452,8 @@ function blur() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Handle a message.
|
||||||
* @param {*} event
|
* @param event The message.
|
||||||
*/
|
*/
|
||||||
function message(event) {
|
function message(event) {
|
||||||
if (
|
if (
|
||||||
@@ -1510,8 +1501,8 @@ function message(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Reconnect the WebSocket.
|
||||||
* @param {*} path
|
* @param path The path to which the WebSocket should be connected.
|
||||||
*/
|
*/
|
||||||
function reconnect(path) {
|
function reconnect(path) {
|
||||||
let oldSocket = gSocket;
|
let oldSocket = gSocket;
|
||||||
@@ -1526,8 +1517,8 @@ function reconnect(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Connect the WebSocket.
|
||||||
* @param {*} path
|
* @param path The path to which to connect.
|
||||||
*/
|
*/
|
||||||
function connectSocket(path) {
|
function connectSocket(path) {
|
||||||
if (!gSocket || gSocket.readyState != gSocket.OPEN) {
|
if (!gSocket || gSocket.readyState != gSocket.OPEN) {
|
||||||
@@ -1593,8 +1584,8 @@ function connectSocket(path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Open a file by name.
|
||||||
* @param {*} name
|
* @param name The file to open.
|
||||||
*/
|
*/
|
||||||
function openFile(name) {
|
function openFile(name) {
|
||||||
let newDoc =
|
let newDoc =
|
||||||
@@ -1619,7 +1610,7 @@ function openFile(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Refresh the files list.
|
||||||
*/
|
*/
|
||||||
function updateFiles() {
|
function updateFiles() {
|
||||||
let files = document.getElementsByTagName('tf-files-pane')[0];
|
let files = document.getElementsByTagName('tf-files-pane')[0];
|
||||||
@@ -1641,8 +1632,8 @@ function updateFiles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Create a new file with the given name.
|
||||||
* @param {*} name
|
* @param name The file's name.
|
||||||
*/
|
*/
|
||||||
function makeNewFile(name) {
|
function makeNewFile(name) {
|
||||||
gFiles[name] = {
|
gFiles[name] = {
|
||||||
@@ -1652,7 +1643,7 @@ function makeNewFile(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Prompt to create a new file.
|
||||||
*/
|
*/
|
||||||
function newFile() {
|
function newFile() {
|
||||||
let name = prompt('Name of new file:', 'file.js');
|
let name = prompt('Name of new file:', 'file.js');
|
||||||
@@ -1662,7 +1653,7 @@ function newFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Prompt to remove a file.
|
||||||
*/
|
*/
|
||||||
function removeFile() {
|
function removeFile() {
|
||||||
if (confirm('Remove ' + gCurrentFile + '?')) {
|
if (confirm('Remove ' + gCurrentFile + '?')) {
|
||||||
@@ -1672,7 +1663,7 @@ function removeFile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Export the app to a zip file, which is downloaded by the browser.
|
||||||
*/
|
*/
|
||||||
async function appExport() {
|
async function appExport() {
|
||||||
let JsZip = (await import('/static/jszip.min.js')).default;
|
let JsZip = (await import('/static/jszip.min.js')).default;
|
||||||
@@ -1703,10 +1694,10 @@ async function appExport() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Save a file.
|
||||||
* @param {*} name
|
* @param name The file to svae.
|
||||||
* @param {*} file
|
* @param file The file contents.
|
||||||
* @returns
|
* @return A promise resolved with the blob ID of the saved file.
|
||||||
*/
|
*/
|
||||||
async function save_file_to_blob_id(name, file) {
|
async function save_file_to_blob_id(name, file) {
|
||||||
console.log(`Saving ${name}.`);
|
console.log(`Saving ${name}.`);
|
||||||
@@ -1730,7 +1721,7 @@ async function save_file_to_blob_id(name, file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Prompt to import an app from a zip file.
|
||||||
*/
|
*/
|
||||||
async function appImport() {
|
async function appImport() {
|
||||||
let JsZip = (await import('/static/jszip.min.js')).default;
|
let JsZip = (await import('/static/jszip.min.js')).default;
|
||||||
@@ -1801,7 +1792,7 @@ async function appImport() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Prettify the current source file.
|
||||||
*/
|
*/
|
||||||
async function sourcePretty() {
|
async function sourcePretty() {
|
||||||
let prettier = (await import('/prettier/standalone.mjs')).default;
|
let prettier = (await import('/prettier/standalone.mjs')).default;
|
||||||
@@ -1829,6 +1820,9 @@ async function sourcePretty() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle visible whitespace.
|
||||||
|
*/
|
||||||
function toggleVisibleWhitespace() {
|
function toggleVisibleWhitespace() {
|
||||||
let editor_style = document.getElementById('editor_style');
|
let editor_style = document.getElementById('editor_style');
|
||||||
/*
|
/*
|
||||||
@@ -1854,7 +1848,9 @@ function toggleVisibleWhitespace() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODOC
|
/**
|
||||||
|
* Register event handlers and connect the WebSocket on load.
|
||||||
|
*/
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
window.addEventListener('hashchange', hashChange);
|
window.addEventListener('hashchange', hashChange);
|
||||||
window.addEventListener('focus', focus);
|
window.addEventListener('focus', focus);
|
||||||
@@ -1902,3 +1898,5 @@ window.addEventListener('load', function () {
|
|||||||
toggleVisibleWhitespace();
|
toggleVisibleWhitespace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
115
core/core.js
115
core/core.js
@@ -1,12 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfcore Tilde Friends Core JS
|
||||||
|
* Tilde Friends process management, in JavaScript.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
import * as app from './app.js';
|
import * as app from './app.js';
|
||||||
import * as http from './http.js';
|
import * as http from './http.js';
|
||||||
|
|
||||||
let gProcesses = {};
|
export {invoke, getProcessBlob};
|
||||||
let gStatsTimer = false;
|
/** \endcond */
|
||||||
let g_handler_index = 0;
|
|
||||||
|
|
||||||
|
/** All running processes. */
|
||||||
|
let gProcesses = {};
|
||||||
|
/** Whether stats are currently being sent. */
|
||||||
|
let gStatsTimer = false;
|
||||||
|
/** Effectively a process ID. */
|
||||||
|
let g_handler_index = 0;
|
||||||
|
/** Time between pings, in milliseconds. */
|
||||||
const k_ping_interval = 60 * 1000;
|
const k_ping_interval = 60 * 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an error.
|
||||||
|
* @param error The error.
|
||||||
|
*/
|
||||||
function printError(error) {
|
function printError(error) {
|
||||||
if (error.stackTrace) {
|
if (error.stackTrace) {
|
||||||
print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
print(error.fileName + ':' + error.lineNumber + ': ' + error.message);
|
||||||
@@ -19,6 +37,12 @@ function printError(error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke a handler.
|
||||||
|
* @param handlers The handlers on which to invoke the callback.
|
||||||
|
* @param argv Arguments to pass to the handlers.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function invoke(handlers, argv) {
|
function invoke(handlers, argv) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
@@ -39,6 +63,12 @@ function invoke(handlers, argv) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast a named event to all registered apps.
|
||||||
|
* @param eventName the name of the event.
|
||||||
|
* @param argv Arguments to pass to the handlers.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function broadcastEvent(eventName, argv) {
|
function broadcastEvent(eventName, argv) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
for (let process of Object.values(gProcesses)) {
|
for (let process of Object.values(gProcesses)) {
|
||||||
@@ -49,6 +79,11 @@ function broadcastEvent(eventName, argv) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to all other instances of the same app.
|
||||||
|
* @param message The message.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function broadcast(message) {
|
function broadcast(message) {
|
||||||
let sender = this;
|
let sender = this;
|
||||||
let promises = [];
|
let promises = [];
|
||||||
@@ -65,6 +100,15 @@ function broadcast(message) {
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to all instances of the same app running as the same user.
|
||||||
|
* @param user The user.
|
||||||
|
* @param packageOwner The owner of the app.
|
||||||
|
* @param packageName The name of the app.
|
||||||
|
* @param eventName The name of the event.
|
||||||
|
* @param argv The arguments to pass.
|
||||||
|
* @return A promise.
|
||||||
|
*/
|
||||||
function broadcastAppEventToUser(
|
function broadcastAppEventToUser(
|
||||||
user,
|
user,
|
||||||
packageOwner,
|
packageOwner,
|
||||||
@@ -87,6 +131,11 @@ function broadcastAppEventToUser(
|
|||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user context information for a call.
|
||||||
|
* @param caller The calling process.
|
||||||
|
* @param process The receiving process.
|
||||||
|
*/
|
||||||
function getUser(caller, process) {
|
function getUser(caller, process) {
|
||||||
return {
|
return {
|
||||||
key: process.key,
|
key: process.key,
|
||||||
@@ -97,38 +146,26 @@ function getUser(caller, process) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getApps(user, process) {
|
/**
|
||||||
if (
|
* Send a message.
|
||||||
process.credentials &&
|
* @param from The calling process.
|
||||||
process.credentials.session &&
|
* @param to The receiving process.
|
||||||
process.credentials.session.name
|
* @param message The message.
|
||||||
) {
|
* @return A promise.
|
||||||
if (user && user !== process.credentials.session.name && user !== 'core') {
|
*/
|
||||||
return {};
|
|
||||||
} else if (!user) {
|
|
||||||
user = process.credentials.session.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user) {
|
|
||||||
let db = new Database(user);
|
|
||||||
try {
|
|
||||||
let names = JSON.parse(await db.get('apps'));
|
|
||||||
let result = {};
|
|
||||||
for (let name of names) {
|
|
||||||
result[name] = await db.get('path:' + name);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function postMessageInternal(from, to, message) {
|
function postMessageInternal(from, to, message) {
|
||||||
if (to.eventHandlers['message']) {
|
if (to.eventHandlers['message']) {
|
||||||
return invoke(to.eventHandlers['message'], [getUser(from, from), message]);
|
return invoke(to.eventHandlers['message'], [getUser(from, from), message]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a process for an app blob.
|
||||||
|
* @param blobId The blob identifier.
|
||||||
|
* @param key A unique key for the invocation.
|
||||||
|
* @param options Other options.
|
||||||
|
* @return The process.
|
||||||
|
*/
|
||||||
async function getProcessBlob(blobId, key, options) {
|
async function getProcessBlob(blobId, key, options) {
|
||||||
let process = gProcesses[key];
|
let process = gProcesses[key];
|
||||||
if (!process && !(options && 'create' in options && !options.create)) {
|
if (!process && !(options && 'create' in options && !options.create)) {
|
||||||
@@ -220,7 +257,6 @@ async function getProcessBlob(blobId, key, options) {
|
|||||||
let settings = await loadSettings();
|
let settings = await loadSettings();
|
||||||
return settings?.permissions?.[user] ?? [];
|
return settings?.permissions?.[user] ?? [];
|
||||||
},
|
},
|
||||||
apps: (user) => getApps(user, process),
|
|
||||||
getSockets: getSockets,
|
getSockets: getSockets,
|
||||||
permissionTest: async function (permission) {
|
permissionTest: async function (permission) {
|
||||||
let user = process?.credentials?.session?.name;
|
let user = process?.credentials?.session?.name;
|
||||||
@@ -679,6 +715,10 @@ ssb.addEventListener('connections', function () {
|
|||||||
broadcastEvent('onConnectionsChanged', []);
|
broadcastEvent('onConnectionsChanged', []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load settings from the database.
|
||||||
|
* @return The settings as a key value pairs object.
|
||||||
|
*/
|
||||||
async function loadSettings() {
|
async function loadSettings() {
|
||||||
let data = {};
|
let data = {};
|
||||||
try {
|
try {
|
||||||
@@ -697,6 +737,9 @@ async function loadSettings() {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send periodic stats to all clients.
|
||||||
|
*/
|
||||||
function sendStats() {
|
function sendStats() {
|
||||||
let apps = Object.values(gProcesses)
|
let apps = Object.values(gProcesses)
|
||||||
.filter((process) => process.app)
|
.filter((process) => process.app)
|
||||||
@@ -712,6 +755,16 @@ function sendStats() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke an app's handler.js.
|
||||||
|
* @param response The response object.
|
||||||
|
* @param app_blob_id The app's blob identifier.
|
||||||
|
* @param path The request path.
|
||||||
|
* @param query The request query string.
|
||||||
|
* @param headers The request headers.
|
||||||
|
* @param package_owner The app's owner.
|
||||||
|
* @param package_name The app's name.
|
||||||
|
*/
|
||||||
exports.callAppHandler = async function callAppHandler(
|
exports.callAppHandler = async function callAppHandler(
|
||||||
response,
|
response,
|
||||||
app_blob_id,
|
app_blob_id,
|
||||||
@@ -777,4 +830,4 @@ exports.callAppHandler = async function callAppHandler(
|
|||||||
response.end(answer?.data);
|
response.end(answer?.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
export {invoke, getProcessBlob};
|
/** @} */
|
||||||
|
34
core/http.js
34
core/http.js
@@ -1,8 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* TODOC
|
* \file
|
||||||
* TODO: document so we can improve this
|
* \defgroup tfhttp Tilde Friends HTTP Client JS
|
||||||
* @param {*} url
|
* Tilde Friends server-side HTTP client.
|
||||||
* @returns
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a URL into protocol, host, path, and port parts.
|
||||||
|
* @param url
|
||||||
|
* @return An object of the URL parts.
|
||||||
*/
|
*/
|
||||||
function parseUrl(url) {
|
function parseUrl(url) {
|
||||||
// XXX: Hack.
|
// XXX: Hack.
|
||||||
@@ -16,9 +22,9 @@ function parseUrl(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Parse an HTTP response into headers and body content.
|
||||||
* @param {*} data
|
* @param data The response data, headers and body included.
|
||||||
* @returns
|
* @return headers and body data.
|
||||||
*/
|
*/
|
||||||
function parseResponse(data) {
|
function parseResponse(data) {
|
||||||
let firstLine;
|
let firstLine;
|
||||||
@@ -36,15 +42,15 @@ function parseResponse(data) {
|
|||||||
headers[line.substring(colon)] = line.substring(colon + 1);
|
headers[line.substring(colon)] = line.substring(colon + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {body: data};
|
return {headers: headers, body: data};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Make an HTTP request.
|
||||||
* @param {*} url
|
* @param url The URL.
|
||||||
* @param {*} options
|
* @param options Request options.
|
||||||
* @param {*} allowed_hosts
|
* @param allowed_hosts List of allowed hosts.
|
||||||
* @returns
|
* @return A promise resolved with the response headers and body.
|
||||||
*/
|
*/
|
||||||
export function fetch(url, options, allowed_hosts) {
|
export function fetch(url, options, allowed_hosts) {
|
||||||
let parsed = parseUrl(url);
|
let parsed = parseUrl(url);
|
||||||
@@ -111,3 +117,5 @@ export function fetch(url, options, allowed_hosts) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
@@ -1,11 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* \defgroup tfrpc Tilde Friends RPC.
|
||||||
|
* Tilde Friends RPC.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Whether this module is being run in a web browser. */
|
||||||
const k_is_browser = get_is_browser();
|
const k_is_browser = get_is_browser();
|
||||||
|
/** Registered methods. */
|
||||||
let g_api = {};
|
let g_api = {};
|
||||||
|
/** The next method identifier. */
|
||||||
let g_next_id = 1;
|
let g_next_id = 1;
|
||||||
|
/** Identifiers of pending calls. */
|
||||||
let g_calls = {};
|
let g_calls = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Check if being called from a browser vs. server-side.
|
||||||
* @returns
|
* @return true if called from a browser.
|
||||||
*/
|
*/
|
||||||
function get_is_browser() {
|
function get_is_browser() {
|
||||||
try {
|
try {
|
||||||
@@ -15,16 +26,30 @@ function get_is_browser() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \cond */
|
||||||
if (k_is_browser) {
|
if (k_is_browser) {
|
||||||
print = console.log;
|
print = console.log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (k_is_browser) {
|
||||||
|
window.addEventListener('message', function (event) {
|
||||||
|
call_rpc(event.data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.register('message', function (message) {
|
||||||
|
call_rpc(message?.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export let rpc = new Proxy({}, {get: make_rpc});
|
||||||
|
/** \endcond */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Make a function to invoke a remote procedure.
|
||||||
* @param {*} target
|
* @param target The target.
|
||||||
* @param {*} prop
|
* @param prop The name of the function.
|
||||||
* @param {*} receiver
|
* @param receiver The receiver.
|
||||||
* @returns
|
* @return A function.
|
||||||
*/
|
*/
|
||||||
function make_rpc(target, prop, receiver) {
|
function make_rpc(target, prop, receiver) {
|
||||||
return function () {
|
return function () {
|
||||||
@@ -55,8 +80,8 @@ function make_rpc(target, prop, receiver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Send a response.
|
||||||
* @param {*} response
|
* @param response The response.
|
||||||
*/
|
*/
|
||||||
function send(response) {
|
function send(response) {
|
||||||
if (k_is_browser) {
|
if (k_is_browser) {
|
||||||
@@ -67,8 +92,8 @@ function send(response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Invoke a remote procedure.
|
||||||
* @param {*} message
|
* @param message An object describing the call.
|
||||||
*/
|
*/
|
||||||
function call_rpc(message) {
|
function call_rpc(message) {
|
||||||
if (message && message.message === 'tfrpc') {
|
if (message && message.message === 'tfrpc') {
|
||||||
@@ -112,22 +137,12 @@ function call_rpc(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k_is_browser) {
|
|
||||||
window.addEventListener('message', function (event) {
|
|
||||||
call_rpc(event.data);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
core.register('message', function (message) {
|
|
||||||
call_rpc(message?.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export let rpc = new Proxy({}, {get: make_rpc});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODOC
|
* Register a function that to be called remotely.
|
||||||
* @param {*} method
|
* @param method The method.
|
||||||
*/
|
*/
|
||||||
export function register(method) {
|
export function register(method) {
|
||||||
g_api[method.name] = method;
|
g_api[method.name] = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
@@ -25,14 +25,14 @@
|
|||||||
}:
|
}:
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "tildefriends";
|
pname = "tildefriends";
|
||||||
version = "0.0.32";
|
version = "0.0.33";
|
||||||
|
|
||||||
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-Dk0NOEQIg2LeENySK0+MgpZEtfsClGq6dZL+eOOpE0U=";
|
hash = "sha256-9D28gmaBTRVyXhY3zZd/W9PsXA1YZt/K69hz41aVP04=";
|
||||||
fetchSubmodules = true;
|
fetchSubmodules = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
304
deps/codemirror_src/package-lock.json
generated
vendored
304
deps/codemirror_src/package-lock.json
generated
vendored
@@ -22,6 +22,7 @@
|
|||||||
"version": "6.18.6",
|
"version": "6.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
||||||
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
"version": "6.8.1",
|
"version": "6.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
|
||||||
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
|
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
|
||||||
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
@@ -56,6 +59,7 @@
|
|||||||
"version": "6.4.9",
|
"version": "6.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
|
||||||
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/lang-css": "^6.0.0",
|
"@codemirror/lang-css": "^6.0.0",
|
||||||
@@ -72,6 +76,7 @@
|
|||||||
"version": "6.2.4",
|
"version": "6.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
|
||||||
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
|
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/language": "^6.6.0",
|
"@codemirror/language": "^6.6.0",
|
||||||
@@ -86,15 +91,17 @@
|
|||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.2.tgz",
|
||||||
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
"integrity": "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@lezer/json": "^1.0.0"
|
"@lezer/json": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.11.2",
|
"version": "6.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz",
|
||||||
"integrity": "sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==",
|
"integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.23.0",
|
"@codemirror/view": "^6.23.0",
|
||||||
@@ -108,6 +115,7 @@
|
|||||||
"version": "6.8.5",
|
"version": "6.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
|
||||||
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
|
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.35.0",
|
"@codemirror/view": "^6.35.0",
|
||||||
@@ -118,6 +126,7 @@
|
|||||||
"version": "6.5.11",
|
"version": "6.5.11",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
||||||
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.0.0",
|
||||||
@@ -128,6 +137,7 @@
|
|||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||||
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@marijn/find-cluster-break": "^1.0.0"
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -136,6 +146,7 @@
|
|||||||
"version": "6.1.3",
|
"version": "6.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
|
||||||
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
@@ -147,6 +158,7 @@
|
|||||||
"version": "6.38.1",
|
"version": "6.38.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.1.tgz",
|
||||||
"integrity": "sha512-RmTOkE7hRU3OVREqFVITWHz6ocgBjv08GoePscAakgVQfciA3SGCEk7mb9IzwW61cKKmlTpHXG6DUE5Ubx+MGQ==",
|
"integrity": "sha512-RmTOkE7hRU3OVREqFVITWHz6ocgBjv08GoePscAakgVQfciA3SGCEk7mb9IzwW61cKKmlTpHXG6DUE5Ubx+MGQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
"crelt": "^1.0.6",
|
"crelt": "^1.0.6",
|
||||||
@@ -155,10 +167,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.12",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
"integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
|
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||||
"@jridgewell/trace-mapping": "^0.3.24"
|
"@jridgewell/trace-mapping": "^0.3.24"
|
||||||
@@ -169,31 +182,35 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/source-map": {
|
"node_modules/@jridgewell/source-map": {
|
||||||
"version": "0.3.10",
|
"version": "0.3.11",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
|
||||||
"integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==",
|
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
"@jridgewell/trace-mapping": "^0.3.25"
|
"@jridgewell/trace-mapping": "^0.3.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.5.4",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
"integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@jridgewell/trace-mapping": {
|
"node_modules/@jridgewell/trace-mapping": {
|
||||||
"version": "0.3.29",
|
"version": "0.3.30",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
|
||||||
"integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
|
"integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/resolve-uri": "^3.1.0",
|
"@jridgewell/resolve-uri": "^3.1.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
@@ -202,12 +219,14 @@
|
|||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
||||||
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
|
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/css": {
|
"node_modules/@lezer/css": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz",
|
||||||
"integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==",
|
"integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -218,6 +237,7 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
||||||
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -226,6 +246,7 @@
|
|||||||
"version": "1.3.10",
|
"version": "1.3.10",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
|
||||||
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
|
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -236,6 +257,7 @@
|
|||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
|
||||||
"integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
|
"integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.1.3",
|
"@lezer/highlight": "^1.1.3",
|
||||||
@@ -246,6 +268,7 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||||
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.2.0",
|
"@lezer/common": "^1.2.0",
|
||||||
"@lezer/highlight": "^1.0.0",
|
"@lezer/highlight": "^1.0.0",
|
||||||
@@ -256,6 +279,7 @@
|
|||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||||
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -263,12 +287,14 @@
|
|||||||
"node_modules/@marijn/find-cluster-break": {
|
"node_modules/@marijn/find-cluster-break": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||||
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="
|
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/plugin-node-resolve": {
|
"node_modules/@rollup/plugin-node-resolve": {
|
||||||
"version": "15.3.1",
|
"version": "15.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz",
|
||||||
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
|
"integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^5.0.1",
|
"@rollup/pluginutils": "^5.0.1",
|
||||||
"@types/resolve": "1.20.2",
|
"@types/resolve": "1.20.2",
|
||||||
@@ -293,6 +319,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
|
||||||
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
"integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialize-javascript": "^6.0.1",
|
"serialize-javascript": "^6.0.1",
|
||||||
"smob": "^1.0.0",
|
"smob": "^1.0.0",
|
||||||
@@ -314,6 +341,7 @@
|
|||||||
"version": "5.2.0",
|
"version": "5.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz",
|
||||||
"integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==",
|
"integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
@@ -332,240 +360,260 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.4.tgz",
|
||||||
"integrity": "sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==",
|
"integrity": "sha512-B2wfzCJ+ps/OBzRjeds7DlJumCU3rXMxJJS1vzURyj7+KBHGONm7c9q1TfdBl4vCuNMkDvARn3PBl2wZzuR5mw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.4.tgz",
|
||||||
"integrity": "sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==",
|
"integrity": "sha512-FGJYXvYdn8Bs6lAlBZYT5n+4x0ciEp4cmttsvKAZc/c8/JiPaQK8u0c/86vKX8lA7OY/+37lIQSe0YoAImvBAA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"android"
|
"android"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.4.tgz",
|
||||||
"integrity": "sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==",
|
"integrity": "sha512-/9qwE/BM7ATw/W/OFEMTm3dmywbJyLQb4f4v5nmOjgYxPIGpw7HaxRi6LnD4Pjn/q7k55FGeHe1/OD02w63apA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.4.tgz",
|
||||||
"integrity": "sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==",
|
"integrity": "sha512-QkWfNbeRuzFnv2d0aPlrzcA3Ebq2mE8kX/5Pl7VdRShbPBjSnom7dbT8E3Jmhxo2RL784hyqGvR5KHavCJQciw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.4.tgz",
|
||||||
"integrity": "sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==",
|
"integrity": "sha512-+ToyOMYnSfV8D+ckxO6NthPln/PDNp1P6INcNypfZ7muLmEvPKXqduUiD8DlJpMMT8LxHcE5W0dK9kXfJke9Zw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.4.tgz",
|
||||||
"integrity": "sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==",
|
"integrity": "sha512-cGT6ey/W+sje6zywbLiqmkfkO210FgRz7tepWAzzEVgQU8Hn91JJmQWNqs55IuglG8sJdzk7XfNgmGRtcYlo1w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"freebsd"
|
"freebsd"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.4.tgz",
|
||||||
"integrity": "sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==",
|
"integrity": "sha512-9fhTJyOb275w5RofPSl8lpr4jFowd+H4oQKJ9XTYzD1JWgxdZKE8bA6d4npuiMemkecQOcigX01FNZNCYnQBdA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.4.tgz",
|
||||||
"integrity": "sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==",
|
"integrity": "sha512-+6kCIM5Zjvz2HwPl/udgVs07tPMIp1VU2Y0c72ezjOvSvEfAIWsUgpcSDvnC7g9NrjYR6X9bZT92mZZ90TfvXw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.4.tgz",
|
||||||
"integrity": "sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==",
|
"integrity": "sha512-SWuXdnsayCZL4lXoo6jn0yyAj7TTjWE4NwDVt9s7cmu6poMhtiras5c8h6Ih6Y0Zk6Z+8t/mLumvpdSPTWub2Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.4.tgz",
|
||||||
"integrity": "sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==",
|
"integrity": "sha512-vDknMDqtMhrrroa5kyX6tuC0aRZZlQ+ipDfbXd2YGz5HeV2t8HOl/FDAd2ynhs7Ki5VooWiiZcCtxiZ4IjqZwQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.4.tgz",
|
||||||
"integrity": "sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==",
|
"integrity": "sha512-mCBkjRZWhvjtl/x+Bd4fQkWZT8canStKDxGrHlBiTnZmJnWygGcvBylzLVCZXka4dco5ymkWhZlLwKCGFF4ivw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.4.tgz",
|
||||||
"integrity": "sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==",
|
"integrity": "sha512-YMdz2phOTFF+Z66dQfGf0gmeDSi5DJzY5bpZyeg9CPBkV9QDzJ1yFRlmi/j7WWRf3hYIWrOaJj5jsfwgc8GTHQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.4.tgz",
|
||||||
"integrity": "sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==",
|
"integrity": "sha512-r0WKLSfFAK8ucG024v2yiLSJMedoWvk8yWqfNICX28NHDGeu3F/wBf8KG6mclghx4FsLePxJr/9N8rIj1PtCnw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.4.tgz",
|
||||||
"integrity": "sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==",
|
"integrity": "sha512-IaizpPP2UQU3MNyPH1u0Xxbm73D+4OupL0bjo4Hm0496e2wg3zuvoAIhubkD1NGy9fXILEExPQy87mweujEatA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.4.tgz",
|
||||||
"integrity": "sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==",
|
"integrity": "sha512-aCM29orANR0a8wk896p6UEgIfupReupnmISz6SUwMIwTGaTI8MuKdE0OD2LvEg8ondDyZdMvnaN3bW4nFbATPA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.4.tgz",
|
||||||
"integrity": "sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==",
|
"integrity": "sha512-0Xj1vZE3cbr/wda8d/m+UeuSL+TDpuozzdD4QaSzu/xSOMK0Su5RhIkF7KVHFQsobemUNHPLEcYllL7ZTCP/Cg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.4.tgz",
|
||||||
"integrity": "sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==",
|
"integrity": "sha512-kM/orjpolfA5yxsx84kI6bnK47AAZuWxglGKcNmokw2yy9i5eHY5UAjcX45jemTJnfHAWo3/hOoRqEeeTdL5hw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.4.tgz",
|
||||||
"integrity": "sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==",
|
"integrity": "sha512-cNLH4psMEsWKILW0isbpQA2OvjXLbKvnkcJFmqAptPQbtLrobiapBJVj6RoIvg6UXVp5w0wnIfd/Q56cNpF+Ew==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.4.tgz",
|
||||||
"integrity": "sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==",
|
"integrity": "sha512-OiEa5lRhiANpv4SfwYVgQ3opYWi/QmPDC5ve21m8G9pf6ZO+aX1g2EEF1/IFaM1xPSP7mK0msTRXlPs6mIagkg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.4.tgz",
|
||||||
"integrity": "sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==",
|
"integrity": "sha512-IKL9mewGZ5UuuX4NQlwOmxPyqielvkAPUS2s1cl6yWjjQvyN3h5JTdVFGD5Jr5xMjRC8setOfGQDVgX8V+dkjg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
@@ -574,18 +622,21 @@
|
|||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="
|
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/resolve": {
|
"node_modules/@types/resolve": {
|
||||||
"version": "1.20.2",
|
"version": "1.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
|
||||||
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="
|
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.15.0",
|
"version": "8.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -597,12 +648,14 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/codemirror": {
|
"node_modules/codemirror": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
|
||||||
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
"@codemirror/commands": "^6.0.0",
|
"@codemirror/commands": "^6.0.0",
|
||||||
@@ -617,17 +670,20 @@
|
|||||||
"version": "2.20.3",
|
"version": "2.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/crelt": {
|
"node_modules/crelt": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
"version": "4.3.1",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -635,13 +691,15 @@
|
|||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
@@ -654,6 +712,7 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
@@ -662,6 +721,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
},
|
},
|
||||||
@@ -673,6 +733,7 @@
|
|||||||
"version": "2.16.1",
|
"version": "2.16.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hasown": "^2.0.2"
|
"hasown": "^2.0.2"
|
||||||
},
|
},
|
||||||
@@ -686,17 +747,20 @@
|
|||||||
"node_modules/is-module": {
|
"node_modules/is-module": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
|
||||||
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g=="
|
"integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/path-parse": {
|
"node_modules/path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -709,6 +773,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
@@ -717,6 +782,7 @@
|
|||||||
"version": "1.22.10",
|
"version": "1.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||||
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-core-module": "^2.16.0",
|
"is-core-module": "^2.16.0",
|
||||||
"path-parse": "^1.0.7",
|
"path-parse": "^1.0.7",
|
||||||
@@ -733,9 +799,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.45.1",
|
"version": "4.46.4",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.45.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.4.tgz",
|
||||||
"integrity": "sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==",
|
"integrity": "sha512-YbxoxvoqNg9zAmw4+vzh1FkGAiZRK+LhnSrbSrSXMdZYsRPDWoshcSd/pldKRO6lWzv/e9TiJAVQyirYIeSIPQ==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.8"
|
"@types/estree": "1.0.8"
|
||||||
},
|
},
|
||||||
@@ -747,26 +814,26 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.45.1",
|
"@rollup/rollup-android-arm-eabi": "4.46.4",
|
||||||
"@rollup/rollup-android-arm64": "4.45.1",
|
"@rollup/rollup-android-arm64": "4.46.4",
|
||||||
"@rollup/rollup-darwin-arm64": "4.45.1",
|
"@rollup/rollup-darwin-arm64": "4.46.4",
|
||||||
"@rollup/rollup-darwin-x64": "4.45.1",
|
"@rollup/rollup-darwin-x64": "4.46.4",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.45.1",
|
"@rollup/rollup-freebsd-arm64": "4.46.4",
|
||||||
"@rollup/rollup-freebsd-x64": "4.45.1",
|
"@rollup/rollup-freebsd-x64": "4.46.4",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.45.1",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.46.4",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.45.1",
|
"@rollup/rollup-linux-arm-musleabihf": "4.46.4",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.45.1",
|
"@rollup/rollup-linux-arm64-gnu": "4.46.4",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.45.1",
|
"@rollup/rollup-linux-arm64-musl": "4.46.4",
|
||||||
"@rollup/rollup-linux-loongarch64-gnu": "4.45.1",
|
"@rollup/rollup-linux-loongarch64-gnu": "4.46.4",
|
||||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.45.1",
|
"@rollup/rollup-linux-ppc64-gnu": "4.46.4",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.45.1",
|
"@rollup/rollup-linux-riscv64-gnu": "4.46.4",
|
||||||
"@rollup/rollup-linux-riscv64-musl": "4.45.1",
|
"@rollup/rollup-linux-riscv64-musl": "4.46.4",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.45.1",
|
"@rollup/rollup-linux-s390x-gnu": "4.46.4",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.45.1",
|
"@rollup/rollup-linux-x64-gnu": "4.46.4",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.45.1",
|
"@rollup/rollup-linux-x64-musl": "4.46.4",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.45.1",
|
"@rollup/rollup-win32-arm64-msvc": "4.46.4",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.45.1",
|
"@rollup/rollup-win32-ia32-msvc": "4.46.4",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.45.1",
|
"@rollup/rollup-win32-x64-msvc": "4.46.4",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -788,13 +855,15 @@
|
|||||||
"type": "consulting",
|
"type": "consulting",
|
||||||
"url": "https://feross.org/support"
|
"url": "https://feross.org/support"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/serialize-javascript": {
|
"node_modules/serialize-javascript": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||||
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"randombytes": "^2.1.0"
|
"randombytes": "^2.1.0"
|
||||||
}
|
}
|
||||||
@@ -803,13 +872,15 @@
|
|||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
|
||||||
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -819,6 +890,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-from": "^1.0.0",
|
"buffer-from": "^1.0.0",
|
||||||
"source-map": "^0.6.0"
|
"source-map": "^0.6.0"
|
||||||
@@ -827,12 +899,14 @@
|
|||||||
"node_modules/style-mod": {
|
"node_modules/style-mod": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
|
||||||
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/supports-preserve-symlinks-flag": {
|
"node_modules/supports-preserve-symlinks-flag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
},
|
},
|
||||||
@@ -845,6 +919,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
|
||||||
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
|
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/source-map": "^0.3.3",
|
"@jridgewell/source-map": "^0.3.3",
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.14.0",
|
||||||
@@ -861,7 +936,8 @@
|
|||||||
"node_modules/w3c-keyname": {
|
"node_modules/w3c-keyname": {
|
||||||
"version": "2.2.8",
|
"version": "2.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||||
|
"license": "MIT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
deps/openssl_src
vendored
2
deps/openssl_src
vendored
Submodule deps/openssl_src updated: aea7aaf2ab...0893a62353
2
deps/speedscope/index.html
vendored
2
deps/speedscope/index.html
vendored
@@ -11,7 +11,7 @@
|
|||||||
<link rel="icon" type="image/x-icon" href="favicon-FOKUP5Y5.ico">
|
<link rel="icon" type="image/x-icon" href="favicon-FOKUP5Y5.ico">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="speedscope-7YPLLUY2.js"></script>
|
<script src="speedscope-HCR63FMT.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
6
deps/speedscope/release.txt
vendored
6
deps/speedscope/release.txt
vendored
@@ -1,3 +1,3 @@
|
|||||||
speedscope@1.23.0
|
speedscope@1.23.1
|
||||||
Sun Jul 6 20:04:28 PDT 2025
|
Mon Aug 11 11:43:09 PDT 2025
|
||||||
aa9bef50789a2989746b576fff182b6f01dfce6a
|
0cec0f82c334aed6cf19d43cabeadcda0d95e0fc
|
||||||
|
File diff suppressed because one or more lines are too long
43
deps/sqlite/sqlite3.c
vendored
43
deps/sqlite/sqlite3.c
vendored
@@ -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.50.3. By combining all the individual C code files into this
|
** version 3.50.4. 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
|
||||||
** 3ce993b8657d6d9deda380a93cdd6404a8c8 with changes in files:
|
** 4d8adfb30e03f9cf27f800a2c1ba3c48fb4c 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.50.3"
|
#define SQLITE_VERSION "3.50.4"
|
||||||
#define SQLITE_VERSION_NUMBER 3050003
|
#define SQLITE_VERSION_NUMBER 3050004
|
||||||
#define SQLITE_SOURCE_ID "2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543"
|
#define SQLITE_SOURCE_ID "2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@@ -19440,6 +19440,7 @@ struct Expr {
|
|||||||
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
||||||
** for a column of an index on an expression */
|
** for a column of an index on an expression */
|
||||||
Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
|
Window *pWin; /* EP_WinFunc: Window/Filter defn for a function */
|
||||||
|
int nReg; /* TK_NULLS: Number of registers to NULL out */
|
||||||
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
|
struct { /* TK_IN, TK_SELECT, and TK_EXISTS */
|
||||||
int iAddr; /* Subroutine entry address */
|
int iAddr; /* Subroutine entry address */
|
||||||
int regReturn; /* Register used to hold return address */
|
int regReturn; /* Register used to hold return address */
|
||||||
@@ -21474,6 +21475,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int)
|
|||||||
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
|
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
|
||||||
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
|
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
|
||||||
SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int);
|
SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int);
|
||||||
|
SQLITE_PRIVATE void sqlite3ExprNullRegisterRange(Parse*, int, int);
|
||||||
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||||
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
||||||
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
|
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
|
||||||
@@ -115241,6 +115243,12 @@ expr_code_doover:
|
|||||||
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
|
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
case TK_NULLS: {
|
||||||
|
/* Set a range of registers to NULL. pExpr->y.nReg registers starting
|
||||||
|
** with target */
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Null, 0, target, target + pExpr->y.nReg - 1);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
/* Make NULL the default case so that if a bug causes an illegal
|
/* Make NULL the default case so that if a bug causes an illegal
|
||||||
** Expr node to be passed into this function, it will be handled
|
** Expr node to be passed into this function, it will be handled
|
||||||
@@ -115925,6 +115933,25 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
|
|||||||
return regDest;
|
return regDest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Make arrangements to invoke OP_Null on a range of registers
|
||||||
|
** during initialization.
|
||||||
|
*/
|
||||||
|
SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3ExprNullRegisterRange(
|
||||||
|
Parse *pParse, /* Parsing context */
|
||||||
|
int iReg, /* First register to set to NULL */
|
||||||
|
int nReg /* Number of sequential registers to NULL out */
|
||||||
|
){
|
||||||
|
u8 okConstFactor = pParse->okConstFactor;
|
||||||
|
Expr t;
|
||||||
|
memset(&t, 0, sizeof(t));
|
||||||
|
t.op = TK_NULLS;
|
||||||
|
t.y.nReg = nReg;
|
||||||
|
pParse->okConstFactor = 1;
|
||||||
|
sqlite3ExprCodeRunJustOnce(pParse, &t, iReg);
|
||||||
|
pParse->okConstFactor = okConstFactor;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate code to evaluate an expression and store the results
|
** Generate code to evaluate an expression and store the results
|
||||||
** into a register. Return the register number where the results
|
** into a register. Return the register number where the results
|
||||||
@@ -153175,6 +153202,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
|
||||||
VdbeComment((v, "clear abort flag"));
|
VdbeComment((v, "clear abort flag"));
|
||||||
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
||||||
|
sqlite3ExprNullRegisterRange(pParse, iAMem, pGroupBy->nExpr);
|
||||||
|
|
||||||
/* Begin a loop that will extract all source rows in GROUP BY order.
|
/* Begin a loop that will extract all source rows in GROUP BY order.
|
||||||
** This might involve two separate loops with an OP_Sort in between, or
|
** This might involve two separate loops with an OP_Sort in between, or
|
||||||
@@ -168470,6 +168498,7 @@ static int whereLoopAddBtree(
|
|||||||
pNew->u.btree.nEq = 0;
|
pNew->u.btree.nEq = 0;
|
||||||
pNew->u.btree.nBtm = 0;
|
pNew->u.btree.nBtm = 0;
|
||||||
pNew->u.btree.nTop = 0;
|
pNew->u.btree.nTop = 0;
|
||||||
|
pNew->u.btree.nDistinctCol = 0;
|
||||||
pNew->nSkip = 0;
|
pNew->nSkip = 0;
|
||||||
pNew->nLTerm = 0;
|
pNew->nLTerm = 0;
|
||||||
pNew->iSortIdx = 0;
|
pNew->iSortIdx = 0;
|
||||||
@@ -169538,8 +169567,6 @@ static i8 wherePathSatisfiesOrderBy(
|
|||||||
obSat = obDone;
|
obSat = obDone;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}else if( wctrlFlags & WHERE_DISTINCTBY ){
|
|
||||||
pLoop->u.btree.nDistinctCol = 0;
|
|
||||||
}
|
}
|
||||||
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
|
||||||
|
|
||||||
@@ -257280,7 +257307,7 @@ static void fts5SourceIdFunc(
|
|||||||
){
|
){
|
||||||
assert( nArg==0 );
|
assert( nArg==0 );
|
||||||
UNUSED_PARAM2(nArg, apUnused);
|
UNUSED_PARAM2(nArg, apUnused);
|
||||||
sqlite3_result_text(pCtx, "fts5: 2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543", -1, SQLITE_TRANSIENT);
|
sqlite3_result_text(pCtx, "fts5: 2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3", -1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
6
deps/sqlite/sqlite3.h
vendored
6
deps/sqlite/sqlite3.h
vendored
@@ -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.50.3"
|
#define SQLITE_VERSION "3.50.4"
|
||||||
#define SQLITE_VERSION_NUMBER 3050003
|
#define SQLITE_VERSION_NUMBER 3050004
|
||||||
#define SQLITE_SOURCE_ID "2025-07-17 13:25:10 3ce993b8657d6d9deda380a93cdd6404a8c8ba1b185b2bc423703e41ae5f2543"
|
#define SQLITE_SOURCE_ID "2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
|
6
flake.lock
generated
6
flake.lock
generated
@@ -20,11 +20,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1750622754,
|
"lastModified": 1753749649,
|
||||||
"narHash": "sha256-kMhs+YzV4vPGfuTpD3mwzibWUE6jotw5Al2wczI0Pv8=",
|
"narHash": "sha256-+jkEZxs7bfOKfBIk430K+tK9IvXlwzqQQnppC2ZKFj4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c7ab75210cb8cb16ddd8f290755d9558edde7ee1",
|
"rev": "1f08a4df998e21f4e8be8fb6fbf61d11a1a5076a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
14
metadata/en-US/changelogs/40.txt
Normal file
14
metadata/en-US/changelogs/40.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
* Added an option to stay connected to a handful of peers.
|
||||||
|
* Load more messages at a time.
|
||||||
|
* Fix a set of Android not responding errors.
|
||||||
|
* Target Android 15 (API level 35) to meet new requirements.
|
||||||
|
* Support JS-less webapps.
|
||||||
|
* Fix unnecessary tunnel disconnects.
|
||||||
|
* Many small user interface tweaks.
|
||||||
|
* Update:
|
||||||
|
* CodeMirror
|
||||||
|
* OpenSSL 3.5.1
|
||||||
|
* lit 3.3.1
|
||||||
|
* picohttpparser
|
||||||
|
* speedscope 1.23.0
|
||||||
|
* sqlite 3.50.4
|
9
metadata/en-US/changelogs/42.txt
Normal file
9
metadata/en-US/changelogs/42.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
* Private messages interface overhaul in progress.
|
||||||
|
* Added a loading indicator.
|
||||||
|
* Documented the core JavaScript.
|
||||||
|
* Fixed @-completion.
|
||||||
|
* Covered up launch on Android with the splash screen.
|
||||||
|
* Update:
|
||||||
|
* CodeMirror
|
||||||
|
* OpenSSL 3.5.2
|
||||||
|
* speedscope 1.23.1
|
1
package-lock.json
generated
1
package-lock.json
generated
@@ -14,6 +14,7 @@
|
|||||||
"version": "3.6.2",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
|
||||||
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
},
|
},
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.unprompted.tildefriends"
|
package="com.unprompted.tildefriends"
|
||||||
android:versionCode="40"
|
android:versionCode="42"
|
||||||
android:versionName="0.0.33-wip">
|
android:versionName="0.2025.8">
|
||||||
<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
|
||||||
|
@@ -25,6 +25,7 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
import android.webkit.CookieManager;
|
import android.webkit.CookieManager;
|
||||||
import android.webkit.DownloadListener;
|
import android.webkit.DownloadListener;
|
||||||
import android.webkit.JsPromptResult;
|
import android.webkit.JsPromptResult;
|
||||||
@@ -50,6 +51,7 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
TildeFriendsWebView web_view;
|
TildeFriendsWebView web_view;
|
||||||
String base_url;
|
String base_url;
|
||||||
String port_file_path;
|
String port_file_path;
|
||||||
|
Thread create_thread;
|
||||||
Thread server_thread;
|
Thread server_thread;
|
||||||
ServiceConnection service_connection;
|
ServiceConnection service_connection;
|
||||||
FileObserver observer;
|
FileObserver observer;
|
||||||
@@ -57,6 +59,8 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
private ValueCallback<Uri[]> upload_message;
|
private ValueCallback<Uri[]> upload_message;
|
||||||
private final static int FILECHOOSER_RESULT = 1;
|
private final static int FILECHOOSER_RESULT = 1;
|
||||||
private float touch_down_y;
|
private float touch_down_y;
|
||||||
|
private boolean ready = false;
|
||||||
|
private boolean loaded = false;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Log.w("tildefriends", "Calling system.loadLibrary().");
|
Log.w("tildefriends", "Calling system.loadLibrary().");
|
||||||
@@ -67,19 +71,8 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
|
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
|
||||||
public static native int tf_sandbox_main(int pipe_fd);
|
public static native int tf_sandbox_main(int pipe_fd);
|
||||||
|
|
||||||
@Override
|
private void createThread() {
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
s_activity = this;
|
|
||||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
|
||||||
.detectLeakedClosableObjects()
|
|
||||||
.penaltyLog()
|
|
||||||
.build());
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
|
|
||||||
web_view = (TildeFriendsWebView)findViewById(R.id.web);
|
web_view = (TildeFriendsWebView)findViewById(R.id.web);
|
||||||
set_status("Extracting executable...");
|
|
||||||
Log.w("tildefriends", String.format("getFilesDir() is %s", getFilesDir().toString()));
|
Log.w("tildefriends", String.format("getFilesDir() is %s", getFilesDir().toString()));
|
||||||
Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
|
Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
|
||||||
Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
|
Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
|
||||||
@@ -90,14 +83,13 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
|
|
||||||
TildeFriendsActivity activity = this;
|
TildeFriendsActivity activity = this;
|
||||||
|
|
||||||
|
server_thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
|
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString());
|
||||||
observer = make_file_observer(getFilesDir().toString(), port_file_path);
|
observer = make_file_observer(getFilesDir().toString(), port_file_path);
|
||||||
observer.startWatching();
|
observer.startWatching();
|
||||||
|
|
||||||
set_status("Starting server...");
|
|
||||||
server_thread = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Log.w("tildefriends", "Calling tf_server_main.");
|
Log.w("tildefriends", "Calling tf_server_main.");
|
||||||
int result = tf_server_main(
|
int result = tf_server_main(
|
||||||
getFilesDir().toString(),
|
getFilesDir().toString(),
|
||||||
@@ -109,6 +101,7 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
});
|
});
|
||||||
server_thread.start();
|
server_thread.start();
|
||||||
|
|
||||||
|
runOnUiThread(() -> {
|
||||||
web_view.getSettings().setJavaScriptEnabled(true);
|
web_view.getSettings().setJavaScriptEnabled(true);
|
||||||
web_view.getSettings().setDomStorageEnabled(true);
|
web_view.getSettings().setDomStorageEnabled(true);
|
||||||
|
|
||||||
@@ -241,6 +234,7 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
});
|
});
|
||||||
|
|
||||||
web_view.setWebViewClient(new WebViewClient() {
|
web_view.setWebViewClient(new WebViewClient() {
|
||||||
|
@Override
|
||||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
|
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
|
||||||
{
|
{
|
||||||
if (request.getUrl() != null && request.getUrl().toString().startsWith(base_url)) {
|
if (request.getUrl() != null && request.getUrl().toString().startsWith(base_url)) {
|
||||||
@@ -250,11 +244,62 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageFinished(WebView view, String url) {
|
||||||
|
s_activity.loaded = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
s_activity.create_thread = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
s_activity = this;
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
StrictMode.setThreadPolicy(
|
||||||
|
new StrictMode.ThreadPolicy.Builder()
|
||||||
|
.detectAll()
|
||||||
|
.penaltyDialog()
|
||||||
|
.penaltyLog()
|
||||||
|
.build());
|
||||||
|
StrictMode.setVmPolicy(
|
||||||
|
new StrictMode.VmPolicy.Builder()
|
||||||
|
.detectLeakedClosableObjects()
|
||||||
|
.detectAll()
|
||||||
|
.penaltyLog()
|
||||||
|
.build());
|
||||||
|
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
TextView refresh = (TextView)findViewById(R.id.refresh);
|
TextView refresh = (TextView)findViewById(R.id.refresh);
|
||||||
refresh.setVisibility(View.GONE);
|
refresh.setVisibility(View.GONE);
|
||||||
refresh.setText("REFRESH");
|
refresh.setText("REFRESH");
|
||||||
|
|
||||||
|
final View content = findViewById(android.R.id.content);
|
||||||
|
content.getViewTreeObserver().addOnPreDrawListener(
|
||||||
|
new ViewTreeObserver.OnPreDrawListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw() {
|
||||||
|
if (s_activity.ready && s_activity.loaded) {
|
||||||
|
content.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
create_thread = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
s_activity.createThread();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
create_thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -353,19 +398,6 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void set_status(String text) {
|
|
||||||
TextView text_view = (TextView)findViewById(R.id.text);
|
|
||||||
web_view.setVisibility(View.GONE);
|
|
||||||
text_view.setVisibility(View.VISIBLE);
|
|
||||||
text_view.setText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hide_status() {
|
|
||||||
TextView text_view = (TextView)findViewById(R.id.text);
|
|
||||||
web_view.setVisibility(View.VISIBLE);
|
|
||||||
text_view.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void start_sandbox(int pipe_fd) {
|
public static void start_sandbox(int pipe_fd) {
|
||||||
Log.w("tildefriends", "starting service with fd: " + pipe_fd);
|
Log.w("tildefriends", "starting service with fd: " + pipe_fd);
|
||||||
Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class);
|
Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class);
|
||||||
@@ -403,7 +435,7 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
Log.w("tildefriends", "onServiceDisconnected");
|
Log.w("tildefriends", "onServiceDisconnected");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE);
|
s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void stop_sandbox() {
|
public static void stop_sandbox() {
|
||||||
@@ -419,14 +451,11 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
if (port >= 0) {
|
if (port >= 0) {
|
||||||
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
|
base_url = "http://127.0.0.1:" + String.valueOf(port) + "/";
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
hide_status();
|
ready = true;
|
||||||
web_view.loadUrl(base_url + "login/auto");
|
web_view.loadUrl(base_url + "login/auto");
|
||||||
});
|
});
|
||||||
|
observer.stopWatching();
|
||||||
observer = null;
|
observer = null;
|
||||||
} else {
|
|
||||||
runOnUiThread(() -> {
|
|
||||||
set_status("Waiting to connect...");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,11 +10,6 @@
|
|||||||
android:id="@+id/web"
|
android:id="@+id/web"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
<TextView
|
|
||||||
android:id="@+id/text"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_horizontal|center_vertical"/>
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/refresh"
|
android:id="@+id/refresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
148
src/api.js.c
148
src/api.js.c
@@ -1,11 +1,159 @@
|
|||||||
#include "api.js.h"
|
#include "api.js.h"
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "ssb.db.h"
|
||||||
|
#include "ssb.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "util.js.h"
|
||||||
|
|
||||||
#include <quickjs.h>
|
#include <quickjs.h>
|
||||||
|
|
||||||
|
typedef struct _app_path_pair_t
|
||||||
|
{
|
||||||
|
const char* app;
|
||||||
|
const char* path;
|
||||||
|
} app_path_pair_t;
|
||||||
|
|
||||||
|
typedef struct _get_apps_t
|
||||||
|
{
|
||||||
|
app_path_pair_t* apps;
|
||||||
|
int count;
|
||||||
|
JSContext* context;
|
||||||
|
JSValue promise[2];
|
||||||
|
char user[];
|
||||||
|
} get_apps_t;
|
||||||
|
|
||||||
|
static void _tf_api_core_apps_work(tf_ssb_t* ssb, void* user_data)
|
||||||
|
{
|
||||||
|
get_apps_t* work = user_data;
|
||||||
|
|
||||||
|
JSMallocFunctions funcs = { 0 };
|
||||||
|
tf_get_js_malloc_functions(&funcs);
|
||||||
|
JSRuntime* runtime = JS_NewRuntime2(&funcs, NULL);
|
||||||
|
JSContext* context = JS_NewContext(runtime);
|
||||||
|
|
||||||
|
const char* apps = tf_ssb_db_get_property(ssb, work->user, "apps");
|
||||||
|
if (apps)
|
||||||
|
{
|
||||||
|
JSValue apps_array = JS_ParseJSON(context, apps, strlen(apps), NULL);
|
||||||
|
if (JS_IsArray(context, apps_array))
|
||||||
|
{
|
||||||
|
int length = tf_util_get_length(context, apps_array);
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
JSValue name = JS_GetPropertyUint32(context, apps_array, i);
|
||||||
|
const char* name_string = JS_ToCString(context, name);
|
||||||
|
if (name_string)
|
||||||
|
{
|
||||||
|
work->apps = tf_resize_vec(work->apps, sizeof(app_path_pair_t) * (work->count + 1));
|
||||||
|
work->apps[work->count].app = tf_strdup(name_string);
|
||||||
|
size_t size = strlen("path:") + strlen(name_string) + 1;
|
||||||
|
char* path_key = tf_malloc(size);
|
||||||
|
snprintf(path_key, size, "path:%s", name_string);
|
||||||
|
work->apps[work->count].path = tf_ssb_db_get_property(ssb, work->user, path_key);
|
||||||
|
tf_free(path_key);
|
||||||
|
work->count++;
|
||||||
|
}
|
||||||
|
JS_FreeCString(context, name_string);
|
||||||
|
JS_FreeValue(context, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, apps_array);
|
||||||
|
}
|
||||||
|
tf_free((void*)apps);
|
||||||
|
|
||||||
|
JS_FreeContext(context);
|
||||||
|
JS_FreeRuntime(runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _tf_api_core_apps_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
|
{
|
||||||
|
get_apps_t* work = user_data;
|
||||||
|
JSContext* context = work->context;
|
||||||
|
JSValue result = JS_NewObject(context);
|
||||||
|
for (int i = 0; i < work->count; i++)
|
||||||
|
{
|
||||||
|
JS_SetPropertyStr(context, result, work->apps[i].app, JS_NewString(context, work->apps[i].path));
|
||||||
|
}
|
||||||
|
JSValue error = JS_Call(context, work->promise[0], JS_UNDEFINED, 1, &result);
|
||||||
|
tf_util_report_error(context, error);
|
||||||
|
JS_FreeValue(context, error);
|
||||||
|
JS_FreeValue(context, result);
|
||||||
|
JS_FreeValue(context, work->promise[0]);
|
||||||
|
JS_FreeValue(context, work->promise[1]);
|
||||||
|
for (int i = 0; i < work->count; i++)
|
||||||
|
{
|
||||||
|
tf_free((void*)work->apps[i].app);
|
||||||
|
tf_free((void*)work->apps[i].path);
|
||||||
|
}
|
||||||
|
tf_free(work->apps);
|
||||||
|
tf_free(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue _tf_api_core_apps(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv, int magic, JSValue* data)
|
||||||
|
{
|
||||||
|
JSValue result = JS_UNDEFINED;
|
||||||
|
JSValue user = argv[0];
|
||||||
|
JSValue process = data[0];
|
||||||
|
const char* user_string = JS_IsString(user) ? JS_ToCString(context, user) : NULL;
|
||||||
|
|
||||||
|
if (JS_IsObject(process))
|
||||||
|
{
|
||||||
|
JSValue credentials = JS_GetPropertyStr(context, process, "credentials");
|
||||||
|
if (JS_IsObject(credentials))
|
||||||
|
{
|
||||||
|
JSValue session = JS_GetPropertyStr(context, credentials, "session");
|
||||||
|
if (JS_IsObject(session))
|
||||||
|
{
|
||||||
|
JSValue session_name = JS_GetPropertyStr(context, session, "name");
|
||||||
|
const char* session_name_string = JS_IsString(session_name) ? JS_ToCString(context, session_name) : NULL;
|
||||||
|
if (user_string && session_name_string && strcmp(user_string, session_name_string) && strcmp(user_string, "core"))
|
||||||
|
{
|
||||||
|
JS_FreeCString(context, user_string);
|
||||||
|
user_string = NULL;
|
||||||
|
}
|
||||||
|
else if (!user_string)
|
||||||
|
{
|
||||||
|
user_string = session_name_string;
|
||||||
|
session_name_string = NULL;
|
||||||
|
}
|
||||||
|
JS_FreeCString(context, session_name_string);
|
||||||
|
JS_FreeValue(context, session_name);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, session);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_string)
|
||||||
|
{
|
||||||
|
get_apps_t* work = tf_malloc(sizeof(get_apps_t) + strlen(user_string) + 1);
|
||||||
|
*work = (get_apps_t) {
|
||||||
|
.context = context,
|
||||||
|
};
|
||||||
|
memcpy(work->user, user_string, strlen(user_string) + 1);
|
||||||
|
result = JS_NewPromiseCapability(context, work->promise);
|
||||||
|
|
||||||
|
tf_task_t* task = tf_task_get(context);
|
||||||
|
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||||
|
tf_ssb_run_work(ssb, _tf_api_core_apps_work, _tf_api_core_apps_after_work, work);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = JS_NewObject(context);
|
||||||
|
}
|
||||||
|
JS_FreeCString(context, user_string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _tf_api_register_imports(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
{
|
{
|
||||||
|
JSValue imports = argv[0];
|
||||||
|
JSValue process = argv[1];
|
||||||
|
JSValue core = JS_GetPropertyStr(context, imports, "core");
|
||||||
|
JS_SetPropertyStr(context, core, "apps", JS_NewCFunctionData(context, _tf_api_core_apps, 1, 0, 1, &process));
|
||||||
|
JS_FreeValue(context, core);
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -177,7 +177,7 @@ static void _httpd_endpoint_app_index_file_read(tf_task_t* task, const char* pat
|
|||||||
char* replacement = tf_strdup("<iframe srcdoc=\"");
|
char* replacement = tf_strdup("<iframe srcdoc=\"");
|
||||||
size_t replacement_size = 0;
|
size_t replacement_size = 0;
|
||||||
replacement = _append_encoded(replacement, state->data, state->size, &replacement_size);
|
replacement = _append_encoded(replacement, state->data, state->size, &replacement_size);
|
||||||
_append_raw(replacement, &replacement_size, "\"", 1);
|
replacement = _append_raw(replacement, &replacement_size, "\"", 1);
|
||||||
|
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* document = _replace(data, result, "<iframe", replacement, &size);
|
char* document = _replace(data, result, "<iframe", replacement, &size);
|
||||||
|
@@ -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.33</string>
|
<string>0.2025.8</string>
|
||||||
<key>CFBundleSupportedPlatforms</key>
|
<key>CFBundleSupportedPlatforms</key>
|
||||||
<array>
|
<array>
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>15</string>
|
<string>16</string>
|
||||||
<key>DTPlatformName</key>
|
<key>DTPlatformName</key>
|
||||||
<string>iphoneos</string>
|
<string>iphoneos</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
@@ -1442,7 +1442,7 @@ static int _tf_run_task(const tf_run_args_t* args, int index)
|
|||||||
int result = -1;
|
int result = -1;
|
||||||
tf_task_t* task = tf_task_create();
|
tf_task_t* task = tf_task_create();
|
||||||
tf_task_set_trusted(task, true);
|
tf_task_set_trusted(task, true);
|
||||||
tf_printf("setting zip path to %s\n", args->zip);
|
tf_printf("Zip path: %s\n", args->zip);
|
||||||
tf_task_set_zip_path(task, args->zip);
|
tf_task_set_zip_path(task, args->zip);
|
||||||
tf_task_set_ssb_network_key(task, args->network_key);
|
tf_task_set_ssb_network_key(task, args->network_key);
|
||||||
tf_task_set_args(task, args->args);
|
tf_task_set_args(task, args->args);
|
||||||
@@ -1487,7 +1487,7 @@ static int _tf_run_task(const tf_run_args_t* args, int index)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tf_printf("Using %s as the working directory.\n", cwd);
|
tf_printf("Root path: %s\n", cwd);
|
||||||
}
|
}
|
||||||
if (!*cwd)
|
if (!*cwd)
|
||||||
{
|
{
|
||||||
|
88
src/ssb.c
88
src/ssb.c
@@ -133,6 +133,15 @@ typedef struct _tf_ssb_message_added_callback_node_t
|
|||||||
tf_ssb_message_added_callback_node_t* next;
|
tf_ssb_message_added_callback_node_t* next;
|
||||||
} tf_ssb_message_added_callback_node_t;
|
} tf_ssb_message_added_callback_node_t;
|
||||||
|
|
||||||
|
typedef struct _tf_ssb_blob_stored_callback_node_t tf_ssb_blob_stored_callback_node_t;
|
||||||
|
typedef struct _tf_ssb_blob_stored_callback_node_t
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_t* callback;
|
||||||
|
tf_ssb_callback_cleanup_t* cleanup;
|
||||||
|
void* user_data;
|
||||||
|
tf_ssb_blob_stored_callback_node_t* next;
|
||||||
|
} tf_ssb_blob_stored_callback_node_t;
|
||||||
|
|
||||||
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t;
|
typedef struct _tf_ssb_blob_want_added_callback_node_t tf_ssb_blob_want_added_callback_node_t;
|
||||||
typedef struct _tf_ssb_blob_want_added_callback_node_t
|
typedef struct _tf_ssb_blob_want_added_callback_node_t
|
||||||
{
|
{
|
||||||
@@ -235,6 +244,9 @@ typedef struct _tf_ssb_t
|
|||||||
tf_ssb_message_added_callback_node_t* message_added;
|
tf_ssb_message_added_callback_node_t* message_added;
|
||||||
int message_added_count;
|
int message_added_count;
|
||||||
|
|
||||||
|
tf_ssb_blob_stored_callback_node_t* blob_stored;
|
||||||
|
int blob_stored_count;
|
||||||
|
|
||||||
tf_ssb_blob_want_added_callback_node_t* blob_want_added;
|
tf_ssb_blob_want_added_callback_node_t* blob_want_added;
|
||||||
int blob_want_added_count;
|
int blob_want_added_count;
|
||||||
|
|
||||||
@@ -977,7 +989,6 @@ bool tf_ssb_connection_rpc_send_error_method_not_allowed(tf_ssb_connection_t* co
|
|||||||
{
|
{
|
||||||
char buffer[1024] = "";
|
char buffer[1024] = "";
|
||||||
snprintf(buffer, sizeof(buffer), "method '%s' is not in list of allowed methods", name);
|
snprintf(buffer, sizeof(buffer), "method '%s' is not in list of allowed methods", name);
|
||||||
tf_printf("%s\n", buffer);
|
|
||||||
return tf_ssb_connection_rpc_send_error(connection, flags, request_number, buffer);
|
return tf_ssb_connection_rpc_send_error(connection, flags, request_number, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2742,6 +2753,17 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
}
|
}
|
||||||
tf_free(node);
|
tf_free(node);
|
||||||
}
|
}
|
||||||
|
while (ssb->blob_stored)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* node = ssb->blob_stored;
|
||||||
|
ssb->blob_stored = node->next;
|
||||||
|
ssb->blob_stored_count--;
|
||||||
|
if (node->cleanup)
|
||||||
|
{
|
||||||
|
node->cleanup(ssb, node->user_data);
|
||||||
|
}
|
||||||
|
tf_free(node);
|
||||||
|
}
|
||||||
while (ssb->blob_want_added)
|
while (ssb->blob_want_added)
|
||||||
{
|
{
|
||||||
tf_ssb_blob_want_added_callback_node_t* node = ssb->blob_want_added;
|
tf_ssb_blob_want_added_callback_node_t* node = ssb->blob_want_added;
|
||||||
@@ -2784,6 +2806,16 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
|
|
||||||
uv_run(ssb->loop, UV_RUN_NOWAIT);
|
uv_run(ssb->loop, UV_RUN_NOWAIT);
|
||||||
|
|
||||||
|
if (ssb->own_context)
|
||||||
|
{
|
||||||
|
if (!ssb->quiet)
|
||||||
|
{
|
||||||
|
tf_printf("closing ssb context\n");
|
||||||
|
}
|
||||||
|
JS_FreeContext(ssb->context);
|
||||||
|
JS_FreeRuntime(ssb->runtime);
|
||||||
|
ssb->own_context = false;
|
||||||
|
}
|
||||||
if (ssb->loop == &ssb->own_loop)
|
if (ssb->loop == &ssb->own_loop)
|
||||||
{
|
{
|
||||||
if (!ssb->quiet)
|
if (!ssb->quiet)
|
||||||
@@ -2800,16 +2832,6 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
|
|||||||
{
|
{
|
||||||
tf_printf("uv loop closed.\n");
|
tf_printf("uv loop closed.\n");
|
||||||
}
|
}
|
||||||
if (ssb->own_context)
|
|
||||||
{
|
|
||||||
if (!ssb->quiet)
|
|
||||||
{
|
|
||||||
tf_printf("closing ssb context\n");
|
|
||||||
}
|
|
||||||
JS_FreeContext(ssb->context);
|
|
||||||
JS_FreeRuntime(ssb->runtime);
|
|
||||||
ssb->own_context = false;
|
|
||||||
}
|
|
||||||
while (ssb->broadcasts)
|
while (ssb->broadcasts)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t* broadcast = ssb->broadcasts;
|
tf_ssb_broadcast_t* broadcast = ssb->broadcasts;
|
||||||
@@ -3961,9 +3983,53 @@ void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tf_ssb_add_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, void (*cleanup)(tf_ssb_t* ssb, void* user_data), void* user_data)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* node = tf_malloc(sizeof(tf_ssb_blob_stored_callback_node_t));
|
||||||
|
*node = (tf_ssb_blob_stored_callback_node_t) {
|
||||||
|
.callback = callback,
|
||||||
|
.cleanup = cleanup,
|
||||||
|
.user_data = user_data,
|
||||||
|
.next = ssb->blob_stored,
|
||||||
|
};
|
||||||
|
ssb->blob_stored = node;
|
||||||
|
ssb->blob_stored_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tf_ssb_remove_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, void* user_data)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t** it = &ssb->blob_stored;
|
||||||
|
while (*it)
|
||||||
|
{
|
||||||
|
if ((*it)->callback == callback && (*it)->user_data == user_data)
|
||||||
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* node = *it;
|
||||||
|
*it = node->next;
|
||||||
|
ssb->blob_stored_count--;
|
||||||
|
if (node->cleanup)
|
||||||
|
{
|
||||||
|
node->cleanup(ssb, node->user_data);
|
||||||
|
}
|
||||||
|
tf_free(node);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it = &(*it)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tf_ssb_notify_blob_stored(tf_ssb_t* ssb, const char* id)
|
void tf_ssb_notify_blob_stored(tf_ssb_t* ssb, const char* id)
|
||||||
{
|
{
|
||||||
|
tf_ssb_blob_stored_callback_node_t* next = NULL;
|
||||||
ssb->blobs_stored++;
|
ssb->blobs_stored++;
|
||||||
|
for (tf_ssb_blob_stored_callback_node_t* node = ssb->blob_stored; node; node = next)
|
||||||
|
{
|
||||||
|
next = node->next;
|
||||||
|
tf_trace_begin(ssb->trace, "blob stored callback");
|
||||||
|
node->callback(ssb, id, node->user_data);
|
||||||
|
tf_trace_end(ssb->trace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_keys)
|
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_keys)
|
||||||
|
@@ -903,10 +903,6 @@ void tf_ssb_db_add_blob_wants(sqlite3* db, const char* id)
|
|||||||
{
|
{
|
||||||
tf_printf("blob wants cache update failed: %s.\n", sqlite3_errmsg(db));
|
tf_printf("blob wants cache update failed: %s.\n", sqlite3_errmsg(db));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
tf_printf("want: %s\n", id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sqlite3_finalize(statement);
|
sqlite3_finalize(statement);
|
||||||
}
|
}
|
||||||
|
25
src/ssb.h
25
src/ssb.h
@@ -680,6 +680,31 @@ void tf_ssb_remove_message_added_callback(tf_ssb_t* ssb, tf_ssb_message_added_ca
|
|||||||
*/
|
*/
|
||||||
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_with_keys);
|
void tf_ssb_notify_message_added(tf_ssb_t* ssb, const char* author, int32_t sequence, const char* id, JSValue message_with_keys);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** A callback called when a blob is added to the database.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param id The blob identifier.
|
||||||
|
** @param user_data The user data.
|
||||||
|
*/
|
||||||
|
typedef void(tf_ssb_blob_stored_callback_t)(tf_ssb_t* ssb, const char* id, void* user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Register a callback called when a blob is added to the database.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param callback The callback function.
|
||||||
|
** @param cleanup A function to call when the callback is removed.
|
||||||
|
** @param user_data User data to pass to the callback.
|
||||||
|
*/
|
||||||
|
void tf_ssb_add_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, tf_ssb_callback_cleanup_t* cleanup, void* user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Remove a callback registered for when a blob is added to the database.
|
||||||
|
** @param ssb The SSB instance.
|
||||||
|
** @param callback The callback function.
|
||||||
|
** @param user_data User data registered with the callback.
|
||||||
|
*/
|
||||||
|
void tf_ssb_remove_blob_stored_callback(tf_ssb_t* ssb, tf_ssb_blob_stored_callback_t* callback, void* user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Record that a new blob was stored.
|
** Record that a new blob was stored.
|
||||||
** @param ssb The SSB instance.
|
** @param ssb The SSB instance.
|
||||||
|
24
src/ssb.js.c
24
src/ssb.js.c
@@ -1627,6 +1627,20 @@ static void _tf_ssb_on_message_added_callback(tf_ssb_t* ssb, const char* author,
|
|||||||
JS_FreeValue(context, string);
|
JS_FreeValue(context, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tf_ssb_on_blob_stored_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
|
{
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
|
JSValue callback = JS_MKPTR(JS_TAG_OBJECT, user_data);
|
||||||
|
JSValue string = JS_NewString(context, id);
|
||||||
|
JSValue response = JS_Call(context, callback, JS_UNDEFINED, 1, &string);
|
||||||
|
if (tf_util_report_error(context, response))
|
||||||
|
{
|
||||||
|
tf_ssb_remove_blob_stored_callback(ssb, _tf_ssb_on_blob_stored_callback, user_data);
|
||||||
|
}
|
||||||
|
JS_FreeValue(context, response);
|
||||||
|
JS_FreeValue(context, string);
|
||||||
|
}
|
||||||
|
|
||||||
static void _tf_ssb_on_blob_want_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
static void _tf_ssb_on_blob_want_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
{
|
{
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
@@ -1747,6 +1761,11 @@ static JSValue _tf_ssb_add_event_listener(JSContext* context, JSValueConst this_
|
|||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
tf_ssb_add_message_added_callback(ssb, _tf_ssb_on_message_added_callback, _tf_ssb_cleanup_value, ptr);
|
tf_ssb_add_message_added_callback(ssb, _tf_ssb_on_message_added_callback, _tf_ssb_cleanup_value, ptr);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(event_name, "blob") == 0)
|
||||||
|
{
|
||||||
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
|
tf_ssb_add_blob_stored_callback(ssb, _tf_ssb_on_blob_stored_callback, _tf_ssb_cleanup_value, ptr);
|
||||||
|
}
|
||||||
else if (strcmp(event_name, "blob_want_added") == 0)
|
else if (strcmp(event_name, "blob_want_added") == 0)
|
||||||
{
|
{
|
||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
@@ -1790,6 +1809,11 @@ static JSValue _tf_ssb_remove_event_listener(JSContext* context, JSValueConst th
|
|||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
tf_ssb_remove_message_added_callback(ssb, _tf_ssb_on_message_added_callback, ptr);
|
tf_ssb_remove_message_added_callback(ssb, _tf_ssb_on_message_added_callback, ptr);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(event_name, "blob") == 0)
|
||||||
|
{
|
||||||
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
|
tf_ssb_remove_blob_stored_callback(ssb, _tf_ssb_on_blob_stored_callback, ptr);
|
||||||
|
}
|
||||||
else if (strcmp(event_name, "blob_want_added") == 0)
|
else if (strcmp(event_name, "blob_want_added") == 0)
|
||||||
{
|
{
|
||||||
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
void* ptr = JS_VALUE_GET_PTR(JS_DupValue(context, callback));
|
||||||
|
@@ -1561,7 +1561,10 @@ static void _tf_ssb_rpc_delete_blobs_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
tf_free(ids);
|
tf_free(ids);
|
||||||
}
|
}
|
||||||
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
|
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
|
||||||
|
if (deleted)
|
||||||
|
{
|
||||||
tf_printf("Deleted %d blobs in %d ms.\n", deleted, (int)delete->duration_ms);
|
tf_printf("Deleted %d blobs in %d ms.\n", deleted, (int)delete->duration_ms);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -1580,7 +1583,6 @@ static void _tf_ssb_rpc_start_delete_blobs_callback(tf_ssb_t* ssb, void* user_da
|
|||||||
|
|
||||||
static void _tf_ssb_rpc_start_delete_blobs(tf_ssb_t* ssb, int delay_ms)
|
static void _tf_ssb_rpc_start_delete_blobs(tf_ssb_t* ssb, int delay_ms)
|
||||||
{
|
{
|
||||||
tf_printf("will delete more blobs in %d ms\n", delay_ms);
|
|
||||||
tf_ssb_schedule_work(ssb, delay_ms, _tf_ssb_rpc_start_delete_blobs_callback, NULL);
|
tf_ssb_schedule_work(ssb, delay_ms, _tf_ssb_rpc_start_delete_blobs_callback, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1675,7 +1677,10 @@ static void _tf_ssb_rpc_delete_feeds_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
JS_FreeRuntime(runtime);
|
JS_FreeRuntime(runtime);
|
||||||
|
|
||||||
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
|
delete->duration_ms = (uv_hrtime() - start_ns) / 1000000LL;
|
||||||
|
if (delete->deleted)
|
||||||
|
{
|
||||||
tf_printf("Deleted %d message in %d ms.\n", delete->deleted, (int)delete->duration_ms);
|
tf_printf("Deleted %d message in %d ms.\n", delete->deleted, (int)delete->duration_ms);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_delete_feeds_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
static void _tf_ssb_rpc_delete_feeds_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||||
@@ -1694,7 +1699,6 @@ static void _tf_ssb_rpc_start_delete_feeds_callback(tf_ssb_t* ssb, void* user_da
|
|||||||
|
|
||||||
static void _tf_ssb_rpc_start_delete_feeds(tf_ssb_t* ssb, int delay_ms)
|
static void _tf_ssb_rpc_start_delete_feeds(tf_ssb_t* ssb, int delay_ms)
|
||||||
{
|
{
|
||||||
tf_printf("will delete more feeds in %d ms\n", delay_ms);
|
|
||||||
tf_ssb_schedule_work(ssb, delay_ms, _tf_ssb_rpc_start_delete_feeds_callback, NULL);
|
tf_ssb_schedule_work(ssb, delay_ms, _tf_ssb_rpc_start_delete_feeds_callback, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -152,6 +152,12 @@ static void _wait_stored(tf_ssb_t* ssb, bool* stored)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _blob_stored(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
|
{
|
||||||
|
tf_printf("blob stored %s\n", id);
|
||||||
|
*(bool*)user_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
void tf_ssb_test_ssb(const tf_test_options_t* options)
|
void tf_ssb_test_ssb(const tf_test_options_t* options)
|
||||||
{
|
{
|
||||||
tf_printf("Testing SSB.\n");
|
tf_printf("Testing SSB.\n");
|
||||||
@@ -224,8 +230,13 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
|
|
||||||
char blob_id[k_id_base64_len] = { 0 };
|
char blob_id[k_id_base64_len] = { 0 };
|
||||||
const char* k_blob = "Hello, blob!";
|
const char* k_blob = "Hello, blob!";
|
||||||
|
bool blob_stored = false;
|
||||||
|
tf_ssb_add_blob_stored_callback(ssb0, _blob_stored, NULL, &blob_stored);
|
||||||
b = tf_ssb_db_blob_store(ssb0, (const uint8_t*)k_blob, strlen(k_blob), blob_id, sizeof(blob_id), NULL);
|
b = tf_ssb_db_blob_store(ssb0, (const uint8_t*)k_blob, strlen(k_blob), blob_id, sizeof(blob_id), NULL);
|
||||||
|
tf_ssb_notify_blob_stored(ssb0, blob_id);
|
||||||
|
tf_ssb_remove_blob_stored_callback(ssb0, _blob_stored, &blob_stored);
|
||||||
assert(b);
|
assert(b);
|
||||||
|
assert(blob_stored);
|
||||||
|
|
||||||
JSContext* context0 = tf_ssb_get_context(ssb0);
|
JSContext* context0 = tf_ssb_get_context(ssb0);
|
||||||
JSValue obj = JS_NewObject(context0);
|
JSValue obj = JS_NewObject(context0);
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
#define VERSION_NUMBER "0.0.33-wip"
|
#define VERSION_NUMBER "0.2025.8"
|
||||||
#define VERSION_NAME "This program kills fascists."
|
#define VERSION_NAME "This program kills fascists."
|
||||||
|
@@ -93,7 +93,7 @@ try:
|
|||||||
select(driver, ['#document', 'frame', '#gs_room_name'], ('send_keys', 'test room'))
|
select(driver, ['#document', 'frame', '#gs_room_name'], ('send_keys', 'test room'))
|
||||||
select(driver, ['#document', 'frame', '//*[@id="gs_room_name"]/following-sibling::button'], ('click',))
|
select(driver, ['#document', 'frame', '//*[@id="gs_room_name"]/following-sibling::button'], ('click',))
|
||||||
select(driver, ['//button[text()="✅ Allow"]'], ('click',))
|
select(driver, ['//button[text()="✅ Allow"]'], ('click',))
|
||||||
driver.switch_to.alert.accept()
|
wait.until(expected_conditions.alert_is_present()).accept()
|
||||||
|
|
||||||
select(driver, ['tf-navigation', 'shadow_root', '#identity'], ('click',))
|
select(driver, ['tf-navigation', 'shadow_root', '#identity'], ('click',))
|
||||||
select(driver, ['tf-navigation', 'shadow_root', '#logout'], ('click',))
|
select(driver, ['tf-navigation', 'shadow_root', '#logout'], ('click',))
|
||||||
|
Reference in New Issue
Block a user