feat(meditate): Meditate's server, its sealed tables, and SimpleLogin's way back to it
halkyon_meditate_server and its generated client, copied from Todo's
and stripped to the module, the register and the sync engine (ADR 0038,
D1, D7): content_key, meditate_settings and sitting, synced and sealed,
each indexing spaceId and deleted with the person's space; two
migrations, the initial one and sittings (purely additive, the ADR
explains the SQL); ports 8280 to 8282 and PostgreSQL 8290 (D13).
Tests: the module's basics naming `meditate`, the sync engine refusing
calls without a session, the register's modes, and a person's deletion
taking their rows alone.
halkyon_base's forwarding page knows Meditate's ways back
(meditate-loopback on 43826, meditate-scheme app.halkyon.meditate),
which halkyon_app's repository names among the apps' ports.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-03 09:25:30 +01:00
|
|
|
|
import 'package:halkyon_base_server/base.dart';
|
|
|
|
|
|
import 'package:halkyon_meditate_server/src/meditate_data.dart';
|
|
|
|
|
|
|
|
|
|
|
|
/// Where this project's source is published, which the instance names
|
|
|
|
|
|
/// unless its operator sets `SOURCE_URL`. Both licences require offering it
|
|
|
|
|
|
/// to the people who use the instance (AGPL-3.0-or-later for the app,
|
|
|
|
|
|
/// SSPL-1.0 for the server).
|
|
|
|
|
|
const upstreamSourceCodeUrl =
|
|
|
|
|
|
'https://code.halkyon.app/project-halkyon/halkyon';
|
|
|
|
|
|
|
|
|
|
|
|
/// The oldest build of the app this server works with (the number after `+`
|
|
|
|
|
|
/// in the app's version); apps below it are asked to update. Raise it in the
|
|
|
|
|
|
/// commit that breaks older apps, to the build of the first that works again.
|
|
|
|
|
|
const minimumAppBuild = 1;
|
|
|
|
|
|
|
|
|
|
|
|
/// How Halkyon Meditate sets halkyon_base up (ADR 0014), the module giving every
|
|
|
|
|
|
/// Halkyon server its sign-in, the account and its deletion, the pruning and
|
|
|
|
|
|
/// the instance's basics: the instance says it serves `meditate` (the app accepts
|
|
|
|
|
|
/// only such an instance; never change it), sign-in mails name the app, and
|
|
|
|
|
|
/// the instance names this project's source. A person's sittings and keys go
|
|
|
|
|
|
/// with them ([deleteMeditateData]). It holds the instance's
|
|
|
|
|
|
/// register, or is a member of the one [accounts] names (ADR 0016; the
|
|
|
|
|
|
/// server reads it from the operator's environment, `ACCOUNT_REGISTER_URL`).
|
|
|
|
|
|
/// The server sets it up before it starts (`server.dart`), and so do its
|
|
|
|
|
|
/// tests.
|
|
|
|
|
|
HalkyonBase meditateBase({AccountsMode accounts = const HoldsRegister()}) =>
|
|
|
|
|
|
HalkyonBase(
|
|
|
|
|
|
app: 'meditate',
|
|
|
|
|
|
appName: 'Halkyon Meditate',
|
|
|
|
|
|
upstreamSourceCodeUrl: upstreamSourceCodeUrl,
|
|
|
|
|
|
minimumAppBuild: minimumAppBuild,
|
|
|
|
|
|
deletePersonData: const [deleteMeditateData],
|
|
|
|
|
|
accounts: accounts,
|
2026-11-03 14:47:35 +01:00
|
|
|
|
privacyPagePoints: _privacyPagePoints,
|
feat(meditate): Meditate's server, its sealed tables, and SimpleLogin's way back to it
halkyon_meditate_server and its generated client, copied from Todo's
and stripped to the module, the register and the sync engine (ADR 0038,
D1, D7): content_key, meditate_settings and sitting, synced and sealed,
each indexing spaceId and deleted with the person's space; two
migrations, the initial one and sittings (purely additive, the ADR
explains the SQL); ports 8280 to 8282 and PostgreSQL 8290 (D13).
Tests: the module's basics naming `meditate`, the sync engine refusing
calls without a session, the register's modes, and a person's deletion
taking their rows alone.
halkyon_base's forwarding page knows Meditate's ways back
(meditate-loopback on 43826, meditate-scheme app.halkyon.meditate),
which halkyon_app's repository names among the apps' ports.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-03 09:25:30 +01:00
|
|
|
|
);
|
2026-11-03 14:47:35 +01:00
|
|
|
|
|
|
|
|
|
|
/// What the instance's privacy page says of Meditate's data (ADR 0038, D7,
|
|
|
|
|
|
/// D14, D15), where Meditate's server serves the page: what is sealed, and
|
|
|
|
|
|
/// what a dream spoken passes through. Change it with what Meditate keeps
|
|
|
|
|
|
/// or sends.
|
|
|
|
|
|
const List<PrivacyPagePoint> _privacyPagePoints = [
|
|
|
|
|
|
(
|
|
|
|
|
|
english:
|
|
|
|
|
|
'On Halkyon Meditate, your settings, the sittings you keep and the '
|
|
|
|
|
|
'dreams you write down are encrypted on your devices with your key: '
|
|
|
|
|
|
'the instance sees how many there are, their size and when they '
|
|
|
|
|
|
'changed, never what they hold. A device that can’t encrypt keeps '
|
|
|
|
|
|
'none.',
|
|
|
|
|
|
german:
|
|
|
|
|
|
'In Halkyon Meditate werden deine Einstellungen, die Sitzungen, die '
|
|
|
|
|
|
'du aufbewahrst, und die Träume, die du aufschreibst, auf deinen '
|
|
|
|
|
|
'Geräten mit deinem Schlüssel verschlüsselt: Die Instanz sieht, wie '
|
|
|
|
|
|
'viele es sind, wie groß sie sind und wann sie sich änderten, nie, '
|
|
|
|
|
|
'was sie enthalten. Ein Gerät, das nicht verschlüsseln kann, bewahrt '
|
|
|
|
|
|
'keine auf.',
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
2026-11-03 16:47:23 +01:00
|
|
|
|
english:
|
|
|
|
|
|
'Where this instance offers a library of recordings, only people '
|
|
|
|
|
|
'signed in get it. Fetching a recording names no account: your '
|
|
|
|
|
|
'device shows an access the instance signed alike for everyone it '
|
|
|
|
|
|
'gave the library to within the same hour, so beyond the address a '
|
|
|
|
|
|
'request comes from, the instance can’t tell who listens to what. '
|
|
|
|
|
|
'What you listened to, your favourites and the lessons you did are '
|
|
|
|
|
|
'sealed with your key as your sittings are.',
|
|
|
|
|
|
german:
|
|
|
|
|
|
'Wo diese Instanz eine Bibliothek mit Aufnahmen anbietet, bekommen '
|
|
|
|
|
|
'sie nur angemeldete Personen. Eine Aufnahme zu laden nennt kein '
|
|
|
|
|
|
'Konto: Dein Gerät zeigt eine Zugangsberechtigung, die die Instanz '
|
|
|
|
|
|
'allen gleich signiert, denen sie die Bibliothek in derselben Stunde '
|
|
|
|
|
|
'gab. Über die Adresse hinaus, von der eine Anfrage kommt, weiß die '
|
|
|
|
|
|
'Instanz also nicht, wer was hört. Was du gehört hast, deine '
|
|
|
|
|
|
'Favoriten und die Lektionen, die du gemacht hast, werden wie deine '
|
|
|
|
|
|
'Sitzungen mit deinem Schlüssel verschlüsselt.',
|
|
|
|
|
|
),
|
|
|
|
|
|
(
|
2026-11-03 14:47:35 +01:00
|
|
|
|
english:
|
|
|
|
|
|
'A dream you speak is written by your device’s own speech '
|
feat(learn,todo,meditate): dictate through the phone's voice input app (ADR 0038, D18)
On Android the microphone now opens the app handling
RECOGNIZE_SPEECH (FUTO Voice Input, Google's), the default the person
chose in Android, and puts the text it returns where the cursor stood,
as Dictation does; cancelled, nothing. Only where none is installed, or
it can't be opened, does speech_to_text listen in line as before.
halkyon_app: VoiceInputApp (one listen, an answer once closed) on the
channel app.halkyon/voice_input, which DeviceSpeechInput asks first at
every listen, answering SpeechStart.finished so that Dictation doesn't
listen again; speech_to_text isn't touched on that route, so our app
asks for no microphone. SpeechInput.listen and Dictation.start take the
prompt the voice input app shows (the field's hint).
Each app: VoiceInput.kt (queryIntentActivities, startActivityForResult,
the first of EXTRA_RESULTS) attached in MainActivity, which hands it
activity results, and RECOGNIZE_SPEECH among the manifest's queries.
The privacy pages of Learn and Meditate say so.
Our own Whisper and Meditate's dream recordings are dropped (D18).
Whats-New: The microphone now dictates through your phone's voice input app, such as FUTO Voice Input.
Whats-New-De: Das Mikrofon diktiert jetzt über die Spracheingabe-App deines Telefons, etwa FUTO Voice Input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-07 23:45:20 +01:00
|
|
|
|
'recognition. On Android, where a voice input app is installed '
|
|
|
|
|
|
'(FUTO Voice Input, for one), that app listens and hands Meditate '
|
|
|
|
|
|
'the text alone, and it decides whether the sound leaves the device; '
|
|
|
|
|
|
'without one, Meditate asks for recognition on the '
|
2026-11-03 14:47:35 +01:00
|
|
|
|
'device, which Android 12 and later offer where the language is '
|
|
|
|
|
|
'installed; otherwise Android’s recogniser may send the sound to '
|
|
|
|
|
|
'Google or the phone’s maker. Apple’s and Windows’ recognisers decide '
|
|
|
|
|
|
'for themselves whether the sound leaves the device. It never reaches '
|
|
|
|
|
|
'the instance.',
|
|
|
|
|
|
german:
|
|
|
|
|
|
'Einen Traum, den du erzählst, schreibt die Spracherkennung deines '
|
feat(learn,todo,meditate): dictate through the phone's voice input app (ADR 0038, D18)
On Android the microphone now opens the app handling
RECOGNIZE_SPEECH (FUTO Voice Input, Google's), the default the person
chose in Android, and puts the text it returns where the cursor stood,
as Dictation does; cancelled, nothing. Only where none is installed, or
it can't be opened, does speech_to_text listen in line as before.
halkyon_app: VoiceInputApp (one listen, an answer once closed) on the
channel app.halkyon/voice_input, which DeviceSpeechInput asks first at
every listen, answering SpeechStart.finished so that Dictation doesn't
listen again; speech_to_text isn't touched on that route, so our app
asks for no microphone. SpeechInput.listen and Dictation.start take the
prompt the voice input app shows (the field's hint).
Each app: VoiceInput.kt (queryIntentActivities, startActivityForResult,
the first of EXTRA_RESULTS) attached in MainActivity, which hands it
activity results, and RECOGNIZE_SPEECH among the manifest's queries.
The privacy pages of Learn and Meditate say so.
Our own Whisper and Meditate's dream recordings are dropped (D18).
Whats-New: The microphone now dictates through your phone's voice input app, such as FUTO Voice Input.
Whats-New-De: Das Mikrofon diktiert jetzt über die Spracheingabe-App deines Telefons, etwa FUTO Voice Input.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-07 23:45:20 +01:00
|
|
|
|
'Geräts auf. Unter Android hört, wo eine Spracheingabe-App '
|
|
|
|
|
|
'installiert ist (etwa FUTO Voice Input), diese App zu und gibt '
|
|
|
|
|
|
'Meditate nur den Text; ob der Ton das Gerät verlässt, entscheidet '
|
|
|
|
|
|
'sie. Ohne eine bittet Meditate um Erkennung auf dem '
|
2026-11-03 14:47:35 +01:00
|
|
|
|
'Gerät, die Android ab Version 12 bietet, wo die Sprache installiert '
|
|
|
|
|
|
'ist; sonst kann Androids Spracherkennung den Ton an Google oder den '
|
|
|
|
|
|
'Hersteller des Telefons senden. Die Spracherkennung von Apple und '
|
|
|
|
|
|
'Windows entscheidet selbst, ob der Ton das Gerät verlässt. Bei der '
|
|
|
|
|
|
'Instanz kommt er nie an.',
|
|
|
|
|
|
),
|
|
|
|
|
|
];
|