Compare commits
41 Commits
latest_rel
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 33fb96b120 | |||
| 28a4accabf | |||
| 31c7394c17 | |||
| e2974d34e2 | |||
| 4a06c84511 | |||
| 4960a1d9d6 | |||
| 75dd8889e9 | |||
| 111a6c3c6e | |||
| 775fdafa63 | |||
| dae38bbd83 | |||
| 35f374047a | |||
| aea4a14a62 | |||
| 98f7504a4c | |||
| bb52cdd7c2 | |||
| 07b660a0d6 | |||
| 2b9d712d48 | |||
| 3c1f60b62d | |||
| bb75edfd42 | |||
| c2b61cec2c | |||
| 05c3107b27 | |||
| bb67df7846 | |||
| 89ec523ea2 | |||
| f30458d953 | |||
| 42df0d830e | |||
| 50b2c0c7f4 | |||
| 0edb76b678 | |||
| 2d71af3243 | |||
| b571cd213b | |||
| b52c79ac4e | |||
| 63c6a5ab07 | |||
| 4447ea63e2 | |||
| 61200c4a7d | |||
| 62dc9d6cc0 | |||
| a28d41e1ee | |||
| 6a05e3770b | |||
| 53a93e510c | |||
| 1cb3ecf1ea | |||
| 687665cd6b | |||
| 7879ab1d50 | |||
| 24f0cdb398 | |||
| 6d5555e596 |
15
GNUmakefile
15
GNUmakefile
@@ -16,15 +16,15 @@ MAKEFLAGS += --no-builtin-rules
|
||||
## LD := Linker.
|
||||
## ANDROID_SDK := Path to the Android SDK.
|
||||
|
||||
VERSION_CODE := 44
|
||||
VERSION_CODE_IOS := 18
|
||||
VERSION_CODE := 47
|
||||
VERSION_CODE_IOS := 25
|
||||
VERSION_NUMBER := 0.2025.10
|
||||
VERSION_NAME := This program kills fascists.
|
||||
|
||||
IPHONEOS_VERSION_MIN=14.0
|
||||
IPHONEOS_VERSION_MIN=14.5
|
||||
|
||||
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3500400.zip
|
||||
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
||||
SQLITE_URL := https://www.sqlite.org/2025/sqlite-amalgamation-3510000.zip
|
||||
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.18.2/bundletool-all-1.18.2.jar
|
||||
APPIMAGETOOL_URL := https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
APPIMAGETOOL_MD5 := e989fadfc4d685fd3d6aeeb9b525d74d out/appimagetool
|
||||
|
||||
@@ -815,7 +815,9 @@ $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS): CFLAGS += \
|
||||
$(IOS_TARGETS) $(IOSSIM_TARGETS): LDFLAGS += \
|
||||
-framework Foundation \
|
||||
-framework CoreFoundation \
|
||||
-framework CoreSpotlight \
|
||||
-framework UIKit \
|
||||
-framework UniformTypeIdentifiers \
|
||||
-framework WebKit
|
||||
|
||||
##
|
||||
@@ -1180,8 +1182,9 @@ ios%go: out/tildefriends-ios%.app/tildefriends
|
||||
ideviceinstaller -i $(realpath $(dir $<))
|
||||
|
||||
iossimdebuggo: out/tildefriends-iossimdebug.app/tildefriends ## Build, install, and run an iOS debug build.
|
||||
xcrun -sdk iphoneos codesign -f -s 'Apple Distribution' --entitlements src/ios/Entitlements.plist --generate-entitlement-der out/tildefriends-iossimdebug.app
|
||||
xcrun simctl install booted out/tildefriends-iossimdebug.app/
|
||||
xcrun simctl launch booted com.unprompted.tildefriends
|
||||
xcrun simctl launch --console booted com.unprompted.tildefriends
|
||||
.PHONY: iossimdebuggo
|
||||
|
||||
out/macos%/tildefriends: out/macos%-arm/tildefriends out/macos%-x86_64/tildefriends
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"type": "tildefriends-app",
|
||||
"emoji": "🦀",
|
||||
"previous": "&Gic1e3jOZ7z5131jSCclbFXRpjyu8JlWJrjE7Fvn5dc=.sha256"
|
||||
"previous": "&Tozi8g5lPpLW7znc+jm7xDZxoTq1G3DJAh2YhG+FRAQ=.sha256"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as tfrpc from '/tfrpc.js';
|
||||
|
||||
let g_database;
|
||||
let g_hash;
|
||||
let g_sql_cache = {};
|
||||
|
||||
tfrpc.register(async function localStorageGet(key) {
|
||||
return app.localStorageGet(key);
|
||||
@@ -51,11 +52,38 @@ tfrpc.register(async function connect(token) {
|
||||
tfrpc.register(async function closeConnection(id) {
|
||||
await ssb.closeConnection(id);
|
||||
});
|
||||
tfrpc.register(async function query(sql, args) {
|
||||
tfrpc.register(async function query(sql, args, options) {
|
||||
let start = new Date();
|
||||
let result = [];
|
||||
await ssb.sqlAsync(sql, args, function callback(row) {
|
||||
result.push(row);
|
||||
});
|
||||
let key = options?.cacheable ? JSON.stringify([sql, args]) : undefined;
|
||||
let entry = key ? g_sql_cache[key] : undefined;
|
||||
const k_ideal_count = 64;
|
||||
if (entry) {
|
||||
result = entry.result;
|
||||
} else {
|
||||
await ssb.sqlAsync(sql, args, function callback(row) {
|
||||
result.push(row);
|
||||
});
|
||||
if (key) {
|
||||
g_sql_cache[key] = {
|
||||
result: result,
|
||||
time: new Date().valueOf(),
|
||||
};
|
||||
if (Object.keys(g_sql_cache).length > k_ideal_count * 2) {
|
||||
let aged = Object.entries(g_sql_cache).map(([k, v]) => [v.time, k]);
|
||||
aged.sort();
|
||||
for (let i = 0; i < aged.length / 2; i++) {
|
||||
delete g_sql_cache[aged[i][1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let end = new Date();
|
||||
print(
|
||||
(end - start) / 1000,
|
||||
entry ? 'from cache' : 'from db',
|
||||
sql.replaceAll(/\s+/g, ' ').trim()
|
||||
);
|
||||
return result;
|
||||
});
|
||||
tfrpc.register(async function appendMessage(id, message) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -403,14 +403,6 @@ class TfElement extends LitElement {
|
||||
return [cache.latest, cache.messages];
|
||||
}
|
||||
|
||||
async query_timed(sql, args) {
|
||||
let start = new Date();
|
||||
let result = await tfrpc.rpc.query(sql, args);
|
||||
let end = new Date();
|
||||
console.log((end - start) / 1000, sql.replaceAll(/\s+/g, ' ').trim());
|
||||
return result;
|
||||
}
|
||||
|
||||
async group_private_messages(messages) {
|
||||
let groups = {};
|
||||
let result = await this.decrypt(
|
||||
@@ -452,7 +444,7 @@ class TfElement extends LitElement {
|
||||
];
|
||||
let channels = (
|
||||
await Promise.all([
|
||||
this.query_timed(
|
||||
tfrpc.rpc.query(
|
||||
`
|
||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN json_each(?1) AS channels ON messages.content ->> 'channel' = channels.value
|
||||
@@ -465,7 +457,7 @@ class TfElement extends LitElement {
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
tfrpc.rpc.query(
|
||||
`
|
||||
SELECT channels.value AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN messages_refs ON messages.id = messages_refs.message
|
||||
@@ -479,7 +471,7 @@ class TfElement extends LitElement {
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
tfrpc.rpc.query(
|
||||
`
|
||||
SELECT '' AS channel, MAX(messages.rowid) AS rowid FROM messages
|
||||
JOIN json_each(?2) AS following ON messages.author = following.value
|
||||
@@ -490,7 +482,7 @@ class TfElement extends LitElement {
|
||||
`,
|
||||
k_args
|
||||
),
|
||||
this.query_timed(
|
||||
tfrpc.rpc.query(
|
||||
`
|
||||
SELECT '@' AS channel, MAX(messages.rowid) AS rowid FROM messages_fts(?3)
|
||||
JOIN messages ON messages.rowid = messages_fts.rowid
|
||||
@@ -501,7 +493,7 @@ class TfElement extends LitElement {
|
||||
),
|
||||
])
|
||||
).flat();
|
||||
let latest = {};
|
||||
let latest = {'🔐': undefined};
|
||||
for (let row of channels) {
|
||||
if (!latest[row.channel]) {
|
||||
latest[row.channel] = row.rowid;
|
||||
@@ -514,14 +506,13 @@ class TfElement extends LitElement {
|
||||
let self = this;
|
||||
start_time = new Date();
|
||||
latest_private.then(async function (latest) {
|
||||
let grouped = await self.group_private_messages(latest[1]);
|
||||
self.channels_latest = Object.assign({}, self.channels_latest, {
|
||||
'🔐': latest[0],
|
||||
});
|
||||
console.log('private took', (new Date() - start_time) / 1000.0);
|
||||
self.private_messages = latest[1];
|
||||
self.grouped_private_messages = await self.group_private_messages(
|
||||
latest[1]
|
||||
);
|
||||
self.grouped_private_messages = grouped;
|
||||
console.log('private took', (new Date() - start_time) / 1000.0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -37,16 +37,22 @@ class TfProfileElement extends LitElement {
|
||||
this.following = undefined;
|
||||
this.blocking = undefined;
|
||||
|
||||
let latest = (
|
||||
await tfrpc.rpc.query('SELECT MAX(rowid) AS latest FROM messages')
|
||||
)[0].latest;
|
||||
|
||||
let result = await tfrpc.rpc.query(
|
||||
`
|
||||
SELECT json_extract(content, '$.following') AS following
|
||||
FROM messages WHERE author = ? AND
|
||||
json_extract(content, '$.type') = 'contact' AND
|
||||
json_extract(content, '$.contact') = ? AND
|
||||
following IS NOT NULL
|
||||
following IS NOT NULL AND
|
||||
messages.rowid <= ?
|
||||
ORDER BY sequence DESC LIMIT 1
|
||||
`,
|
||||
[this.whoami, this.id]
|
||||
[this.whoami, this.id, latest],
|
||||
{cacheable: true}
|
||||
);
|
||||
this.following = result?.[0]?.following ?? false;
|
||||
result = await tfrpc.rpc.query(
|
||||
@@ -55,10 +61,12 @@ class TfProfileElement extends LitElement {
|
||||
FROM messages WHERE author = ? AND
|
||||
json_extract(content, '$.type') = 'contact' AND
|
||||
json_extract(content, '$.contact') = ? AND
|
||||
blocking IS NOT NULL
|
||||
blocking IS NOT NULL AND
|
||||
messages.rowid <= ?
|
||||
ORDER BY sequence DESC LIMIT 1
|
||||
`,
|
||||
[this.whoami, this.id]
|
||||
[this.whoami, this.id, latest],
|
||||
{cacheable: true}
|
||||
);
|
||||
this.blocking = result?.[0]?.blocking ?? false;
|
||||
}
|
||||
@@ -238,7 +246,7 @@ class TfProfileElement extends LitElement {
|
||||
let profile = this.users[this.id] || {};
|
||||
tfrpc.rpc
|
||||
.query(
|
||||
`SELECT SUM(LENGTH(content)) AS size, MAX(sequence) AS sequence FROM messages WHERE author = ?`,
|
||||
`SELECT size AS size, max_sequence AS sequence FROM messages_stats WHERE author = ?`,
|
||||
[this.id]
|
||||
)
|
||||
.then(function (result) {
|
||||
|
||||
@@ -175,7 +175,6 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
[this.hash.substring(1)]
|
||||
);
|
||||
} else if (this.hash.startsWith('##')) {
|
||||
let t0 = new Date();
|
||||
let initial_messages = await tfrpc.rpc.query(
|
||||
`
|
||||
WITH
|
||||
@@ -203,12 +202,7 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
k_max_results,
|
||||
]
|
||||
);
|
||||
let t1 = new Date();
|
||||
result = await this._fetch_related_messages(initial_messages);
|
||||
let t2 = new Date();
|
||||
console.log(
|
||||
`load of ${result.length} rows took ${(t2 - t0) / 1000} (${(t1 - t0) / 1000} to find ${initial_messages.length} initial messages, ${(t2 - t1) / 1000} to find ${result.length} total messages) following=${this.following.length} st=${start_time} et=${end_time}`
|
||||
);
|
||||
} else if (this.hash.startsWith('#🔐')) {
|
||||
let ids =
|
||||
this.hash == '#🔐' ? [] : this.hash.substring('#🔐'.length).split(',');
|
||||
@@ -253,7 +247,6 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
[JSON.stringify(this.following), start_time, end_time, k_max_results]
|
||||
);
|
||||
} else {
|
||||
let t0 = new Date();
|
||||
let initial_messages = await tfrpc.rpc.query(
|
||||
`
|
||||
WITH
|
||||
@@ -279,12 +272,7 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
JSON.stringify(Object.keys(this.channels_latest)),
|
||||
]
|
||||
);
|
||||
let t1 = new Date();
|
||||
result = await this._fetch_related_messages(initial_messages);
|
||||
let t2 = new Date();
|
||||
console.log(
|
||||
`load of ${result.length} rows took ${(t2 - t0) / 1000} (${(t1 - t0) / 1000} to find ${initial_messages.length} initial messages, ${(t2 - t1) / 1000} to find ${result.length} total messages) following=${this.following.length} st=${start_time} et=${end_time}`
|
||||
);
|
||||
}
|
||||
this.time_loading = undefined;
|
||||
return result;
|
||||
@@ -407,9 +395,10 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
this._messages_hash = this.hash;
|
||||
}
|
||||
this._messages_following = JSON.stringify(this.following);
|
||||
this._private_messages =
|
||||
JSON.stringify(this.private_messages) +
|
||||
JSON.stringify(this.grouped_private_messages);
|
||||
this._private_messages = JSON.stringify([
|
||||
this.private_messages,
|
||||
this.grouped_private_messages,
|
||||
]);
|
||||
this._channels_latest = JSON.stringify(
|
||||
Object.keys(this.channels_latest ?? {})
|
||||
);
|
||||
@@ -487,13 +476,15 @@ class TfTabNewsFeedElement extends LitElement {
|
||||
this._messages_hash !== this.hash ||
|
||||
this._messages_following !== JSON.stringify(this.following) ||
|
||||
this._private_messages !==
|
||||
JSON.stringify(this.private_messages) +
|
||||
JSON.stringify(this.grouped_private_messages) ||
|
||||
JSON.stringify([
|
||||
this.private_messages,
|
||||
this.grouped_private_messages,
|
||||
]) ||
|
||||
this._channels_latest !==
|
||||
JSON.stringify(Object.keys(this.channels_latest))
|
||||
) {
|
||||
console.log(
|
||||
`loading messages for ${this.whoami} (following ${this.following.length})`
|
||||
`loading messages for ${this.whoami} (messages=${!this.messages},${this._messages_hash != this.hash} following=${this._messages_following !== JSON.stringify(this.following)}, channels=${this._channels_latest !== JSON.stringify(Object.keys(this.channels_latest))}, private=${this._private_messages !== JSON.stringify([this.private_messages, this.grouped_private_messages])},${this.private_messages?.length},${Object.keys(this.grouped_private_messages ?? {}).length})`
|
||||
);
|
||||
this.load_messages();
|
||||
}
|
||||
|
||||
@@ -75,6 +75,10 @@
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
}
|
||||
#code_of_conduct:has(>textarea:empty) {
|
||||
display: none;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<div style="display: flex; flex-direction: column; max-width: 1280px; margin: auto">
|
||||
<h1 ?hidden=${this.name}>Welcome.</h1>
|
||||
@@ -126,8 +130,10 @@
|
||||
There is currently no administrator. You will be made administrator.
|
||||
</div>
|
||||
|
||||
<h2>Code of Conduct</h2>
|
||||
<textarea readonly rows="20" cols="80" style="resize: none">${this.code_of_conduct}</textarea>
|
||||
<div id="code_of_conduct">
|
||||
<h2>Code of Conduct</h2>
|
||||
<textarea readonly rows="20" style="resize: none; width: 100%">${this.code_of_conduct}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ const k_api = {
|
||||
error: {args: ['error'], func: api_error},
|
||||
localStorageSet: {args: ['key', 'value'], func: api_localStorageSet},
|
||||
localStorageGet: {args: ['key'], func: api_localStorageGet},
|
||||
requestPermission: {args: ['permission', 'id'], func: api_requestPermission},
|
||||
requestPermission: {
|
||||
args: ['permission', 'id', 'description'],
|
||||
func: api_requestPermission,
|
||||
},
|
||||
print: {args: ['...'], func: api_print},
|
||||
setHash: {args: ['hash'], func: api_setHash},
|
||||
};
|
||||
@@ -369,16 +372,15 @@ class TfNavigationElement extends LitElement {
|
||||
>${this.version?.number}</span
|
||||
>
|
||||
<a
|
||||
class="w3-bar-item"
|
||||
class="w3-bar-item w3-button w3-text-white"
|
||||
accesskey="h"
|
||||
@mouseover=${set_access_key_title}
|
||||
data-tip="Open home app."
|
||||
href="/"
|
||||
style="color: #fff; white-space: nowrap"
|
||||
>TF</a
|
||||
>
|
||||
<a
|
||||
class="w3-bar-item"
|
||||
class="w3-bar-item w3-button w3-text-light-gray"
|
||||
accesskey="a"
|
||||
@mouseover=${set_access_key_title}
|
||||
data-tip="Open apps list."
|
||||
@@ -386,7 +388,7 @@ class TfNavigationElement extends LitElement {
|
||||
>apps</a
|
||||
>
|
||||
<a
|
||||
class="w3-bar-item"
|
||||
class="w3-bar-item w3-button w3-text-light-gray"
|
||||
accesskey="e"
|
||||
@mouseover=${set_access_key_title}
|
||||
data-tip="Toggle the app editor."
|
||||
@@ -395,7 +397,7 @@ class TfNavigationElement extends LitElement {
|
||||
>edit</a
|
||||
>
|
||||
<a
|
||||
class="w3-bar-item"
|
||||
class="w3-bar-item w3-button"
|
||||
accesskey="p"
|
||||
@mouseover=${set_access_key_title}
|
||||
data-tip="View and change permissions."
|
||||
@@ -1222,10 +1224,10 @@ function api_localStorageGet(key) {
|
||||
/**
|
||||
* Request a permission
|
||||
* @param permission The permission to request.
|
||||
* @param id The id requeesting the permission.
|
||||
* @param description An optional human-readable description of the action for which the permission is being requested.
|
||||
* @return A promise fulfilled if the permission was granted.
|
||||
*/
|
||||
function api_requestPermission(permission, id) {
|
||||
function api_requestPermission(permission, description) {
|
||||
let outer = document.createElement('div');
|
||||
outer.classList.add('permissions');
|
||||
|
||||
@@ -1242,6 +1244,18 @@ function api_requestPermission(permission, id) {
|
||||
div.appendChild(span);
|
||||
container.appendChild(div);
|
||||
|
||||
if (description) {
|
||||
container.appendChild(document.createTextNode('for the action:'));
|
||||
let description_div = document.createElement('div');
|
||||
description_div.classList.add('w3-border');
|
||||
description_div.classList.add('w3-padding');
|
||||
description_div.style.backgroundColor = '#666';
|
||||
description_div.style.maxHeight = '3em';
|
||||
description_div.style.overflow = 'auto';
|
||||
description_div.appendChild(document.createTextNode(description));
|
||||
container.appendChild(description_div);
|
||||
}
|
||||
|
||||
div = document.createElement('div');
|
||||
div.style = 'padding: 1em';
|
||||
let check = document.createElement('input');
|
||||
|
||||
67
core/core.js
67
core/core.js
@@ -17,6 +17,8 @@ let gProcesses = {};
|
||||
let gStatsTimer = false;
|
||||
/** Effectively a process ID. */
|
||||
let g_handler_index = 0;
|
||||
/** Whether updating accounts information is currently scheduled. */
|
||||
let g_update_accounts_scheduled;
|
||||
/** Time between pings, in milliseconds. */
|
||||
const k_ping_interval = 60 * 1000;
|
||||
|
||||
@@ -212,7 +214,7 @@ async function getProcessBlob(blobId, key, options) {
|
||||
return settings.userPermissions[user];
|
||||
}
|
||||
},
|
||||
permissionTest: async function (permission) {
|
||||
permissionTest: async function (permission, description) {
|
||||
let user = process?.credentials?.session?.name;
|
||||
let settings = await loadSettings();
|
||||
if (!user || !options?.packageOwner || !options?.packageName) {
|
||||
@@ -239,7 +241,7 @@ async function getProcessBlob(blobId, key, options) {
|
||||
}
|
||||
} else if (process.app) {
|
||||
return process.app
|
||||
.makeFunction(['requestPermission'])(permission)
|
||||
.makeFunction(['requestPermission'])(permission, description)
|
||||
.then(async function (value) {
|
||||
if (value == 'allow') {
|
||||
await ssb.setUserPermission(
|
||||
@@ -275,18 +277,23 @@ async function getProcessBlob(blobId, key, options) {
|
||||
},
|
||||
};
|
||||
process.sendIdentities = async function () {
|
||||
process.app.send(
|
||||
Object.assign(
|
||||
{
|
||||
action: 'identities',
|
||||
},
|
||||
await ssb_internal.getIdentityInfo(
|
||||
process?.credentials?.session?.name,
|
||||
options?.packageOwner,
|
||||
options?.packageName
|
||||
)
|
||||
)
|
||||
let identities = await ssb_internal.getIdentityInfo(
|
||||
process?.credentials?.session?.name,
|
||||
options?.packageOwner,
|
||||
options?.packageName
|
||||
);
|
||||
let json = JSON.stringify(identities);
|
||||
if (process._last_sent_identities !== json) {
|
||||
process.app.send(
|
||||
Object.assign(
|
||||
{
|
||||
action: 'identities',
|
||||
},
|
||||
identities
|
||||
)
|
||||
);
|
||||
process._last_sent_identities = json;
|
||||
}
|
||||
};
|
||||
process.setActiveIdentity = async function (identity) {
|
||||
if (
|
||||
@@ -337,7 +344,10 @@ async function getProcessBlob(blobId, key, options) {
|
||||
};
|
||||
if (process.credentials?.permissions?.administration) {
|
||||
imports.core.globalSettingsSet = async function (key, value) {
|
||||
await imports.core.permissionTest('set_global_setting');
|
||||
await imports.core.permissionTest(
|
||||
'set_global_setting',
|
||||
`Set ${JSON.stringify(key)} to ${JSON.stringify(value)}.`
|
||||
);
|
||||
print('Setting', key, value);
|
||||
let settings = await loadSettings();
|
||||
settings[key] = value;
|
||||
@@ -436,8 +446,18 @@ async function getProcessBlob(blobId, key, options) {
|
||||
process.credentials.session &&
|
||||
process.credentials.session.name
|
||||
) {
|
||||
let action;
|
||||
try {
|
||||
if (message?.type === 'vote' && message?.vote?.expression) {
|
||||
action = `React with ${message?.vote?.expression}.`;
|
||||
} else if (typeof message === 'string') {
|
||||
action = `Post a private message.`;
|
||||
} else {
|
||||
action = `Publish ${'aeiou'.indexOf(message?.type?.toLowerCase()?.substring(0, 1)) != -1 ? 'an' : 'a'} "${message?.type}" message.`;
|
||||
}
|
||||
} catch {}
|
||||
return Promise.resolve(
|
||||
imports.core.permissionTest('ssb_append')
|
||||
imports.core.permissionTest('ssb_append', action)
|
||||
).then(function () {
|
||||
return ssb.appendMessageWithIdentity(
|
||||
process.credentials.session.name,
|
||||
@@ -611,11 +631,28 @@ async function getProcessBlob(blobId, key, options) {
|
||||
return process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send any changed account information.
|
||||
*/
|
||||
function updateAccounts() {
|
||||
g_update_accounts_scheduled = false;
|
||||
let promises = [];
|
||||
for (let process of Object.values(gProcesses)) {
|
||||
promises.push(process.sendIdentities());
|
||||
}
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* SSB message added callback.
|
||||
*/
|
||||
ssb_internal.addEventListener('message', function () {
|
||||
broadcastEvent('onMessage', [...arguments]);
|
||||
|
||||
if (!g_update_accounts_scheduled) {
|
||||
setTimeout(updateAccounts, 1000);
|
||||
g_update_accounts_scheduled = true;
|
||||
}
|
||||
});
|
||||
|
||||
ssb_internal.addEventListener('blob', function () {
|
||||
|
||||
67
core/eula.html
Normal file
67
core/eula.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Tilde Friends Usage Agreement</title>
|
||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</head>
|
||||
<body class="w3-container">
|
||||
<h1>Tilde Friends Usage Agreement</h1>
|
||||
<p>
|
||||
Tilde Friends is an app that enables communication with other users
|
||||
through the
|
||||
<a href="https://ssbc.github.io/scuttlebutt-protocol-guide/"
|
||||
>Secure Scuttlebutt</a
|
||||
>
|
||||
protocol.
|
||||
</p>
|
||||
<h2>Your actions are your responsibility</h2>
|
||||
<p>
|
||||
Apple tolerates no objectionable content or abusive users on their
|
||||
platforms.
|
||||
</p>
|
||||
<p>
|
||||
You are responsible for your own actions within this app. You are
|
||||
responsible for complying with all applicable rules and laws.
|
||||
</p>
|
||||
<h2>You choose what you see</h2>
|
||||
<p>
|
||||
You are in full control of the content you see in Tilde Friends. The peers
|
||||
to which you choose to connect and the users you choose to follow directly
|
||||
determine the content presented to you. Initially you will be following no
|
||||
one with no connections and as a result see no user-generated content.
|
||||
</p>
|
||||
<p>
|
||||
If you encounter objectionable content, you can filter it from your view
|
||||
by blocking the user who posted it. This also makes it so that users
|
||||
following you will not see it as a consequence of following you.
|
||||
</p>
|
||||
<p>
|
||||
The <code>admin</code> app contains a variety of settings that control the
|
||||
types of connections Tilde Friends will make or accept, including whether
|
||||
the app will even accept or make connections at all.
|
||||
</p>
|
||||
<h2>This app is not a service</h2>
|
||||
<p>
|
||||
Tilde Friends is an app. It relies on no servers. The author of this app
|
||||
has no more ability to see or filter what you post or read than any other
|
||||
user of the network.
|
||||
</p>
|
||||
<p>
|
||||
If you believe objectionable content obtained from a service that is
|
||||
running as part of the Secure Scuttlebutt network should be flagged,
|
||||
report it to the operator of the service, generally by contacting the
|
||||
email address listed when visiting the server address in a web browser.
|
||||
</p>
|
||||
<h2>Agreement</h2>
|
||||
<p>
|
||||
If you do not accept these terms, do not use this app. You may close and
|
||||
delete it now.
|
||||
</p>
|
||||
<div class="w3-center w3-margin">
|
||||
<a class="w3-button w3-blue w3-round-large" href="/eula/accept"
|
||||
>Accept Agreement</a
|
||||
>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,7 +5,10 @@
|
||||
<link type="text/css" rel="stylesheet" href="/static/style.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/static/w3.css" />
|
||||
<link type="image/svg+xml" rel="icon" href="/static/tildefriends.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1"
|
||||
/>
|
||||
<meta
|
||||
name="title"
|
||||
content="Tilde Friends - Make friends and apps from your web browser."
|
||||
|
||||
@@ -152,4 +152,5 @@ body {
|
||||
border-bottom: 4px solid #fff;
|
||||
padding: 1em;
|
||||
margin: 0 auto;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
2
deps/codemirror/cm6.js
vendored
2
deps/codemirror/cm6.js
vendored
File diff suppressed because one or more lines are too long
212
deps/codemirror_src/package-lock.json
generated
vendored
212
deps/codemirror_src/package-lock.json
generated
vendored
@@ -112,9 +112,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/lint": {
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.1.tgz",
|
||||
"integrity": "sha512-te7To1EQHePBQQzasDKWmK2xKINIXpk+xAiSYr9ZN+VB4KaT+/Hi2PEkeErTk5BV3PTz1TLyQL4MtJfPkKZ9sw==",
|
||||
"version": "6.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz",
|
||||
"integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.0.0",
|
||||
@@ -155,9 +155,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/view": {
|
||||
"version": "6.38.6",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.6.tgz",
|
||||
"integrity": "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==",
|
||||
"version": "6.38.8",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.8.tgz",
|
||||
"integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.5.0",
|
||||
@@ -234,9 +234,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/highlight": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.2.tgz",
|
||||
"integrity": "sha512-z8TQwaBXXQIvG6i2g3e9cgMwUUXu9Ib7jo2qRRggdhwKpM56Dw3PM3wmexn+EGaaOZ7az0K7sjc3/gcGW7sz7A==",
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
||||
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.3.0"
|
||||
@@ -276,9 +276,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@lezer/lr": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.3.tgz",
|
||||
"integrity": "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@lezer/common": "^1.0.0"
|
||||
@@ -360,9 +360,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz",
|
||||
"integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
|
||||
"integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -373,9 +373,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
|
||||
"integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -386,9 +386,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
|
||||
"integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -399,9 +399,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz",
|
||||
"integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
|
||||
"integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -412,9 +412,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
|
||||
"integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -425,9 +425,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz",
|
||||
"integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
|
||||
"integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -438,9 +438,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz",
|
||||
"integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
|
||||
"integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -451,9 +451,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz",
|
||||
"integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
|
||||
"integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -464,9 +464,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -477,9 +477,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz",
|
||||
"integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
|
||||
"integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -490,9 +490,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -503,9 +503,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -516,9 +516,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -529,9 +529,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz",
|
||||
"integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
|
||||
"integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -542,9 +542,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -555,9 +555,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -568,9 +568,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz",
|
||||
"integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
|
||||
"integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -581,9 +581,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz",
|
||||
"integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
|
||||
"integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -594,9 +594,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz",
|
||||
"integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
|
||||
"integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -607,9 +607,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz",
|
||||
"integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
|
||||
"integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -620,9 +620,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz",
|
||||
"integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
|
||||
"integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -633,9 +633,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz",
|
||||
"integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
|
||||
"integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -825,9 +825,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.52.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz",
|
||||
"integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
|
||||
"version": "4.53.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
|
||||
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
@@ -840,28 +840,28 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.52.5",
|
||||
"@rollup/rollup-android-arm64": "4.52.5",
|
||||
"@rollup/rollup-darwin-arm64": "4.52.5",
|
||||
"@rollup/rollup-darwin-x64": "4.52.5",
|
||||
"@rollup/rollup-freebsd-arm64": "4.52.5",
|
||||
"@rollup/rollup-freebsd-x64": "4.52.5",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.52.5",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.52.5",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.52.5",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.52.5",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.52.5",
|
||||
"@rollup/rollup-linux-x64-musl": "4.52.5",
|
||||
"@rollup/rollup-openharmony-arm64": "4.52.5",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.52.5",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.52.5",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.52.5",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.52.5",
|
||||
"@rollup/rollup-android-arm-eabi": "4.53.3",
|
||||
"@rollup/rollup-android-arm64": "4.53.3",
|
||||
"@rollup/rollup-darwin-arm64": "4.53.3",
|
||||
"@rollup/rollup-darwin-x64": "4.53.3",
|
||||
"@rollup/rollup-freebsd-arm64": "4.53.3",
|
||||
"@rollup/rollup-freebsd-x64": "4.53.3",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.53.3",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.53.3",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.53.3",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.53.3",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.53.3",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.53.3",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.53.3",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.53.3",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.53.3",
|
||||
"@rollup/rollup-linux-x64-musl": "4.53.3",
|
||||
"@rollup/rollup-openharmony-arm64": "4.53.3",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.53.3",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.53.3",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.53.3",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.53.3",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -943,9 +943,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz",
|
||||
"integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==",
|
||||
"version": "5.44.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
|
||||
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
|
||||
2
deps/libbacktrace
vendored
2
deps/libbacktrace
vendored
Submodule deps/libbacktrace updated: 2f67a3abfd...b9e40069c0
2529
deps/sqlite/shell.c
vendored
2529
deps/sqlite/shell.c
vendored
File diff suppressed because it is too large
Load Diff
5679
deps/sqlite/sqlite3.c
vendored
5679
deps/sqlite/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
413
deps/sqlite/sqlite3.h
vendored
413
deps/sqlite/sqlite3.h
vendored
@@ -146,9 +146,12 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.50.4"
|
||||
#define SQLITE_VERSION_NUMBER 3050004
|
||||
#define SQLITE_SOURCE_ID "2025-07-30 19:33:53 4d8adfb30e03f9cf27f800a2c1ba3c48fb4ca1b08b0f5ed59a4d5ecbf45e20a3"
|
||||
#define SQLITE_VERSION "3.51.0"
|
||||
#define SQLITE_VERSION_NUMBER 3051000
|
||||
#define SQLITE_SOURCE_ID "2025-11-04 19:38:17 fb2c931ae597f8d00a37574ff67aeed3eced4e5547f9120744ae4bfa8e74527b"
|
||||
#define SQLITE_SCM_BRANCH "trunk"
|
||||
#define SQLITE_SCM_TAGS "release major-release version-3.51.0"
|
||||
#define SQLITE_SCM_DATETIME "2025-11-04T19:38:17.314Z"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -168,9 +171,9 @@ extern "C" {
|
||||
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
|
||||
** </pre></blockquote>)^
|
||||
**
|
||||
** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION]
|
||||
** macro. ^The sqlite3_libversion() function returns a pointer to the
|
||||
** to the sqlite3_version[] string constant. The sqlite3_libversion()
|
||||
** ^The sqlite3_version[] string constant contains the text of the
|
||||
** [SQLITE_VERSION] macro. ^The sqlite3_libversion() function returns a
|
||||
** pointer to the sqlite3_version[] string constant. The sqlite3_libversion()
|
||||
** function is provided for use in DLLs since DLL users usually do not have
|
||||
** direct access to string constants within the DLL. ^The
|
||||
** sqlite3_libversion_number() function returns an integer equal to
|
||||
@@ -370,7 +373,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
** without having to use a lot of C code.
|
||||
**
|
||||
** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
|
||||
** semicolon-separate SQL statements passed into its 2nd argument,
|
||||
** semicolon-separated SQL statements passed into its 2nd argument,
|
||||
** in the context of the [database connection] passed in as its 1st
|
||||
** argument. ^If the callback function of the 3rd argument to
|
||||
** sqlite3_exec() is not NULL, then it is invoked for each result row
|
||||
@@ -403,7 +406,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
** result row is NULL then the corresponding string pointer for the
|
||||
** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the
|
||||
** sqlite3_exec() callback is an array of pointers to strings where each
|
||||
** entry represents the name of corresponding result column as obtained
|
||||
** entry represents the name of a corresponding result column as obtained
|
||||
** from [sqlite3_column_name()].
|
||||
**
|
||||
** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
|
||||
@@ -497,6 +500,9 @@ SQLITE_API int sqlite3_exec(
|
||||
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8))
|
||||
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8))
|
||||
#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8))
|
||||
#define SQLITE_ERROR_RESERVESIZE (SQLITE_ERROR | (4<<8))
|
||||
#define SQLITE_ERROR_KEY (SQLITE_ERROR | (5<<8))
|
||||
#define SQLITE_ERROR_UNABLE (SQLITE_ERROR | (6<<8))
|
||||
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
|
||||
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
|
||||
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
|
||||
@@ -531,6 +537,8 @@ SQLITE_API int sqlite3_exec(
|
||||
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
|
||||
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
|
||||
#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
|
||||
#define SQLITE_IOERR_BADKEY (SQLITE_IOERR | (35<<8))
|
||||
#define SQLITE_IOERR_CODEC (SQLITE_IOERR | (36<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
||||
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
@@ -589,7 +597,7 @@ SQLITE_API int sqlite3_exec(
|
||||
** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into
|
||||
** [sqlite3_open_v2()] does *not* cause the underlying database file
|
||||
** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into
|
||||
** [sqlite3_open_v2()] has historically be a no-op and might become an
|
||||
** [sqlite3_open_v2()] has historically been a no-op and might become an
|
||||
** error in future versions of SQLite.
|
||||
*/
|
||||
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||
@@ -683,7 +691,7 @@ SQLITE_API int sqlite3_exec(
|
||||
** SQLite uses one of these integer values as the second
|
||||
** argument to calls it makes to the xLock() and xUnlock() methods
|
||||
** of an [sqlite3_io_methods] object. These values are ordered from
|
||||
** lest restrictive to most restrictive.
|
||||
** least restrictive to most restrictive.
|
||||
**
|
||||
** The argument to xLock() is always SHARED or higher. The argument to
|
||||
** xUnlock is either SHARED or NONE.
|
||||
@@ -924,7 +932,7 @@ struct sqlite3_io_methods {
|
||||
** connection. See also [SQLITE_FCNTL_FILE_POINTER].
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
|
||||
** No longer in use.
|
||||
** The SQLITE_FCNTL_SYNC_OMITTED file-control is no longer used.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_SYNC]]
|
||||
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
|
||||
@@ -999,7 +1007,7 @@ struct sqlite3_io_methods {
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_VFSNAME]]
|
||||
** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
|
||||
** all [VFSes] in the VFS stack. The names are of all VFS shims and the
|
||||
** all [VFSes] in the VFS stack. The names of all VFS shims and the
|
||||
** final bottom-level VFS are written into memory obtained from
|
||||
** [sqlite3_malloc()] and the result is stored in the char* variable
|
||||
** that the fourth parameter of [sqlite3_file_control()] points to.
|
||||
@@ -1013,7 +1021,7 @@ struct sqlite3_io_methods {
|
||||
** ^The [SQLITE_FCNTL_VFS_POINTER] opcode finds a pointer to the top-level
|
||||
** [VFSes] currently in use. ^(The argument X in
|
||||
** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be
|
||||
** of type "[sqlite3_vfs] **". This opcodes will set *X
|
||||
** of type "[sqlite3_vfs] **". This opcode will set *X
|
||||
** to a pointer to the top-level VFS.)^
|
||||
** ^When there are multiple VFS shims in the stack, this opcode finds the
|
||||
** upper-most shim only.
|
||||
@@ -1203,7 +1211,7 @@ struct sqlite3_io_methods {
|
||||
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
|
||||
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
|
||||
** whether or not there is a database client in another process with a wal-mode
|
||||
** transaction open on the database or not. It is only available on unix.The
|
||||
** transaction open on the database or not. It is only available on unix. The
|
||||
** (void*) argument passed with this file-control should be a pointer to a
|
||||
** value of type (int). The integer value is set to 1 if the database is a wal
|
||||
** mode database and there exists at least one client in another process that
|
||||
@@ -1221,6 +1229,15 @@ struct sqlite3_io_methods {
|
||||
** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
|
||||
** purges the contents of the in-memory page cache. If there is an open
|
||||
** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_FILESTAT]]
|
||||
** The [SQLITE_FCNTL_FILESTAT] opcode returns low-level diagnostic information
|
||||
** about the [sqlite3_file] objects used access the database and journal files
|
||||
** for the given schema. The fourth parameter to [sqlite3_file_control()]
|
||||
** should be an initialized [sqlite3_str] pointer. JSON text describing
|
||||
** various aspects of the sqlite3_file object is appended to the sqlite3_str.
|
||||
** The SQLITE_FCNTL_FILESTAT opcode is usually a no-op, unless compile-time
|
||||
** options are used to enable it.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@@ -1266,6 +1283,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_RESET_CACHE 42
|
||||
#define SQLITE_FCNTL_NULL_IO 43
|
||||
#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
|
||||
#define SQLITE_FCNTL_FILESTAT 45
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -1628,7 +1646,7 @@ struct sqlite3_vfs {
|
||||
** SQLite interfaces so that an application usually does not need to
|
||||
** invoke sqlite3_initialize() directly. For example, [sqlite3_open()]
|
||||
** calls sqlite3_initialize() so the SQLite library will be automatically
|
||||
** initialized when [sqlite3_open()] is called if it has not be initialized
|
||||
** initialized when [sqlite3_open()] is called if it has not been initialized
|
||||
** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT]
|
||||
** compile-time option, then the automatic calls to sqlite3_initialize()
|
||||
** are omitted and the application must call sqlite3_initialize() directly
|
||||
@@ -1885,21 +1903,21 @@ struct sqlite3_mem_methods {
|
||||
** The [sqlite3_mem_methods]
|
||||
** structure is filled with the currently defined memory allocation routines.)^
|
||||
** This option can be used to overload the default memory allocation
|
||||
** routines with a wrapper that simulations memory allocation failure or
|
||||
** routines with a wrapper that simulates memory allocation failure or
|
||||
** tracks memory usage, for example. </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_SMALL_MALLOC]] <dt>SQLITE_CONFIG_SMALL_MALLOC</dt>
|
||||
** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes single argument of
|
||||
** <dd> ^The SQLITE_CONFIG_SMALL_MALLOC option takes a single argument of
|
||||
** type int, interpreted as a boolean, which if true provides a hint to
|
||||
** SQLite that it should avoid large memory allocations if possible.
|
||||
** SQLite will run faster if it is free to make large memory allocations,
|
||||
** but some application might prefer to run slower in exchange for
|
||||
** but some applications might prefer to run slower in exchange for
|
||||
** guarantees about memory fragmentation that are possible if large
|
||||
** allocations are avoided. This hint is normally off.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
|
||||
** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
|
||||
** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes a single argument of type int,
|
||||
** interpreted as a boolean, which enables or disables the collection of
|
||||
** memory allocation statistics. ^(When memory allocation statistics are
|
||||
** disabled, the following SQLite interfaces become non-operational:
|
||||
@@ -1944,7 +1962,7 @@ struct sqlite3_mem_methods {
|
||||
** ^If pMem is NULL and N is non-zero, then each database connection
|
||||
** does an initial bulk allocation for page cache memory
|
||||
** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or
|
||||
** of -1024*N bytes if N is negative, . ^If additional
|
||||
** of -1024*N bytes if N is negative. ^If additional
|
||||
** page cache memory is needed beyond what is provided by the initial
|
||||
** allocation, then SQLite goes to [sqlite3_malloc()] separately for each
|
||||
** additional cache line. </dd>
|
||||
@@ -1973,7 +1991,7 @@ struct sqlite3_mem_methods {
|
||||
** <dd> ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a
|
||||
** pointer to an instance of the [sqlite3_mutex_methods] structure.
|
||||
** The argument specifies alternative low-level mutex routines to be used
|
||||
** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of
|
||||
** in place of the mutex routines built into SQLite.)^ ^SQLite makes a copy of
|
||||
** the content of the [sqlite3_mutex_methods] structure before the call to
|
||||
** [sqlite3_config()] returns. ^If SQLite is compiled with
|
||||
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
|
||||
@@ -2015,7 +2033,7 @@ struct sqlite3_mem_methods {
|
||||
**
|
||||
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
|
||||
** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which
|
||||
** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of
|
||||
** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies off
|
||||
** the current page cache implementation into that object.)^ </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
|
||||
@@ -2032,7 +2050,7 @@ struct sqlite3_mem_methods {
|
||||
** the logger function is a copy of the first parameter to the corresponding
|
||||
** [sqlite3_log()] call and is intended to be a [result code] or an
|
||||
** [extended result code]. ^The third parameter passed to the logger is
|
||||
** log message after formatting via [sqlite3_snprintf()].
|
||||
** a log message after formatting via [sqlite3_snprintf()].
|
||||
** The SQLite logging interface is not reentrant; the logger function
|
||||
** supplied by the application must not invoke any SQLite interface.
|
||||
** In a multi-threaded application, the application-defined logger
|
||||
@@ -2223,7 +2241,7 @@ struct sqlite3_mem_methods {
|
||||
** These constants are the available integer configuration options that
|
||||
** can be passed as the second parameter to the [sqlite3_db_config()] interface.
|
||||
**
|
||||
** The [sqlite3_db_config()] interface is a var-args functions. It takes a
|
||||
** The [sqlite3_db_config()] interface is a var-args function. It takes a
|
||||
** variable number of parameters, though always at least two. The number of
|
||||
** parameters passed into sqlite3_db_config() depends on which of these
|
||||
** constants is given as the second parameter. This documentation page
|
||||
@@ -2335,17 +2353,20 @@ struct sqlite3_mem_methods {
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
|
||||
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
|
||||
** <dd> ^This option is used to enable or disable the
|
||||
** [fts3_tokenizer()] function which is part of the
|
||||
** [FTS3] full-text search engine extension.
|
||||
** There must be two additional arguments.
|
||||
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
|
||||
** positive to enable fts3_tokenizer() or negative to leave the setting
|
||||
** unchanged.
|
||||
** The second parameter is a pointer to an integer into which
|
||||
** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
|
||||
** following this call. The second parameter may be a NULL pointer, in
|
||||
** which case the new setting is not reported back. </dd>
|
||||
** <dd> ^This option is used to enable or disable using the
|
||||
** [fts3_tokenizer()] function - part of the [FTS3] full-text search engine
|
||||
** extension - without using bound parameters as the parameters. Doing so
|
||||
** is disabled by default. There must be two additional arguments. The first
|
||||
** argument is an integer. If it is passed 0, then using fts3_tokenizer()
|
||||
** without bound parameters is disabled. If it is passed a positive value,
|
||||
** then calling fts3_tokenizer without bound parameters is enabled. If it
|
||||
** is passed a negative value, this setting is not modified - this can be
|
||||
** used to query for the current setting. The second parameter is a pointer
|
||||
** to an integer into which is written 0 or 1 to indicate the current value
|
||||
** of this setting (after it is modified, if applicable). The second
|
||||
** parameter may be a NULL pointer, in which case the value of the setting
|
||||
** is not reported back. Refer to [FTS3] documentation for further details.
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION]]
|
||||
** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
|
||||
@@ -2357,8 +2378,8 @@ struct sqlite3_mem_methods {
|
||||
** When the first argument to this interface is 1, then only the C-API is
|
||||
** enabled and the SQL function remains disabled. If the first argument to
|
||||
** this interface is 0, then both the C-API and the SQL function are disabled.
|
||||
** If the first argument is -1, then no changes are made to state of either the
|
||||
** C-API or the SQL function.
|
||||
** If the first argument is -1, then no changes are made to the state of either
|
||||
** the C-API or the SQL function.
|
||||
** The second parameter is a pointer to an integer into which
|
||||
** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
|
||||
** is disabled or enabled following this call. The second parameter may
|
||||
@@ -2476,7 +2497,7 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_DBCONFIG_LEGACY_ALTER_TABLE]]
|
||||
** <dt>SQLITE_DBCONFIG_LEGACY_ALTER_TABLE</dt>
|
||||
** <dd>The SQLITE_DBCONFIG_LEGACY_ALTER_TABLE option activates or deactivates
|
||||
** the legacy behavior of the [ALTER TABLE RENAME] command such it
|
||||
** the legacy behavior of the [ALTER TABLE RENAME] command such that it
|
||||
** behaves as it did prior to [version 3.24.0] (2018-06-04). See the
|
||||
** "Compatibility Notice" on the [ALTER TABLE RENAME documentation] for
|
||||
** additional information. This feature can also be turned on and off
|
||||
@@ -2525,7 +2546,7 @@ struct sqlite3_mem_methods {
|
||||
** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
|
||||
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
|
||||
** the legacy file format flag. When activated, this flag causes all newly
|
||||
** created database file to have a schema format version number (the 4-byte
|
||||
** created database files to have a schema format version number (the 4-byte
|
||||
** integer found at offset 44 into the database header) of 1. This in turn
|
||||
** means that the resulting database file will be readable and writable by
|
||||
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
|
||||
@@ -2552,7 +2573,7 @@ struct sqlite3_mem_methods {
|
||||
** the database handle both when the SQL statement is prepared and when it
|
||||
** is stepped. The flag is set (collection of statistics is enabled)
|
||||
** by default. <p>This option takes two arguments: an integer and a pointer to
|
||||
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
|
||||
** an integer. The first argument is 1, 0, or -1 to enable, disable, or
|
||||
** leave unchanged the statement scanstatus option. If the second argument
|
||||
** is not NULL, then the value of the statement scanstatus setting after
|
||||
** processing the first argument is written into the integer that the second
|
||||
@@ -2595,8 +2616,8 @@ struct sqlite3_mem_methods {
|
||||
** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the
|
||||
** ability of the [ATTACH DATABASE] SQL command to open a database for writing.
|
||||
** This capability is enabled by default. Applications can disable or
|
||||
** reenable this capability using the current DBCONFIG option. If the
|
||||
** the this capability is disabled, the [ATTACH] command will still work,
|
||||
** reenable this capability using the current DBCONFIG option. If
|
||||
** this capability is disabled, the [ATTACH] command will still work,
|
||||
** but the database will be opened read-only. If this option is disabled,
|
||||
** then the ability to create a new database using [ATTACH] is also disabled,
|
||||
** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]
|
||||
@@ -2630,7 +2651,7 @@ struct sqlite3_mem_methods {
|
||||
**
|
||||
** <p>Most of the SQLITE_DBCONFIG options take two arguments, so that the
|
||||
** overall call to [sqlite3_db_config()] has a total of four parameters.
|
||||
** The first argument (the third parameter to sqlite3_db_config()) is a integer.
|
||||
** The first argument (the third parameter to sqlite3_db_config()) is an integer.
|
||||
** The second argument is a pointer to an integer. If the first argument is 1,
|
||||
** then the option becomes enabled. If the first integer argument is 0, then the
|
||||
** option is disabled. If the first argument is -1, then the option setting
|
||||
@@ -2920,7 +2941,7 @@ SQLITE_API int sqlite3_is_interrupted(sqlite3*);
|
||||
** ^These routines return 0 if the statement is incomplete. ^If a
|
||||
** memory allocation fails, then SQLITE_NOMEM is returned.
|
||||
**
|
||||
** ^These routines do not parse the SQL statements thus
|
||||
** ^These routines do not parse the SQL statements and thus
|
||||
** will not detect syntactically incorrect SQL.
|
||||
**
|
||||
** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
|
||||
@@ -3037,7 +3058,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
|
||||
** indefinitely if possible. The results of passing any other negative value
|
||||
** are undefined.
|
||||
**
|
||||
** Internally, each SQLite database handle store two timeout values - the
|
||||
** Internally, each SQLite database handle stores two timeout values - the
|
||||
** busy-timeout (used for rollback mode databases, or if the VFS does not
|
||||
** support blocking locks) and the setlk-timeout (used for blocking locks
|
||||
** on wal-mode databases). The sqlite3_busy_timeout() method sets both
|
||||
@@ -3067,7 +3088,7 @@ SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
|
||||
** This is a legacy interface that is preserved for backwards compatibility.
|
||||
** Use of this interface is not recommended.
|
||||
**
|
||||
** Definition: A <b>result table</b> is memory data structure created by the
|
||||
** Definition: A <b>result table</b> is a memory data structure created by the
|
||||
** [sqlite3_get_table()] interface. A result table records the
|
||||
** complete query results from one or more queries.
|
||||
**
|
||||
@@ -3210,7 +3231,7 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
||||
** ^Calling sqlite3_free() with a pointer previously returned
|
||||
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
|
||||
** that it might be reused. ^The sqlite3_free() routine is
|
||||
** a no-op if is called with a NULL pointer. Passing a NULL pointer
|
||||
** a no-op if it is called with a NULL pointer. Passing a NULL pointer
|
||||
** to sqlite3_free() is harmless. After being freed, memory
|
||||
** should neither be read nor written. Even reading previously freed
|
||||
** memory might result in a segmentation fault or other severe error.
|
||||
@@ -3228,13 +3249,13 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
||||
** sqlite3_free(X).
|
||||
** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
|
||||
** of at least N bytes in size or NULL if insufficient memory is available.
|
||||
** ^If M is the size of the prior allocation, then min(N,M) bytes
|
||||
** of the prior allocation are copied into the beginning of buffer returned
|
||||
** ^If M is the size of the prior allocation, then min(N,M) bytes of the
|
||||
** prior allocation are copied into the beginning of the buffer returned
|
||||
** by sqlite3_realloc(X,N) and the prior allocation is freed.
|
||||
** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
|
||||
** prior allocation is not freed.
|
||||
**
|
||||
** ^The sqlite3_realloc64(X,N) interfaces works the same as
|
||||
** ^The sqlite3_realloc64(X,N) interface works the same as
|
||||
** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead
|
||||
** of a 32-bit signed integer.
|
||||
**
|
||||
@@ -3284,7 +3305,7 @@ SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
|
||||
** was last reset. ^The values returned by [sqlite3_memory_used()] and
|
||||
** [sqlite3_memory_highwater()] include any overhead
|
||||
** added by SQLite in its implementation of [sqlite3_malloc()],
|
||||
** but not overhead added by the any underlying system library
|
||||
** but not overhead added by any underlying system library
|
||||
** routines that [sqlite3_malloc()] may call.
|
||||
**
|
||||
** ^The memory high-water mark is reset to the current value of
|
||||
@@ -3736,7 +3757,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** there is no harm in trying.)
|
||||
**
|
||||
** ^(<dt>[SQLITE_OPEN_SHAREDCACHE]</dt>
|
||||
** <dd>The database is opened [shared cache] enabled, overriding
|
||||
** <dd>The database is opened with [shared cache] enabled, overriding
|
||||
** the default shared cache setting provided by
|
||||
** [sqlite3_enable_shared_cache()].)^
|
||||
** The [use of shared cache mode is discouraged] and hence shared cache
|
||||
@@ -3744,7 +3765,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
||||
** this option is a no-op.
|
||||
**
|
||||
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
|
||||
** <dd>The database is opened [shared cache] disabled, overriding
|
||||
** <dd>The database is opened with [shared cache] disabled, overriding
|
||||
** the default shared cache setting provided by
|
||||
** [sqlite3_enable_shared_cache()].)^
|
||||
**
|
||||
@@ -4162,7 +4183,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename);
|
||||
** subsequent calls to other SQLite interface functions.)^
|
||||
**
|
||||
** ^The sqlite3_errstr(E) interface returns the English-language text
|
||||
** that describes the [result code] E, as UTF-8, or NULL if E is not an
|
||||
** that describes the [result code] E, as UTF-8, or NULL if E is not a
|
||||
** result code for which a text error message is available.
|
||||
** ^(Memory to hold the error message string is managed internally
|
||||
** and must not be freed by the application)^.
|
||||
@@ -4170,7 +4191,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename);
|
||||
** ^If the most recent error references a specific token in the input
|
||||
** SQL, the sqlite3_error_offset() interface returns the byte offset
|
||||
** of the start of that token. ^The byte offset returned by
|
||||
** sqlite3_error_offset() assumes that the input SQL is UTF8.
|
||||
** sqlite3_error_offset() assumes that the input SQL is UTF-8.
|
||||
** ^If the most recent error does not reference a specific token in the input
|
||||
** SQL, then the sqlite3_error_offset() function returns -1.
|
||||
**
|
||||
@@ -4195,6 +4216,34 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
|
||||
SQLITE_API const char *sqlite3_errstr(int);
|
||||
SQLITE_API int sqlite3_error_offset(sqlite3 *db);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Set Error Codes And Message
|
||||
** METHOD: sqlite3
|
||||
**
|
||||
** Set the error code of the database handle passed as the first argument
|
||||
** to errcode, and the error message to a copy of nul-terminated string
|
||||
** zErrMsg. If zErrMsg is passed NULL, then the error message is set to
|
||||
** the default message associated with the supplied error code. Subsequent
|
||||
** calls to [sqlite3_errcode()] and [sqlite3_errmsg()] and similar will
|
||||
** return the values set by this routine in place of what was previously
|
||||
** set by SQLite itself.
|
||||
**
|
||||
** This function returns SQLITE_OK if the error code and error message are
|
||||
** successfully set, SQLITE_NOMEM if an OOM occurs, and SQLITE_MISUSE if
|
||||
** the database handle is NULL or invalid.
|
||||
**
|
||||
** The error code and message set by this routine remains in effect until
|
||||
** they are changed, either by another call to this routine or until they are
|
||||
** changed to by SQLite itself to reflect the result of some subsquent
|
||||
** API call.
|
||||
**
|
||||
** This function is intended for use by SQLite extensions or wrappers. The
|
||||
** idea is that an extension or wrapper can use this routine to set error
|
||||
** messages and error codes and thus behave more like a core SQLite
|
||||
** feature from the point of view of an application.
|
||||
*/
|
||||
SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zErrMsg);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Prepared Statement Object
|
||||
** KEYWORDS: {prepared statement} {prepared statements}
|
||||
@@ -4269,8 +4318,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
**
|
||||
** These constants define various performance limits
|
||||
** that can be lowered at run-time using [sqlite3_limit()].
|
||||
** The synopsis of the meanings of the various limits is shown below.
|
||||
** Additional information is available at [limits | Limits in SQLite].
|
||||
** A concise description of these limits follows, and additional information
|
||||
** is available at [limits | Limits in SQLite].
|
||||
**
|
||||
** <dl>
|
||||
** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt>
|
||||
@@ -4335,7 +4384,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
/*
|
||||
** CAPI3REF: Prepare Flags
|
||||
**
|
||||
** These constants define various flags that can be passed into
|
||||
** These constants define various flags that can be passed into the
|
||||
** "prepFlags" parameter of the [sqlite3_prepare_v3()] and
|
||||
** [sqlite3_prepare16_v3()] interfaces.
|
||||
**
|
||||
@@ -4422,7 +4471,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** there is a small performance advantage to passing an nByte parameter that
|
||||
** is the number of bytes in the input string <i>including</i>
|
||||
** the nul-terminator.
|
||||
** Note that nByte measure the length of the input in bytes, not
|
||||
** Note that nByte measures the length of the input in bytes, not
|
||||
** characters, even for the UTF-16 interfaces.
|
||||
**
|
||||
** ^If pzTail is not NULL then *pzTail is made to point to the first byte
|
||||
@@ -4556,7 +4605,7 @@ SQLITE_API int sqlite3_prepare16_v3(
|
||||
**
|
||||
** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
|
||||
** is available to hold the result, or if the result would exceed the
|
||||
** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
|
||||
** maximum string length determined by the [SQLITE_LIMIT_LENGTH].
|
||||
**
|
||||
** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
|
||||
** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
|
||||
@@ -4744,7 +4793,7 @@ typedef struct sqlite3_value sqlite3_value;
|
||||
**
|
||||
** The context in which an SQL function executes is stored in an
|
||||
** sqlite3_context object. ^A pointer to an sqlite3_context object
|
||||
** is always first parameter to [application-defined SQL functions].
|
||||
** is always the first parameter to [application-defined SQL functions].
|
||||
** The application-defined SQL function implementation will pass this
|
||||
** pointer through into calls to [sqlite3_result_int | sqlite3_result()],
|
||||
** [sqlite3_aggregate_context()], [sqlite3_user_data()],
|
||||
@@ -4868,9 +4917,11 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** associated with the pointer P of type T. ^D is either a NULL pointer or
|
||||
** a pointer to a destructor function for P. ^SQLite will invoke the
|
||||
** destructor D with a single argument of P when it is finished using
|
||||
** P. The T parameter should be a static string, preferably a string
|
||||
** literal. The sqlite3_bind_pointer() routine is part of the
|
||||
** [pointer passing interface] added for SQLite 3.20.0.
|
||||
** P, even if the call to sqlite3_bind_pointer() fails. Due to a
|
||||
** historical design quirk, results are undefined if D is
|
||||
** SQLITE_TRANSIENT. The T parameter should be a static string,
|
||||
** preferably a string literal. The sqlite3_bind_pointer() routine is
|
||||
** part of the [pointer passing interface] added for SQLite 3.20.0.
|
||||
**
|
||||
** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
|
||||
** for the [prepared statement] or with a prepared statement for which
|
||||
@@ -5481,7 +5532,7 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
|
||||
**
|
||||
** ^The sqlite3_finalize() function is called to delete a [prepared statement].
|
||||
** ^If the most recent evaluation of the statement encountered no errors
|
||||
** or if the statement is never been evaluated, then sqlite3_finalize() returns
|
||||
** or if the statement has never been evaluated, then sqlite3_finalize() returns
|
||||
** SQLITE_OK. ^If the most recent evaluation of statement S failed, then
|
||||
** sqlite3_finalize(S) returns the appropriate [error code] or
|
||||
** [extended error code].
|
||||
@@ -5713,7 +5764,7 @@ SQLITE_API int sqlite3_create_window_function(
|
||||
/*
|
||||
** CAPI3REF: Text Encodings
|
||||
**
|
||||
** These constant define integer codes that represent the various
|
||||
** These constants define integer codes that represent the various
|
||||
** text encodings supported by SQLite.
|
||||
*/
|
||||
#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */
|
||||
@@ -5805,7 +5856,7 @@ SQLITE_API int sqlite3_create_window_function(
|
||||
** result.
|
||||
** Every function that invokes [sqlite3_result_subtype()] should have this
|
||||
** property. If it does not, then the call to [sqlite3_result_subtype()]
|
||||
** might become a no-op if the function is used as term in an
|
||||
** might become a no-op if the function is used as a term in an
|
||||
** [expression index]. On the other hand, SQL functions that never invoke
|
||||
** [sqlite3_result_subtype()] should avoid setting this property, as the
|
||||
** purpose of this property is to disable certain optimizations that are
|
||||
@@ -5932,7 +5983,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
|
||||
** sqlite3_value_nochange(X) interface returns true if and only if
|
||||
** the column corresponding to X is unchanged by the UPDATE operation
|
||||
** that the xUpdate method call was invoked to implement and if
|
||||
** and the prior [xColumn] method call that was invoked to extracted
|
||||
** the prior [xColumn] method call that was invoked to extract
|
||||
** the value for that column returned without setting a result (probably
|
||||
** because it queried [sqlite3_vtab_nochange()] and found that the column
|
||||
** was unchanging). ^Within an [xUpdate] method, any value for which
|
||||
@@ -6205,6 +6256,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
|
||||
** or a NULL pointer if there were no prior calls to
|
||||
** sqlite3_set_clientdata() with the same values of D and N.
|
||||
** Names are compared using strcmp() and are thus case sensitive.
|
||||
** It returns 0 on success and SQLITE_NOMEM on allocation failure.
|
||||
**
|
||||
** If P and X are both non-NULL, then the destructor X is invoked with
|
||||
** argument P on the first of the following occurrences:
|
||||
@@ -8881,9 +8933,18 @@ SQLITE_API int sqlite3_status64(
|
||||
** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a
|
||||
** non-zero [error code] on failure.
|
||||
**
|
||||
** ^The sqlite3_db_status64(D,O,C,H,R) routine works exactly the same
|
||||
** way as sqlite3_db_status(D,O,C,H,R) routine except that the C and H
|
||||
** parameters are pointer to 64-bit integers (type: sqlite3_int64) instead
|
||||
** of pointers to 32-bit integers, which allows larger status values
|
||||
** to be returned. If a status value exceeds 2,147,483,647 then
|
||||
** sqlite3_db_status() will truncate the value whereas sqlite3_db_status64()
|
||||
** will return the full value.
|
||||
**
|
||||
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
|
||||
*/
|
||||
SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
SQLITE_API int sqlite3_db_status64(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Status Parameters for database connections
|
||||
@@ -8980,6 +9041,10 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
** If an IO or other error occurs while writing a page to disk, the effect
|
||||
** on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is undefined.)^ ^The
|
||||
** highwater mark associated with SQLITE_DBSTATUS_CACHE_WRITE is always 0.
|
||||
** <p>
|
||||
** ^(There is overlap between the quantities measured by this parameter
|
||||
** (SQLITE_DBSTATUS_CACHE_WRITE) and SQLITE_DBSTATUS_TEMPBUF_SPILL.
|
||||
** Resetting one will reduce the other.)^
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_CACHE_SPILL]] ^(<dt>SQLITE_DBSTATUS_CACHE_SPILL</dt>
|
||||
@@ -8995,6 +9060,18 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
** <dd>This parameter returns zero for the current value if and only if
|
||||
** all foreign key constraints (deferred or immediate) have been
|
||||
** resolved.)^ ^The highwater mark is always 0.
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_TEMPBUF_SPILL] ^(<dt>SQLITE_DBSTATUS_TEMPBUF_SPILL</dt>
|
||||
** <dd>^(This parameter returns the number of bytes written to temporary
|
||||
** files on disk that could have been kept in memory had sufficient memory
|
||||
** been available. This value includes writes to intermediate tables that
|
||||
** are part of complex queries, external sorts that spill to disk, and
|
||||
** writes to TEMP tables.)^
|
||||
** ^The highwater mark is always 0.
|
||||
** <p>
|
||||
** ^(There is overlap between the quantities measured by this parameter
|
||||
** (SQLITE_DBSTATUS_TEMPBUF_SPILL) and SQLITE_DBSTATUS_CACHE_WRITE.
|
||||
** Resetting one will reduce the other.)^
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
@@ -9011,7 +9088,8 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
||||
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
|
||||
#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
|
||||
#define SQLITE_DBSTATUS_CACHE_SPILL 12
|
||||
#define SQLITE_DBSTATUS_MAX 12 /* Largest defined DBSTATUS */
|
||||
#define SQLITE_DBSTATUS_TEMPBUF_SPILL 13
|
||||
#define SQLITE_DBSTATUS_MAX 13 /* Largest defined DBSTATUS */
|
||||
|
||||
|
||||
/*
|
||||
@@ -9776,7 +9854,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
||||
** is the number of pages currently in the write-ahead log file,
|
||||
** including those that were just committed.
|
||||
**
|
||||
** The callback function should normally return [SQLITE_OK]. ^If an error
|
||||
** ^The callback function should normally return [SQLITE_OK]. ^If an error
|
||||
** code is returned, that error will propagate back up through the
|
||||
** SQLite code base to cause the statement that provoked the callback
|
||||
** to report an error, though the commit will have still occurred. If the
|
||||
@@ -9784,13 +9862,26 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
||||
** that does not correspond to any valid SQLite error code, the results
|
||||
** are undefined.
|
||||
**
|
||||
** A single database handle may have at most a single write-ahead log callback
|
||||
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
|
||||
** previously registered write-ahead log callback. ^The return value is
|
||||
** a copy of the third parameter from the previous call, if any, or 0.
|
||||
** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the
|
||||
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
|
||||
** overwrite any prior [sqlite3_wal_hook()] settings.
|
||||
** ^A single database handle may have at most a single write-ahead log
|
||||
** callback registered at one time. ^Calling [sqlite3_wal_hook()]
|
||||
** replaces the default behavior or previously registered write-ahead
|
||||
** log callback.
|
||||
**
|
||||
** ^The return value is a copy of the third parameter from the
|
||||
** previous call, if any, or 0.
|
||||
**
|
||||
** ^The [sqlite3_wal_autocheckpoint()] interface and the
|
||||
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and
|
||||
** will overwrite any prior [sqlite3_wal_hook()] settings.
|
||||
**
|
||||
** ^If a write-ahead log callback is set using this function then
|
||||
** [sqlite3_wal_checkpoint_v2()] or [PRAGMA wal_checkpoint]
|
||||
** should be invoked periodically to keep the write-ahead log file
|
||||
** from growing without bound.
|
||||
**
|
||||
** ^Passing a NULL pointer for the callback disables automatic
|
||||
** checkpointing entirely. To re-enable the default behavior, call
|
||||
** sqlite3_wal_autocheckpoint(db,1000) or use [PRAGMA wal_checkpoint].
|
||||
*/
|
||||
SQLITE_API void *sqlite3_wal_hook(
|
||||
sqlite3*,
|
||||
@@ -9807,7 +9898,7 @@ SQLITE_API void *sqlite3_wal_hook(
|
||||
** to automatically [checkpoint]
|
||||
** after committing a transaction if there are N or
|
||||
** more frames in the [write-ahead log] file. ^Passing zero or
|
||||
** a negative value as the nFrame parameter disables automatic
|
||||
** a negative value as the N parameter disables automatic
|
||||
** checkpoints entirely.
|
||||
**
|
||||
** ^The callback registered by this function replaces any existing callback
|
||||
@@ -9823,9 +9914,10 @@ SQLITE_API void *sqlite3_wal_hook(
|
||||
**
|
||||
** ^Every new [database connection] defaults to having the auto-checkpoint
|
||||
** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT]
|
||||
** pages. The use of this interface
|
||||
** is only necessary if the default setting is found to be suboptimal
|
||||
** for a particular application.
|
||||
** pages.
|
||||
**
|
||||
** ^The use of this interface is only necessary if the default setting
|
||||
** is found to be suboptimal for a particular application.
|
||||
*/
|
||||
SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
||||
|
||||
@@ -9890,6 +9982,11 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the
|
||||
** addition that it also truncates the log file to zero bytes just prior
|
||||
** to a successful return.
|
||||
**
|
||||
** <dt>SQLITE_CHECKPOINT_NOOP<dd>
|
||||
** ^This mode always checkpoints zero frames. The only reason to invoke
|
||||
** a NOOP checkpoint is to access the values returned by
|
||||
** sqlite3_wal_checkpoint_v2() via output parameters *pnLog and *pnCkpt.
|
||||
** </dl>
|
||||
**
|
||||
** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in
|
||||
@@ -9960,6 +10057,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
||||
** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the
|
||||
** meaning of each of these checkpoint modes.
|
||||
*/
|
||||
#define SQLITE_CHECKPOINT_NOOP -1 /* Do no work at all */
|
||||
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
|
||||
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
|
||||
#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
|
||||
@@ -10787,7 +10885,7 @@ typedef struct sqlite3_snapshot {
|
||||
** The [sqlite3_snapshot_get()] interface is only available when the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
||||
SQLITE_API int sqlite3_snapshot_get(
|
||||
sqlite3 *db,
|
||||
const char *zSchema,
|
||||
sqlite3_snapshot **ppSnapshot
|
||||
@@ -10836,7 +10934,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
||||
** The [sqlite3_snapshot_open()] interface is only available when the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
|
||||
SQLITE_API int sqlite3_snapshot_open(
|
||||
sqlite3 *db,
|
||||
const char *zSchema,
|
||||
sqlite3_snapshot *pSnapshot
|
||||
@@ -10853,7 +10951,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
|
||||
** The [sqlite3_snapshot_free()] interface is only available when the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
|
||||
SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compare the ages of two snapshot handles.
|
||||
@@ -10880,7 +10978,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
|
||||
** This interface is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] option.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
SQLITE_API int sqlite3_snapshot_cmp(
|
||||
sqlite3_snapshot *p1,
|
||||
sqlite3_snapshot *p2
|
||||
);
|
||||
@@ -10908,7 +11006,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
** This interface is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] option.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
|
||||
SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Serialize a database
|
||||
@@ -10982,12 +11080,13 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
||||
**
|
||||
** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
|
||||
** [database connection] D to disconnect from database S and then
|
||||
** reopen S as an in-memory database based on the serialization contained
|
||||
** in P. The serialized database P is N bytes in size. M is the size of
|
||||
** the buffer P, which might be larger than N. If M is larger than N, and
|
||||
** the SQLITE_DESERIALIZE_READONLY bit is not set in F, then SQLite is
|
||||
** permitted to add content to the in-memory database as long as the total
|
||||
** size does not exceed M bytes.
|
||||
** reopen S as an in-memory database based on the serialization
|
||||
** contained in P. If S is a NULL pointer, the main database is
|
||||
** used. The serialized database P is N bytes in size. M is the size
|
||||
** of the buffer P, which might be larger than N. If M is larger than
|
||||
** N, and the SQLITE_DESERIALIZE_READONLY bit is not set in F, then
|
||||
** SQLite is permitted to add content to the in-memory database as
|
||||
** long as the total size does not exceed M bytes.
|
||||
**
|
||||
** If the SQLITE_DESERIALIZE_FREEONCLOSE bit is set in F, then SQLite will
|
||||
** invoke sqlite3_free() on the serialization buffer when the database
|
||||
@@ -11054,6 +11153,54 @@ SQLITE_API int sqlite3_deserialize(
|
||||
#define SQLITE_DESERIALIZE_RESIZEABLE 2 /* Resize using sqlite3_realloc64() */
|
||||
#define SQLITE_DESERIALIZE_READONLY 4 /* Database is read-only */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Bind array values to the CARRAY table-valued function
|
||||
**
|
||||
** The sqlite3_carray_bind(S,I,P,N,F,X) interface binds an array value to
|
||||
** one of the first argument of the [carray() table-valued function]. The
|
||||
** S parameter is a pointer to the [prepared statement] that uses the carray()
|
||||
** functions. I is the parameter index to be bound. P is a pointer to the
|
||||
** array to be bound, and N is the number of eements in the array. The
|
||||
** F argument is one of constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64],
|
||||
** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], or [SQLITE_CARRAY_BLOB] to
|
||||
** indicate the datatype of the array being bound. The X argument is not a
|
||||
** NULL pointer, then SQLite will invoke the function X on the P parameter
|
||||
** after it has finished using P, even if the call to
|
||||
** sqlite3_carray_bind() fails. The special-case finalizer
|
||||
** SQLITE_TRANSIENT has no effect here.
|
||||
*/
|
||||
SQLITE_API int sqlite3_carray_bind(
|
||||
sqlite3_stmt *pStmt, /* Statement to be bound */
|
||||
int i, /* Parameter index */
|
||||
void *aData, /* Pointer to array data */
|
||||
int nData, /* Number of data elements */
|
||||
int mFlags, /* CARRAY flags */
|
||||
void (*xDel)(void*) /* Destructor for aData */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Datatypes for the CARRAY table-valued function
|
||||
**
|
||||
** The fifth argument to the [sqlite3_carray_bind()] interface musts be
|
||||
** one of the following constants, to specify the datatype of the array
|
||||
** that is being bound into the [carray table-valued function].
|
||||
*/
|
||||
#define SQLITE_CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define SQLITE_CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define SQLITE_CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define SQLITE_CARRAY_TEXT 3 /* Data is char* */
|
||||
#define SQLITE_CARRAY_BLOB 4 /* Data is struct iovec */
|
||||
|
||||
/*
|
||||
** Versions of the above #defines that omit the initial SQLITE_, for
|
||||
** legacy compatibility.
|
||||
*/
|
||||
#define CARRAY_INT32 0 /* Data is 32-bit signed integers */
|
||||
#define CARRAY_INT64 1 /* Data is 64-bit signed integers */
|
||||
#define CARRAY_DOUBLE 2 /* Data is doubles */
|
||||
#define CARRAY_TEXT 3 /* Data is char* */
|
||||
#define CARRAY_BLOB 4 /* Data is struct iovec */
|
||||
|
||||
/*
|
||||
** Undo the hack that converts floating point types to integer for
|
||||
** builds on processors without floating point support.
|
||||
@@ -12313,14 +12460,32 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
||||
** update the "main" database attached to handle db with the changes found in
|
||||
** the changeset passed via the second and third arguments.
|
||||
**
|
||||
** All changes made by these functions are enclosed in a savepoint transaction.
|
||||
** If any other error (aside from a constraint failure when attempting to
|
||||
** write to the target database) occurs, then the savepoint transaction is
|
||||
** rolled back, restoring the target database to its original state, and an
|
||||
** SQLite error code returned. Additionally, starting with version 3.51.0,
|
||||
** an error code and error message that may be accessed using the
|
||||
** [sqlite3_errcode()] and [sqlite3_errmsg()] APIs are left in the database
|
||||
** handle.
|
||||
**
|
||||
** The fourth argument (xFilter) passed to these functions is the "filter
|
||||
** callback". If it is not NULL, then for each table affected by at least one
|
||||
** change in the changeset, the filter callback is invoked with
|
||||
** the table name as the second argument, and a copy of the context pointer
|
||||
** passed as the sixth argument as the first. If the "filter callback"
|
||||
** returns zero, then no attempt is made to apply any changes to the table.
|
||||
** Otherwise, if the return value is non-zero or the xFilter argument to
|
||||
** is NULL, all changes related to the table are attempted.
|
||||
** callback". This may be passed NULL, in which case all changes in the
|
||||
** changeset are applied to the database. For sqlite3changeset_apply() and
|
||||
** sqlite3_changeset_apply_v2(), if it is not NULL, then it is invoked once
|
||||
** for each table affected by at least one change in the changeset. In this
|
||||
** case the table name is passed as the second argument, and a copy of
|
||||
** the context pointer passed as the sixth argument to apply() or apply_v2()
|
||||
** as the first. If the "filter callback" returns zero, then no attempt is
|
||||
** made to apply any changes to the table. Otherwise, if the return value is
|
||||
** non-zero, all changes related to the table are attempted.
|
||||
**
|
||||
** For sqlite3_changeset_apply_v3(), the xFilter callback is invoked once
|
||||
** per change. The second argument in this case is an sqlite3_changeset_iter
|
||||
** that may be queried using the usual APIs for the details of the current
|
||||
** change. If the "filter callback" returns zero in this case, then no attempt
|
||||
** is made to apply the current change. If it returns non-zero, the change
|
||||
** is applied.
|
||||
**
|
||||
** For each table that is not excluded by the filter callback, this function
|
||||
** tests that the target database contains a compatible table. A table is
|
||||
@@ -12341,11 +12506,11 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
||||
** one such warning is issued for each table in the changeset.
|
||||
**
|
||||
** For each change for which there is a compatible table, an attempt is made
|
||||
** to modify the table contents according to the UPDATE, INSERT or DELETE
|
||||
** change. If a change cannot be applied cleanly, the conflict handler
|
||||
** function passed as the fifth argument to sqlite3changeset_apply() may be
|
||||
** invoked. A description of exactly when the conflict handler is invoked for
|
||||
** each type of change is below.
|
||||
** to modify the table contents according to each UPDATE, INSERT or DELETE
|
||||
** change that is not excluded by a filter callback. If a change cannot be
|
||||
** applied cleanly, the conflict handler function passed as the fifth argument
|
||||
** to sqlite3changeset_apply() may be invoked. A description of exactly when
|
||||
** the conflict handler is invoked for each type of change is below.
|
||||
**
|
||||
** Unlike the xFilter argument, xConflict may not be passed NULL. The results
|
||||
** of passing anything other than a valid function pointer as the xConflict
|
||||
@@ -12441,12 +12606,6 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
||||
** This can be used to further customize the application's conflict
|
||||
** resolution strategy.
|
||||
**
|
||||
** All changes made by these functions are enclosed in a savepoint transaction.
|
||||
** If any other error (aside from a constraint failure when attempting to
|
||||
** write to the target database) occurs, then the savepoint transaction is
|
||||
** rolled back, restoring the target database to its original state, and an
|
||||
** SQLite error code returned.
|
||||
**
|
||||
** If the output parameters (ppRebase) and (pnRebase) are non-NULL and
|
||||
** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2()
|
||||
** may set (*ppRebase) to point to a "rebase" that may be used with the
|
||||
@@ -12496,6 +12655,23 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
||||
void **ppRebase, int *pnRebase, /* OUT: Rebase data */
|
||||
int flags /* SESSION_CHANGESETAPPLY_* flags */
|
||||
);
|
||||
SQLITE_API int sqlite3changeset_apply_v3(
|
||||
sqlite3 *db, /* Apply change to "main" db of this handle */
|
||||
int nChangeset, /* Size of changeset in bytes */
|
||||
void *pChangeset, /* Changeset blob */
|
||||
int(*xFilter)(
|
||||
void *pCtx, /* Copy of sixth arg to _apply() */
|
||||
sqlite3_changeset_iter *p /* Handle describing change */
|
||||
),
|
||||
int(*xConflict)(
|
||||
void *pCtx, /* Copy of sixth arg to _apply() */
|
||||
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
|
||||
sqlite3_changeset_iter *p /* Handle describing change and conflict */
|
||||
),
|
||||
void *pCtx, /* First argument passed to xConflict */
|
||||
void **ppRebase, int *pnRebase, /* OUT: Rebase data */
|
||||
int flags /* SESSION_CHANGESETAPPLY_* flags */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Flags for sqlite3changeset_apply_v2
|
||||
@@ -12915,6 +13091,23 @@ SQLITE_API int sqlite3changeset_apply_v2_strm(
|
||||
void **ppRebase, int *pnRebase,
|
||||
int flags
|
||||
);
|
||||
SQLITE_API int sqlite3changeset_apply_v3_strm(
|
||||
sqlite3 *db, /* Apply change to "main" db of this handle */
|
||||
int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
|
||||
void *pIn, /* First arg for xInput */
|
||||
int(*xFilter)(
|
||||
void *pCtx, /* Copy of sixth arg to _apply() */
|
||||
sqlite3_changeset_iter *p
|
||||
),
|
||||
int(*xConflict)(
|
||||
void *pCtx, /* Copy of sixth arg to _apply() */
|
||||
int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
|
||||
sqlite3_changeset_iter *p /* Handle describing change and conflict */
|
||||
),
|
||||
void *pCtx, /* First argument passed to xConflict */
|
||||
void **ppRebase, int *pnRebase,
|
||||
int flags
|
||||
);
|
||||
SQLITE_API int sqlite3changeset_concat_strm(
|
||||
int (*xInputA)(void *pIn, void *pData, int *pnData),
|
||||
void *pInA,
|
||||
|
||||
7
deps/sqlite/sqlite3ext.h
vendored
7
deps/sqlite/sqlite3ext.h
vendored
@@ -368,6 +368,10 @@ struct sqlite3_api_routines {
|
||||
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
|
||||
/* Version 3.50.0 and later */
|
||||
int (*setlk_timeout)(sqlite3*,int,int);
|
||||
/* Version 3.51.0 and later */
|
||||
int (*set_errmsg)(sqlite3*,int,const char*);
|
||||
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -703,6 +707,9 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
|
||||
/* Version 3.50.0 and later */
|
||||
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
|
||||
/* Version 3.51.0 and later */
|
||||
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
|
||||
#define sqlite3_db_status64 sqlite3_api->db_status64
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
32
docs/model.md
Normal file
32
docs/model.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Model
|
||||
|
||||
A reasonable mental model of Tilde Friends is as a virtual computer. User
|
||||
interace is through a web browser. Communication with the outside world is
|
||||
through the Secure Scuttlebutt (SSB) network protocol. Persistence is through
|
||||
an SSB store and an additional key-value store in an sqlite database.
|
||||
|
||||
The schema for the sqlite database is primarily a `messages` table and a
|
||||
`blobs` table, which are what one would expect from the SSB specifications.
|
||||
|
||||
```dot
|
||||
digraph {
|
||||
web_browser -> tilde_friends_web_interface [dir=both];
|
||||
web_browser [shape=rect,label="Web Browser"];
|
||||
subgraph cluster_tilde_friends {
|
||||
label = "Tilde Friends";
|
||||
tilde_friends_web_interface -> example_app [dir=both];
|
||||
subgraph cluster_sandbox {
|
||||
label = "app sandbox";
|
||||
example_app;
|
||||
}
|
||||
example_app -> tilde_friends_core;
|
||||
tilde_friends_core -> example_app;
|
||||
tilde_friends_web_interface -> tilde_friends_core;
|
||||
tilde_friends_core -> "db.sqlite";
|
||||
tilde_friends_core -> ssb;
|
||||
"db.sqlite" [shape=cylinder];
|
||||
}
|
||||
ssb -> other_ssb_clients [label="Secure Handshake",dir=both];
|
||||
other_ssb_clients [shape=rect,label="SSB Peers"];
|
||||
}
|
||||
```
|
||||
@@ -60,6 +60,7 @@ options:
|
||||
broadcast (default: true): Send network discovery broadcasts.
|
||||
discovery (default: true): Receive network discovery broadcasts.
|
||||
stay_connected (default: false): Whether to attempt to keep several peer connections open.
|
||||
accepted_eula_version (default: 0): The version of the last accepted EULA.
|
||||
-o, --one-proc Run everything in one process (unsafely!).
|
||||
-z, --zip path Zip archive from which to load files.
|
||||
-v, --verbose Log raw messages.
|
||||
|
||||
7
metadata/en-US/changelogs/47.txt
Normal file
7
metadata/en-US/changelogs/47.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
* Fixed information where identity information was outdated.
|
||||
* Show more context when prompting for permissions.
|
||||
* Reduce redundant queries to improve load times.
|
||||
* Improved profile load times.
|
||||
* Don't show an empty code of conduct.
|
||||
* Resolve ambiguity when a user is both followed and blocked (they're blocked).
|
||||
* Updates: CodeMirror, emojis, libbacktrace, sqlite 3.51.0.
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.unprompted.tildefriends"
|
||||
android:versionCode="44"
|
||||
android:versionCode="47"
|
||||
android:versionName="0.2025.10">
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
10
src/api.js.c
10
src/api.js.c
@@ -446,15 +446,15 @@ static void _tf_ssb_getActiveIdentity_work(tf_ssb_t* ssb, void* user_data)
|
||||
tf_ssb_db_identity_get_active(db, request->name, request->package_owner, request->package_name, request->identity, sizeof(request->identity));
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
|
||||
if (!*request->identity)
|
||||
{
|
||||
tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getActiveIdentity_visit, request);
|
||||
}
|
||||
|
||||
if (!*request->identity && tf_ssb_db_user_has_permission(ssb, NULL, request->name, "administration"))
|
||||
{
|
||||
tf_ssb_whoami(ssb, request->identity, sizeof(request->identity));
|
||||
}
|
||||
|
||||
if (!*request->identity)
|
||||
{
|
||||
tf_ssb_db_identity_visit(ssb, request->name, _tf_ssb_getActiveIdentity_visit, request);
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_getActiveIdentity_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
|
||||
@@ -14,11 +14,17 @@
|
||||
#include "sodium/crypto_sign.h"
|
||||
#include "sodium/utils.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#define CYAN "\e[1;36m"
|
||||
#define MAGENTA "\e[1;35m"
|
||||
#define YELLOW "\e[1;33m"
|
||||
#define RESET "\e[0m"
|
||||
|
||||
static const int k_eula_version = 1;
|
||||
|
||||
static JSClassID _httpd_request_class_id;
|
||||
|
||||
typedef struct _http_user_data_t
|
||||
@@ -616,28 +622,97 @@ tf_httpd_user_app_t* tf_httpd_parse_user_app_from_path(const char* path, const c
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_root_callback(const char* path, void* user_data)
|
||||
typedef struct _root_t
|
||||
{
|
||||
tf_http_request_t* request = user_data;
|
||||
const char* headers[] = {
|
||||
"Location",
|
||||
path ? path : "/~core/apps/",
|
||||
};
|
||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||
tf_http_request_unref(request);
|
||||
}
|
||||
tf_http_request_t* request;
|
||||
const char* path;
|
||||
} root_t;
|
||||
|
||||
static void _httpd_endpoint_root(tf_http_request_t* request)
|
||||
static void _httpd_root_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
root_t* root = user_data;
|
||||
tf_http_request_t* request = root->request;
|
||||
const char* host = tf_http_request_get_header(request, "x-forwarded-host");
|
||||
if (!host)
|
||||
{
|
||||
host = tf_http_request_get_header(request, "host");
|
||||
}
|
||||
|
||||
bool require_eula =
|
||||
#if TARGET_OS_IPHONE
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
int64_t accepted_eula_version = 0;
|
||||
|
||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||
tf_ssb_db_get_global_setting_int64(db, "accepted_eula_version", &accepted_eula_version);
|
||||
if (require_eula && accepted_eula_version != k_eula_version)
|
||||
{
|
||||
root->path = tf_strdup("/static/eula.html");
|
||||
}
|
||||
else
|
||||
{
|
||||
root->path = tf_ssb_db_resolve_index(db, host);
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
}
|
||||
|
||||
static void _httpd_root_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
root_t* root = user_data;
|
||||
tf_http_request_t* request = root->request;
|
||||
const char* headers[] = {
|
||||
"Location",
|
||||
root->path ? root->path : "/~core/apps/",
|
||||
};
|
||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||
tf_http_request_unref(request);
|
||||
tf_free((void*)root->path);
|
||||
tf_free(root);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_root(tf_http_request_t* request)
|
||||
{
|
||||
root_t* root = tf_malloc(sizeof(root_t));
|
||||
*root = (root_t) {
|
||||
.request = request,
|
||||
};
|
||||
tf_http_request_ref(request);
|
||||
tf_task_t* task = request->user_data;
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
tf_ssb_run_work(ssb, _httpd_root_work, _httpd_root_after_work, root);
|
||||
}
|
||||
|
||||
static void _httpd_accept_eula_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "%d", k_eula_version);
|
||||
|
||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||
tf_ssb_db_set_global_setting_from_string(db, "accepted_eula_version", buffer);
|
||||
tf_ssb_release_db_writer(ssb, db);
|
||||
}
|
||||
|
||||
static void _httpd_accept_eula_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
tf_http_request_t* request = user_data;
|
||||
const char* headers[] = {
|
||||
"Location",
|
||||
"/",
|
||||
};
|
||||
tf_http_respond(request, 303, headers, tf_countof(headers) / 2, NULL, 0);
|
||||
tf_http_request_unref(request);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_accept_eula(tf_http_request_t* request)
|
||||
{
|
||||
tf_http_request_ref(request);
|
||||
tf_ssb_db_resolve_index_async(ssb, host, _httpd_endpoint_root_callback, request);
|
||||
tf_task_t* task = request->user_data;
|
||||
tf_ssb_t* ssb = tf_task_get_ssb(task);
|
||||
tf_ssb_run_work(ssb, _httpd_accept_eula_work, _httpd_accept_eula_after_work, request);
|
||||
}
|
||||
|
||||
static void _httpd_endpoint_robots_txt(tf_http_request_t* request)
|
||||
@@ -913,6 +988,7 @@ tf_http_t* tf_httpd_create(JSContext* context)
|
||||
tf_http_add_handler(http, "/login/logout", tf_httpd_endpoint_logout, NULL, task);
|
||||
tf_http_add_handler(http, "/login/auto", tf_httpd_endpoint_login_auto, NULL, task);
|
||||
tf_http_add_handler(http, "/login", tf_httpd_endpoint_login, NULL, task);
|
||||
tf_http_add_handler(http, "/eula/accept", _httpd_endpoint_accept_eula, NULL, task);
|
||||
|
||||
tf_http_add_handler(http, "/app/socket", tf_httpd_endpoint_app_socket, NULL, task);
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
JSValue settings_value = JS_ParseJSON(context, login->settings, strlen(login->settings), NULL);
|
||||
JSValue code_of_conduct_value = JS_GetPropertyStr(context, settings_value, "code_of_conduct");
|
||||
const char* code_of_conduct = JS_ToCString(context, code_of_conduct_value);
|
||||
const char* code_of_conduct = JS_IsString(code_of_conduct_value) ? JS_ToCString(context, code_of_conduct_value) : NULL;
|
||||
const char* result = tf_strdup(code_of_conduct);
|
||||
JS_FreeCString(context, code_of_conduct);
|
||||
JS_FreeValue(context, code_of_conduct_value);
|
||||
|
||||
@@ -124,6 +124,7 @@ void tf_httpd_endpoint_static(tf_http_request_t* request)
|
||||
|
||||
const char* k_static_files[] = {
|
||||
"index.html",
|
||||
"eula.html",
|
||||
"client.js",
|
||||
"tildefriends.svg",
|
||||
"jszip.min.js",
|
||||
|
||||
144
src/ios.m
144
src/ios.m
@@ -1,19 +1,28 @@
|
||||
#import <CoreSpotlight/CSSearchableIndex.h>
|
||||
#import <CoreSpotlight/CSSearchableItem.h>
|
||||
#import <CoreSpotlight/CSSearchableItemAttributeSet.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <WebKit/WKDownload.h>
|
||||
#import <WebKit/WKDownloadDelegate.h>
|
||||
#import <WebKit/WKNavigationAction.h>
|
||||
#import <WebKit/WKNavigationDelegate.h>
|
||||
#import <WebKit/WKNavigationResponse.h>
|
||||
#import <WebKit/WKUIDelegate.h>
|
||||
#import <WebKit/WKWebView.h>
|
||||
#import <WebKit/WKWebViewConfiguration.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.js.h"
|
||||
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
|
||||
void tf_run_thread_start(const char* zip_path);
|
||||
|
||||
@interface ViewController : UINavigationController <WKUIDelegate, WKNavigationDelegate>
|
||||
@interface ViewController : UINavigationController <WKUIDelegate, WKNavigationDelegate, WKDownloadDelegate, UIDocumentPickerDelegate>
|
||||
@property (strong, nonatomic) WKWebView* web_view;
|
||||
@property bool initial_load_complete;
|
||||
@property (retain) NSURL* download_url;
|
||||
@end
|
||||
|
||||
static void _start_initial_load(WKWebView* web_view)
|
||||
@@ -26,20 +35,17 @@ static void _start_initial_load(WKWebView* web_view)
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self setToolbarHidden:false animated:false];
|
||||
self.toolbar.items = @[
|
||||
[[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(goBack)],
|
||||
[[UIBarButtonItem alloc] initWithTitle:@"Forward" style:UIBarButtonItemStylePlain target:self action:@selector(goForward)],
|
||||
[[UIBarButtonItem alloc] initWithTitle:@"Refresh" style:UIBarButtonItemStylePlain target:self action:@selector(reload)]
|
||||
];
|
||||
|
||||
WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init];
|
||||
self.web_view = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];
|
||||
self.web_view.UIDelegate = self;
|
||||
self.web_view.navigationDelegate = self;
|
||||
self.web_view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
|
||||
self.web_view.translatesAutoresizingMaskIntoConstraints = false;
|
||||
self.web_view.allowsBackForwardNavigationGestures = true;
|
||||
[self.view addSubview:self.web_view];
|
||||
UIRefreshControl* refresh = [[UIRefreshControl alloc] init];
|
||||
[refresh addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
|
||||
self.web_view.scrollView.refreshControl = refresh;
|
||||
|
||||
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.web_view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view
|
||||
attribute:NSLayoutAttributeTop
|
||||
@@ -61,30 +67,21 @@ static void _start_initial_load(WKWebView* web_view)
|
||||
_start_initial_load(self.web_view);
|
||||
}
|
||||
|
||||
- (void)goBack
|
||||
{
|
||||
if (self.web_view.canGoBack)
|
||||
{
|
||||
[self.web_view goBack];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)goForward
|
||||
{
|
||||
if (self.web_view.canGoForward)
|
||||
{
|
||||
[self.web_view goForward];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reload
|
||||
- (void)handleRefresh:(id)sender
|
||||
{
|
||||
tf_printf("refresh\n");
|
||||
[self.web_view reload];
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView*)webView didFinishNavigation:(WKNavigation*)navigation
|
||||
{
|
||||
self.initial_load_complete = true;
|
||||
if (!self.initial_load_complete)
|
||||
{
|
||||
tf_printf("initial load complete\n");
|
||||
self.initial_load_complete = true;
|
||||
}
|
||||
self.navigationController.interactivePopGestureRecognizer.enabled = self.web_view.canGoBack;
|
||||
[self.web_view.scrollView.refreshControl endRefreshing];
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView*)webView didFailProvisionalNavigation:(WKNavigation*)navigation withError:(NSError*)error
|
||||
@@ -133,6 +130,59 @@ static void _start_initial_load(WKWebView* web_view)
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) { completionHandler(nil); }]];
|
||||
[self presentViewController:alertController animated:YES completion:^ {}];
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView*)webView decidePolicyForNavigationAction:(WKNavigationAction*)navigationAction decisionHandler:(void (^)(enum WKNavigationActionPolicy))decisionHandler
|
||||
{
|
||||
decisionHandler(navigationAction.shouldPerformDownload ? WKNavigationActionPolicyDownload : WKNavigationActionPolicyAllow);
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView*)webView
|
||||
decidePolicyForNavigationResponse:(WKNavigationResponse*)navigationResponse
|
||||
decisionHandler:(void (^)(enum WKNavigationResponsePolicy))decisionHandler
|
||||
{
|
||||
decisionHandler(navigationResponse.canShowMIMEType ? WKNavigationResponsePolicyAllow : WKNavigationResponsePolicyDownload);
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView*)webView navigationAction:(WKNavigationAction*)navigationAction didBecomeDownload:(WKDownload*)download
|
||||
{
|
||||
download.delegate = self;
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView*)webView navigationResponse:(WKNavigationResponse*)navigationResponse didBecomeDownload:(WKDownload*)download
|
||||
{
|
||||
download.delegate = self;
|
||||
}
|
||||
|
||||
- (void)download:(WKDownload*)download
|
||||
decideDestinationUsingResponse:(NSURLResponse*)response
|
||||
suggestedFilename:(NSString*)suggestedFilename
|
||||
completionHandler:(void (^)(NSURL*))completionHandler
|
||||
{
|
||||
self.download_url = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:suggestedFilename];
|
||||
completionHandler(self.download_url);
|
||||
}
|
||||
|
||||
- (void)downloadDidFinish:(WKDownload*)download
|
||||
{
|
||||
UIDocumentPickerViewController* picker = [[UIDocumentPickerViewController alloc] initForExportingURLs:@[ self.download_url ]];
|
||||
picker.delegate = self;
|
||||
[self presentViewController:picker animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)download:(WKDownload*)download didFailWithError:(NSError*)error resumeData:(NSData*)resumeData
|
||||
{
|
||||
tf_printf("download didFailWithError:%s\n", [error.localizedDescription UTF8String]);
|
||||
}
|
||||
|
||||
- (void)documentPicker:(UIDocumentPickerViewController*)controller didPickDocumentAtURLs:(NSArray<NSURL*>*)urls
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtURL:self.download_url error:nil];
|
||||
}
|
||||
|
||||
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController*)controller
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtURL:self.download_url error:nil];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
@@ -148,8 +198,50 @@ static void _start_initial_load(WKWebView* web_view)
|
||||
[self.window makeKeyAndVisible];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)application:(UIApplication*)application
|
||||
continueUserActivity:(NSUserActivity*)activity
|
||||
restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>>*))restorationHandler
|
||||
{
|
||||
if ([activity.activityType isEqual:CSSearchableItemActionType])
|
||||
{
|
||||
const char* identifier = [[activity.userInfo valueForKey:CSSearchableItemActivityIdentifier] UTF8String];
|
||||
tf_printf("Jumping to search result: %s.\n", identifier);
|
||||
|
||||
char url[1024];
|
||||
snprintf(url, sizeof(url), "http://localhost:12345/~core/ssb/#%s", identifier);
|
||||
tf_printf("Navigating to %s.", url);
|
||||
ViewController* view_controller = (ViewController*)self.window.rootViewController;
|
||||
[view_controller.web_view loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithUTF8String:url]]]];
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("no search\n");
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
void tf_notify_message_added_ios(const char* identifier, const char* title, const char* content)
|
||||
{
|
||||
tf_printf("indexing: identifier=%s title=%s content=%s\n", identifier, title, content);
|
||||
CSSearchableItemAttributeSet* attribute_set = [[CSSearchableItemAttributeSet alloc] initWithContentType:UTTypeText];
|
||||
attribute_set.title = [NSString stringWithUTF8String:content];
|
||||
attribute_set.contentDescription = [NSString stringWithUTF8String:title];
|
||||
CSSearchableItem* item = [[CSSearchableItem alloc] initWithUniqueIdentifier:[NSString stringWithUTF8String:identifier] domainIdentifier:@"com.unprompted.tildefriends.messages"
|
||||
attributeSet:attribute_set];
|
||||
[[CSSearchableIndex defaultSearchableIndex] indexSearchableItems:@[ item ] completionHandler:^(NSError* _Nullable error) {
|
||||
if (error)
|
||||
{
|
||||
tf_printf("indexing error: %s.\n", [error.localizedDescription UTF8String]);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("indexed successfully.\n");
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
NSFileManager* file_manager = [NSFileManager defaultManager];
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>18</string>
|
||||
<string>25</string>
|
||||
<key>DTPlatformName</key>
|
||||
<string>iphoneos</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>14.0</string>
|
||||
<string>14.5</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
@@ -83,5 +83,13 @@
|
||||
</dict>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Camera access is used to take pictures to add to posts.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Microphone access is used to capture audio to add to posts.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Photo library access is used to select images to add to posts.</string>
|
||||
<key>NSDownlodasFolderUsageDescription</key>
|
||||
<string>Downloads folder access is used to export and import apps.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#include <os/log.h>
|
||||
#include <stdio.h>
|
||||
#define tf_printf(...) \
|
||||
do \
|
||||
{ \
|
||||
char buffer##__LINE__[2048]; \
|
||||
snprintf(buffer##__LINE__, sizeof(buffer##__LINE__), __VA_ARGS__); \
|
||||
os_log(OS_LOG_DEFAULT, "%{public}s", buffer##__LINE__); \
|
||||
fputs(buffer##__LINE__, stdout); \
|
||||
fflush(stdout); \
|
||||
} while (0)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
190
src/ssb.db.c
190
src/ssb.db.c
@@ -623,6 +623,12 @@ static char* _tf_ssb_db_get_message_blob_wants(sqlite3* db, int64_t rowid)
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef enum _message_type_t
|
||||
{
|
||||
k_message_type_other,
|
||||
k_message_type_post,
|
||||
} message_type_t;
|
||||
|
||||
typedef struct _message_store_t
|
||||
{
|
||||
char id[k_id_base64_len];
|
||||
@@ -635,6 +641,7 @@ typedef struct _message_store_t
|
||||
const char* content;
|
||||
size_t length;
|
||||
|
||||
message_type_t type;
|
||||
bool out_stored;
|
||||
char* out_blob_wants;
|
||||
|
||||
@@ -716,6 +723,28 @@ static void _tf_ssb_db_store_message_after_work(tf_ssb_t* ssb, int status, void*
|
||||
tf_trace_end(trace);
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
if (store->type == k_message_type_post)
|
||||
{
|
||||
JSContext* context = tf_ssb_get_context(ssb);
|
||||
JSValue content = JS_ParseJSON(context, store->content, strlen(store->content), NULL);
|
||||
if (JS_IsObject(content))
|
||||
{
|
||||
JSValue type_value = JS_GetPropertyStr(context, content, "type");
|
||||
const char* type = JS_ToCString(context, type_value);
|
||||
JSValue text_value = JS_GetPropertyStr(context, content, "text");
|
||||
const char* text = JS_ToCString(context, text_value);
|
||||
void tf_notify_message_added_ios(const char* identifier, const char* title, const char* content);
|
||||
tf_notify_message_added_ios(store->id, type, text);
|
||||
JS_FreeCString(context, text);
|
||||
JS_FreeValue(context, text_value);
|
||||
JS_FreeCString(context, type);
|
||||
JS_FreeValue(context, type_value);
|
||||
}
|
||||
JS_FreeValue(context, content);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (store->callback)
|
||||
{
|
||||
store->callback(store->id, store->out_stored, store->user_data);
|
||||
@@ -777,6 +806,16 @@ void tf_ssb_db_store_message(
|
||||
JS_FreeValue(context, timestampval);
|
||||
|
||||
JSValue contentval = JS_GetPropertyStr(context, val, "content");
|
||||
JSValue typeval = JS_IsObject(contentval) ? JS_GetPropertyStr(context, contentval, "type") : JS_UNDEFINED;
|
||||
const char* type = JS_IsString(typeval) ? JS_ToCString(context, typeval) : NULL;
|
||||
message_type_t message_type = k_message_type_other;
|
||||
if (type)
|
||||
{
|
||||
message_type = strcmp(type, "post") == 0 ? k_message_type_post : k_message_type_other;
|
||||
}
|
||||
JS_FreeCString(context, type);
|
||||
JS_FreeValue(context, typeval);
|
||||
|
||||
JSValue content = JS_JSONStringify(context, contentval, JS_NULL, JS_NULL);
|
||||
size_t content_len;
|
||||
const char* contentstr = JS_ToCStringLen(context, &content_len, content);
|
||||
@@ -788,6 +827,7 @@ void tf_ssb_db_store_message(
|
||||
.sequence = sequence,
|
||||
.timestamp = timestamp,
|
||||
.content = contentstr,
|
||||
.type = message_type,
|
||||
.length = content_len,
|
||||
.flags = flags,
|
||||
|
||||
@@ -1557,8 +1597,10 @@ typedef struct _following_t
|
||||
int depth;
|
||||
following_t** following;
|
||||
following_t** blocking;
|
||||
following_t** both;
|
||||
int following_count;
|
||||
int blocking_count;
|
||||
int both_count;
|
||||
int ref_count;
|
||||
int block_ref_count;
|
||||
} following_t;
|
||||
@@ -1675,14 +1717,27 @@ static void _populate_follows_and_blocks(
|
||||
{
|
||||
if (_add_following_entry(&entry->following, &entry->following_count, next))
|
||||
{
|
||||
next->ref_count++;
|
||||
if (next->ref_count++ == 0 && next->block_ref_count)
|
||||
{
|
||||
if (_remove_following_entry(&entry->blocking, &entry->blocking_count, next))
|
||||
{
|
||||
_remove_following_entry(&entry->following, &entry->following_count, next);
|
||||
_add_following_entry(&entry->both, &entry->both_count, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_remove_following_entry(&entry->following, &entry->following_count, next))
|
||||
{
|
||||
next->ref_count--;
|
||||
if (next->ref_count-- == 1 && next->block_ref_count)
|
||||
{
|
||||
if (_remove_following_entry(&entry->both, &entry->both_count, next))
|
||||
{
|
||||
_add_following_entry(&entry->blocking, &entry->blocking_count, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1697,14 +1752,29 @@ static void _populate_follows_and_blocks(
|
||||
{
|
||||
if (_add_following_entry(&entry->blocking, &entry->blocking_count, next))
|
||||
{
|
||||
next->block_ref_count++;
|
||||
if (next->block_ref_count++ == 0 && next->ref_count)
|
||||
{
|
||||
if (_remove_following_entry(&entry->following, &entry->following_count, next))
|
||||
{
|
||||
next->ref_count--;
|
||||
_remove_following_entry(&entry->blocking, &entry->blocking_count, next);
|
||||
_add_following_entry(&entry->both, &entry->both_count, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_remove_following_entry(&entry->blocking, &entry->blocking_count, next))
|
||||
{
|
||||
next->block_ref_count--;
|
||||
if (next->block_ref_count-- == 1)
|
||||
{
|
||||
if (_remove_following_entry(&entry->both, &entry->both_count, next))
|
||||
{
|
||||
next->ref_count++;
|
||||
_add_following_entry(&entry->following, &entry->following_count, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1801,6 +1871,7 @@ tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, in
|
||||
{
|
||||
tf_free(following[i]->following);
|
||||
tf_free(following[i]->blocking);
|
||||
tf_free(following[i]->both);
|
||||
tf_free(following[i]);
|
||||
}
|
||||
tf_free(following);
|
||||
@@ -1852,6 +1923,7 @@ const char** tf_ssb_db_following_deep_ids(tf_ssb_t* ssb, const char** ids, int c
|
||||
{
|
||||
tf_free(following[i]->following);
|
||||
tf_free(following[i]->blocking);
|
||||
tf_free(following[i]->both);
|
||||
tf_free(following[i]);
|
||||
}
|
||||
tf_free(following);
|
||||
@@ -2186,56 +2258,40 @@ bool tf_ssb_db_identity_get_active(sqlite3* db, const char* user, const char* pa
|
||||
return found;
|
||||
}
|
||||
|
||||
typedef struct _resolve_index_t
|
||||
const char* tf_ssb_db_resolve_index(sqlite3* db, const char* host)
|
||||
{
|
||||
const char* host;
|
||||
const char* path;
|
||||
void (*callback)(const char* path, void* user_data);
|
||||
void* user_data;
|
||||
} resolve_index_t;
|
||||
const char* result = NULL;
|
||||
|
||||
static void _tf_ssb_db_resolve_index_work(tf_ssb_t* ssb, void* user_data)
|
||||
{
|
||||
resolve_index_t* request = user_data;
|
||||
|
||||
sqlite3* db = tf_ssb_acquire_db_reader(ssb);
|
||||
sqlite3_stmt* statement;
|
||||
if (sqlite3_prepare_v2(db, "SELECT json_extract(value, '$.index_map') FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
|
||||
if (!result)
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
const char* index_map = (const char*)sqlite3_column_text(statement, 0);
|
||||
const char* start = index_map;
|
||||
while (start)
|
||||
{
|
||||
const char* end = strchr(start, '\n');
|
||||
const char* equals = strchr(start, '=');
|
||||
if (equals && strncasecmp(request->host, start, equals - start) == 0)
|
||||
{
|
||||
size_t value_length = end && equals < end ? (size_t)(end - (equals + 1)) : strlen(equals + 1);
|
||||
char* path = tf_malloc(value_length + 1);
|
||||
memcpy(path, equals + 1, value_length);
|
||||
path[value_length] = '\0';
|
||||
request->path = path;
|
||||
break;
|
||||
}
|
||||
start = end ? end + 1 : NULL;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
||||
/* Maybe we need to force the EULA first. */
|
||||
}
|
||||
|
||||
if (!request->path)
|
||||
if (!result)
|
||||
{
|
||||
if (sqlite3_prepare_v2(db, "SELECT json_extract(value, '$.index') FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
|
||||
/* Use the index_map setting. */
|
||||
sqlite3_stmt* statement;
|
||||
if (sqlite3_prepare_v2(db, "SELECT json_extract(value, '$.index_map') FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
request->path = tf_strdup((const char*)sqlite3_column_text(statement, 0));
|
||||
const char* index_map = (const char*)sqlite3_column_text(statement, 0);
|
||||
const char* start = index_map;
|
||||
while (start)
|
||||
{
|
||||
const char* end = strchr(start, '\n');
|
||||
const char* equals = strchr(start, '=');
|
||||
if (equals && strncasecmp(host, start, equals - start) == 0)
|
||||
{
|
||||
size_t value_length = end && equals < end ? (size_t)(end - (equals + 1)) : strlen(equals + 1);
|
||||
char* path = tf_malloc(value_length + 1);
|
||||
memcpy(path, equals + 1, value_length);
|
||||
path[value_length] = '\0';
|
||||
result = path;
|
||||
break;
|
||||
}
|
||||
start = end ? end + 1 : NULL;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
@@ -2244,32 +2300,32 @@ static void _tf_ssb_db_resolve_index_work(tf_ssb_t* ssb, void* user_data)
|
||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
tf_ssb_release_db_reader(ssb, db);
|
||||
|
||||
if (!request->path)
|
||||
if (!result)
|
||||
{
|
||||
request->path = tf_strdup(tf_util_get_default_global_setting_string("index"));
|
||||
/* Use the index setting. */
|
||||
sqlite3_stmt* statement;
|
||||
if (sqlite3_prepare_v2(db, "SELECT json_extract(value, '$.index') FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
|
||||
{
|
||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||
{
|
||||
result = tf_strdup((const char*)sqlite3_column_text(statement, 0));
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
}
|
||||
else
|
||||
{
|
||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _tf_ssb_db_resolve_index_after_work(tf_ssb_t* ssb, int status, void* user_data)
|
||||
{
|
||||
resolve_index_t* request = user_data;
|
||||
request->callback(request->path, request->user_data);
|
||||
tf_free((void*)request->host);
|
||||
tf_free((void*)request->path);
|
||||
tf_free(request);
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
/* Use the default index. */
|
||||
result = tf_strdup(tf_util_get_default_global_setting_string("index"));
|
||||
}
|
||||
|
||||
void tf_ssb_db_resolve_index_async(tf_ssb_t* ssb, const char* host, void (*callback)(const char* path, void* user_data), void* user_data)
|
||||
{
|
||||
resolve_index_t* request = tf_malloc(sizeof(resolve_index_t));
|
||||
*request = (resolve_index_t) {
|
||||
.host = tf_strdup(host),
|
||||
.callback = callback,
|
||||
.user_data = user_data,
|
||||
};
|
||||
tf_ssb_run_work(ssb, _tf_ssb_db_resolve_index_work, _tf_ssb_db_resolve_index_after_work, request);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _tf_ssb_db_set_flags(tf_ssb_t* ssb, const char* message_id, int flags)
|
||||
@@ -2514,7 +2570,7 @@ bool tf_ssb_db_set_global_setting_from_string(sqlite3* db, const char* name, cha
|
||||
bound = sqlite3_bind_int(statement, 2, value && (strcmp(value, "true") == 0 || atoi(value))) == SQLITE_OK;
|
||||
break;
|
||||
case k_kind_int:
|
||||
bound = sqlite3_bind_int(statement, 2, atoi(value)) == SQLITE_OK;
|
||||
bound = sqlite3_bind_int64(statement, 2, atoll(value)) == SQLITE_OK;
|
||||
break;
|
||||
case k_kind_string:
|
||||
bound = sqlite3_bind_text(statement, 2, value, -1, NULL) == SQLITE_OK;
|
||||
|
||||
@@ -445,12 +445,11 @@ bool tf_ssb_db_add_value_to_array_property(tf_ssb_t* ssb, const char* id, const
|
||||
|
||||
/**
|
||||
** Resolve a hostname to its index path by global settings.
|
||||
** @param ssb The SSB instance.
|
||||
** @param db The database.
|
||||
** @param host The hostname.
|
||||
** @param callback The callback.
|
||||
** @param user_data The callback user data.
|
||||
** @return The resolved index. Free with tf_free().
|
||||
*/
|
||||
void tf_ssb_db_resolve_index_async(tf_ssb_t* ssb, const char* host, void (*callback)(const char* path, void* user_data), void* user_data);
|
||||
const char* tf_ssb_db_resolve_index(sqlite3* db, const char* host);
|
||||
|
||||
/**
|
||||
** Verify an author's feed.
|
||||
|
||||
@@ -639,8 +639,14 @@ void tf_ssb_test_following(const tf_test_options_t* options)
|
||||
message = JS_NewObject(context); \
|
||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "contact")); \
|
||||
JS_SetPropertyStr(context, message, "contact", JS_NewString(context, contact)); \
|
||||
JS_SetPropertyStr(context, message, "following", follow ? JS_TRUE : JS_FALSE); \
|
||||
JS_SetPropertyStr(context, message, "blocking", block ? JS_TRUE : JS_FALSE); \
|
||||
if (follow) \
|
||||
{ \
|
||||
JS_SetPropertyStr(context, message, "following", JS_TRUE); \
|
||||
} \
|
||||
if (block) \
|
||||
{ \
|
||||
JS_SetPropertyStr(context, message, "blocking", JS_TRUE); \
|
||||
} \
|
||||
signed_message = tf_ssb_sign_message(ssb0, id, priv, message, NULL, 0); \
|
||||
stored = false; \
|
||||
tf_ssb_verify_strip_and_store_message(ssb0, signed_message, _message_stored, &stored); \
|
||||
@@ -660,6 +666,11 @@ void tf_ssb_test_following(const tf_test_options_t* options)
|
||||
_assert_visible(ssb0, id0, id1, true);
|
||||
_assert_visible(ssb0, id0, id2, true);
|
||||
_assert_visible(ssb0, id0, id3, false);
|
||||
FOLLOW_BLOCK(id0, priv0, id1, false, true);
|
||||
_assert_visible(ssb0, id0, id0, true);
|
||||
_assert_visible(ssb0, id0, id1, false);
|
||||
_assert_visible(ssb0, id0, id2, false);
|
||||
_assert_visible(ssb0, id0, id3, false);
|
||||
|
||||
#undef FOLLOW_BLOCK
|
||||
|
||||
|
||||
@@ -338,6 +338,7 @@ static const setting_t k_settings[] = {
|
||||
.type = "boolean",
|
||||
.description = "Whether to attempt to keep several peer connections open.",
|
||||
.default_value = { .kind = k_kind_bool, .bool_value = false } },
|
||||
{ .name = "accepted_eula_version", .type = "hidden", .description = "The version of the last accepted EULA.", .default_value = { .kind = k_kind_int, .int_value = 0 } },
|
||||
};
|
||||
|
||||
static const setting_t* _util_get_setting(const char* name, tf_setting_kind_t kind)
|
||||
|
||||
@@ -132,6 +132,12 @@ try:
|
||||
size = driver.get_window_size()
|
||||
driver.set_window_size(1200, 540)
|
||||
driver.save_screenshot('out/screenshot0.png')
|
||||
driver.set_window_size(1252, 2807)
|
||||
driver.save_screenshot('out/ios0.png')
|
||||
driver.set_window_size(2688 + 10, 1242 + 119)
|
||||
driver.save_screenshot('out/ios2.png')
|
||||
driver.set_window_size(2064 + 10, 2752 + 119)
|
||||
driver.save_screenshot('out/ios4.png')
|
||||
driver.set_window_size(size['width'], size['height'])
|
||||
|
||||
select(driver, ['#editor', '.cm-content'], ('click',))
|
||||
@@ -156,6 +162,12 @@ try:
|
||||
size = driver.get_window_size()
|
||||
driver.set_window_size(540, 1200)
|
||||
driver.save_screenshot('out/screenshot1.png')
|
||||
driver.set_window_size(1252, 2807)
|
||||
driver.save_screenshot('out/ios1.png')
|
||||
driver.set_window_size(2688 + 10, 1242 + 119)
|
||||
driver.save_screenshot('out/ios3.png')
|
||||
driver.set_window_size(2064 + 10, 2752 + 119)
|
||||
driver.save_screenshot('out/ios5.png')
|
||||
driver.set_window_size(size['width'], size['height'])
|
||||
|
||||
select(driver, ['#document', 'frame', '=identity'], ('click',))
|
||||
|
||||
Reference in New Issue
Block a user