Commit graph

2960 commits

Author SHA1 Message Date
Wavesonics
322bbff65c Bump jwt to 2.10.3 for CVE-2026-45363 and pin android-emulator-runner to a commit SHA 2026-06-06 15:42:35 -07:00
Adam Brown
4b6004f567
Add Dark Rock Studios section to README
Added a section about Dark Rock Studios and community engagement.
2026-06-06 15:05:33 -07:00
Wavesonics
88016d2ed4 Tests for ProjectsListComponent 2026-06-06 12:15:39 -07:00
Wavesonics
f2069440fd ComponentTest (the harness) gained two things:
- protected open val projectDef — the ProjectDef("Test", HPath(...)) that was copy-pasted in all four component tests now lives once in the base (open, so a test can override if needed).
  - setupComponentKoin(module) — wraps setupKoin and auto-registers the relaxed TagIndexService that every ProjectComponentBase component injects. This removes the per-test boilerplate and permanently fixes the "easy to
  forget" inconsistency the review flagged (SceneEditor had been missing it).
2026-06-06 12:02:37 -07:00
Wavesonics
dcfec0bf6f Added tests to the SceneEditor Components 2026-06-06 11:25:49 -07:00
Wavesonics
7d8a7f22a5 New Componet test harness
Added tests to the Notes Components
2026-06-06 10:33:37 -07:00
Wavesonics
4a13eb7f1f Rounding out our domain layer tests 2026-06-06 09:17:09 -07:00
Adam Brown
a600b6199d
New Crowdin updates (#556)
* New translations messages_en.properties (French)

[ci skip]

* New translations messages_en.properties (Spanish)

[ci skip]

* New translations messages_en.properties (German)

[ci skip]

* New translations messages_en.properties (Italian)

[ci skip]

* New translations messages_en.properties (Ukrainian)

[ci skip]

* New translations messages_en.properties (Chinese Simplified)

[ci skip]

* New translations messages_en.properties (Portuguese, Brazilian)

[ci skip]
2026-06-06 01:26:32 -07:00
Adam Brown
d9979a654b
Extract EncyclopediaService; make it the single door for UI (#560)
EncyclopediaRepository reached sideways into StatisticsRepository and
ReferenceIndexRepository (markDirty / markEntryDeleted on entry writes).
Hoist that orchestration into a new EncyclopediaService, mirroring how
SceneEditorService owns the same side-effects for scenes. The repository
is now pure data with no sibling-repo deps; the three write call-sites
(CreateEntryComponent, ViewEntryComponent, ClientEncyclopediaSynchronizer)
route writes through the service, reads stay on the repository.
2026-06-06 01:26:20 -07:00
Adam Brown
86267a1503
refactor: decouple SceneRepository — compose SceneSummary in SceneEditorService (#559)
SceneRepository drops its sibling-repo deps and emits a tree-only flow; SceneContentRepository exposes a dirtyBufferIds StateFlow; SceneEditorService composes the scene list (combine) and owns init orchestration. Dirty markers now update reactively.
2026-06-06 01:23:41 -07:00
Adam Brown
d1e265a44c
Add Foundation primitives tier; rename Id/Sync/Settings repos (#558)
* Rename IdRepository to IdAllocator
It is a special foundational primative

* Rename SyncDataRepository to SyncJournal
It is a special foundational primative

* Rename GlobalSettingsRepository to GlobalSettingsStore
It is a special foundational primitive

* docs: add Foundation primitives tier to the architecture doc

Document IdAllocator, SyncJournal, and GlobalSettingsStore as a fixed set of
stateful, cross-cutting primitives that the whole data layer may depend on —
acyclic leaves (GlobalSettingsStore <- SyncJournal <- IdAllocator) that named
the dependency reality instead of treating it as a no-sibling violation.
2026-06-06 01:17:13 -07:00
Adam Brown
fb5251fe83
Replace GlobalSearchRepository with SearchProjectUseCase + retained state (#557)
GlobalSearchRepository was a stateful class masquerading as a Repository while
fanning out across six repositories — really cross-repo coordination with UI
state bolted on. Split it to match the layering:

- SearchProjectUseCase: stateless cross-repo search (data layer)
- GlobalSearchState: component-layer holder (state + debounce), retained on
  ProjectRootComponent via InstanceKeeper so search survives the modal being
  dismissed/reopened and config changes; stateKeeper carries query+filter
  across process death
- GlobalSearchComponent: thin presenter delegating to the holder

Search state now lives in the component layer instead of a project-scoped
singleton, and MutableValue updates run on the main thread (the use case
offloads its fan-out to the default dispatcher).
2026-06-06 01:08:17 -07:00
Adam Brown
bc1a66fc1e
Decompose SceneEditorRepository into focused repositories + a service facade
Split the monolithic SceneEditorRepository into single-responsibility pieces:

- SceneRepository — scene tree, structure, ordering, paths, on-disk layout
- SceneContentRepository — in-memory buffers, autosave, dirty tracking
- SceneMetadataRepository — per-scene and project metadata
- SceneEditorService — the component-facing facade that orchestrates the three
and applies the cross-cutting side-effects (statistics, writing activity,
reference index) the repositories deliberately don't reach up to perform

Components and synchronizers now talk to SceneEditorService; the underlying
repositories hold no sibling-repo dependencies. Tests are reorganized to match
the new boundaries, and the scene-editing domain API is documented in 
docs/DESIGN_PATTERNS.md.
2026-06-06 00:57:35 -07:00
Adam Brown
db4343d8f1
Adds a full monitoring subsystem to the server admin panel
- Data foundation: SQLDelight tables for API metrics, error logs, and
login attempts with a v1→v2 schema migration
- Metrics pipeline: per-endpoint request counts, latency, and error
rates collected via a Ktor plugin; daily rollup job with configurable
retention windows
- Error tracking: fingerprinted deduplication, occurrence counts,
first/last seen timestamps, and email alerting on persistent errors
- Security page: login-attempt tracking, brute-force/spray detection
with cooldown alerts, optional IP storage
- Admin dashboard UI: performance charts (Frappe), error panel with
route filter and JSON export, live log viewer (10k ring buffer),
security event feed
- Alert deep-links from the dashboard into filtered error views
- Settings UI: all monitoring options converted to toggle switches;
master switch disables and grays out sub-options via JS; email field
conditionally required with htmx:before-request validation
2026-06-05 19:19:11 -07:00
Wavesonics
80022fa590 Add iOS and MacOS store metadata 2026-06-05 00:06:35 -07:00
Wavesonics
8acee3835c Fix iOS and MacOS fastlane
They need their changelog written
2026-06-05 00:06:21 -07:00
Adam Brown
cd48c3289e
Allow more run-time config of umami 2026-06-04 23:04:35 -07:00
Wavesonics
97bc5a1b1a Prepared for release: v3.1.3 2026-06-04 21:56:12 -07:00
Wavesonics
08ebef7098 Downgrade core-ktx to 1.16.0 to unblock release
1.19.0 requires compileSdk 37 and AGP 9.1.0 which we're not ready to bump yet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 21:51:48 -07:00
Wavesonics
0f7f2d6657 revertLastRelease now also removes the github release 2026-06-04 21:49:57 -07:00
Wavesonics
c799efb25c Add iOS build to CI 2026-06-04 20:36:56 -07:00
Adam Brown
38bf8bbcdc
New Crowdin updates (#547)
* New translations strings_desktop.xml (French)

[ci skip]

* New translations strings_desktop.xml (Spanish)

[ci skip]

* New translations strings_desktop.xml (German)

[ci skip]

* New translations strings_desktop.xml (Italian)

[ci skip]

* New translations strings_desktop.xml (Ukrainian)

[ci skip]

* New translations strings_desktop.xml (Chinese Simplified)

[ci skip]

* New translations strings_desktop.xml (Portuguese, Brazilian)

[ci skip]

* New translations strings_projects_list.xml (French)

[ci skip]

* New translations strings_sync.xml (French)

[ci skip]

* New translations strings_projects_list.xml (Spanish)

[ci skip]

* New translations strings_sync.xml (Spanish)

[ci skip]

* New translations strings_projects_list.xml (German)

[ci skip]

* New translations strings_sync.xml (German)

[ci skip]

* New translations strings_projects_list.xml (Italian)

[ci skip]

* New translations strings_sync.xml (Italian)

[ci skip]

* New translations strings_projects_list.xml (Ukrainian)

[ci skip]

* New translations strings_sync.xml (Ukrainian)

[ci skip]

* New translations strings_projects_list.xml (Chinese Simplified)

[ci skip]

* New translations strings_sync.xml (Chinese Simplified)

[ci skip]

* New translations strings_projects_list.xml (Portuguese, Brazilian)

[ci skip]

* New translations strings_sync.xml (Portuguese, Brazilian)

[ci skip]
2026-06-04 20:33:11 -07:00
Wavesonics
73f31859c1 For patch releases, pull the previous changelog 2026-06-04 19:49:38 -07:00
Wavesonics
0de5e5711c Enable Apple store targets to actually publish 2026-06-04 19:43:40 -07:00
Wavesonics
4bb4c9501e Update compose-texteditor
Fix for markdown syntax sneaking through into rich text
2026-06-04 19:19:25 -07:00
Wavesonics
4e62f34acc Update compose-texteditor
Fix for markdown syntax sneaking through into rich text
2026-06-04 18:05:28 -07:00
Wavesonics
b4a077c739 Fix restored mid-edit drafts being silently discarded
ViewNote/ViewTimeLineEvent come back from process death with isEditing=true
  and the restored draft, but the note/event isn't loaded yet (async, or cold
  cache). In that window isEditingAndDirty() returned false, so a back-press or
  close took the silent discardEdit() path and wiped the restored text.

  Treat "editing with no loaded baseline" as dirty so those paths route to the
  confirm-discard dialog instead. Behavior is unchanged once loaded.
2026-06-04 18:00:17 -07:00
Wavesonics
e477e0de04 Correct some saved state 2026-06-04 17:44:30 -07:00
Wavesonics
b39fc05a4c More Saveable components
These will allow unsaved user input to survive process death even
2026-06-04 17:36:10 -07:00
Adam Brown
04a9772d03
Expand Android instrumented UI test coverage across editor screens (#553)
Add a reusable EditorTestHarness (seed a project via Koin, launch straight
into ProjectRootActivity, navigate, tear down without racing the scope flush)
and one happy-path instrumented test per feature area: navigation smoke,
scene list/editor, notes, encyclopedia, timeline, project home, and global
search.

To make the UI addressable, add optional testTag params to shared design-system
components (FormField, MarkdownEditField, HdHairlineField/TagField/SearchField/
TypePicker, HdBottomBar/HdNavRail) and colocated testTag consts on the relevant
screens. The custom text editor consumes key events rather than Compose SetText
semantics, so the harness types into it via injected keystrokes.

All 9 new tests pass on an api-34 emulator.
2026-06-04 00:20:52 -07:00
Adam Brown
da516e1772
Android e2e UI test harness (on-device project lifecycle) (#516)
ProjectLifecycleTest launches the real ProjectSelectActivity, creates a project,
waits for it to appear in the list, and confirms opening it launches
ProjectRootActivity (via ActivityMonitor). Cleans up in @After.

- Wire jetbrains-compose ui-test-junit4 into the androidTest source set.
- Tag the create-project affordance (CreateProjectButtonTestTag); "Create
  Project" otherwise appears as three separate on-screen texts.
- Run the instrumented suite on an emulator in CI (android-emulator-runner) with
  AVD snapshot caching.
- Convert HashTest from JUnit Jupiter to JUnit4 so the AndroidJUnit4 runner can
  execute it on-device (it had "no runnable methods" otherwise); use assertEquals
  since assert() is a no-op when assertions are disabled on a device. It now
  verifies EntityHasher's golden vector on Android ART.
- Fix a scope-close crash: getSceneBufferDirectory used a non-recursive
  createDirectory, so closing a project whose scenes/ dir is absent threw on the
  teardown path and crashed the process. Use createDirectories (matching its
  siblings) and order the test teardown so it doesn't delete the project mid-close.
2026-06-03 22:11:14 -07:00
Adam Brown
0c1e246aa1
Fix cloud hosted umami 2026-06-03 00:53:51 -07:00
Adam Brown
35ecc7b750
Prepared for release: v3.1.2 2026-06-03 00:37:43 -07:00
Adam Brown
6fd56b4699
fix: unzip compiles for Kotlin/Native (iOS archive) (#550)
ZipUtils.unzipBytesToDirectory used fileSystem.sink(target).buffer(),
where okio's Sink.buffer() failed to resolve for the iOS/native target
(receiver type mismatch), cascading into a 'cannot infer R' error on the
following .use{} and failing the iOS archive. Compiled fine for JVM, so
it only surfaced in the iOS publish workflow.

Use okio's multiplatform FileSystem.write(target) { } helper, which
yields a BufferedSink directly and handles buffering + closing. Verified
with :common:compileKotlinIosArm64.
2026-06-02 23:34:59 -08:00
Adam Brown
0fbaaf8390
ci: remove Mac App Store dry-run scaffolding (#549)
The dry run served its purpose (verified the pipeline and surfaced the
two-cert signing bug, now fixed in publish-mac-app-store.yml). Drop the
dry-run workflow and its desktop_build_only lane; keep only the fix.
2026-06-02 23:31:36 -08:00
Adam Brown
46f8b30524
Mac App Store: dry-run workflow + two-cert signing fix (#548)
* ci: add Mac App Store dry-run lane and workflow

Adds a way to exercise the Mac App Store build/sign/package pipeline
without releasing anything to App Store Connect.

- fastlane: new `mac desktop_build_only` lane builds, signs, and verifies
  the .pkg (via build-appstore.sh) but skips the App Store Connect build
  number lookup and the upload — no API key needed.
- workflow: new "Dry Run — Mac App Store" (workflow_dispatch) mirrors the
  real publish workflow's keychain + provisioning-profile setup, runs the
  build-only lane, and saves the .pkg as an artifact instead of uploading.

Verified locally: lane builds + passes codesign/pkgutil checks.

* ci: temporarily trigger mac dry-run on push to its branch

workflow_dispatch requires the workflow to exist on the default branch
before it can be dispatched. Add a branch-scoped push trigger so the dry
run can be exercised now; remove before merging.

* ci: import Mac signing certs from two separate p12 files

macOS `security import` only ingests one identity from a combined
multi-key .p12 (which one wins is non-deterministic), so a single secret
holding both the Application and Installer certs left one of them missing
from the CI keychain — caught by the dry run, which failed with "Mac
Installer Distribution certificate not found".

Import the Application and Installer certs from their own single-identity
.p12 files instead. Adds a second secret, MAC_INSTALLER_CERT_P12_BASE64.
Applied to both the dry-run and the real publish-mac-app-store workflows.

* ci: drop temporary push trigger from mac dry-run workflow

The dry run was triggered via a branch-scoped push trigger because
workflow_dispatch only works once the workflow exists on the default
branch. Now that it's merging to develop, revert to workflow_dispatch
only.
2026-06-02 23:29:42 -08:00
Wavesonics
f763066f69 raise timeout 2026-06-02 21:30:18 -07:00
Adam Brown
c026fd852b
Project Sync dialog improvements
- Conflicted projects now properly report has failing
- Allow filtering of sync log by project
2026-06-02 21:12:09 -07:00
Adam Brown
abac7b5bda
Restructure compact project row metadata into an aligned greeble grid
The phone project-list row showed created/opened/words as one flowing mono
line that wrapped at arbitrary points. Replace it with equal-weight
label/value columns so the fields align down the whole list, with faint
captions over muted values to keep the title the only bright anchor.
2026-06-02 21:12:09 -07:00
Adam Brown
2cf4afba8e
Fix sync wedge: phantom newIds and ID-conflict collision guard
Resolves the "Entity X not found for reId" failure that wedged every
project sync. Three related fixes:

- EntitySynchronizers.reIdEntry now skips a newId with no backing entity
  (logged) instead of throwing. The throw aborted sync before finalize,
  and finalize is the only place newIds is cleared, so a single phantom
  deadlocked every future sync. Skipping lets sync finish and self-heal.

- SyncDataRepository.recordIdDeletion prunes the id from newIds when the
  entity was never synced, instead of only appending to deletedIds. This
  stops create-then-delete from leaving a permanent phantom newId behind.

- IdConflictResolutionOperation seeds new-id assignment from
  max(serverLastId, localMaxId). If the server ever reports a lastId
  below the client max (server-side data loss), seeding from serverLastId
  alone handed out ids that collided with and clobbered real local
  entities. Now logs a WARN and assigns above the local max.

Tests reproduce each failure first, then pass after the fix.
2026-06-02 21:12:09 -07:00
Adam Brown
590c9971ca
Restyle server re-auth dialog with design system 2026-06-02 21:12:08 -07:00
Adam Brown
b284a45d89
Handle non-success GitHub responses in version check
Avoids a MissingFieldException when the releases endpoint returns a
rate-limit/error body instead of a release.
2026-06-02 21:12:08 -07:00
Adam Brown
43d5389be4
Fix Auto-sync and Close-sync-dialog toggles not reflecting state
The settings updates collector rebuilt component state without copying
syncAutomaticSync or syncAutoCloseDialog, so toggling either checkbox
persisted the change but never updated the UI. Also removes leftover
debug logging.
2026-06-02 21:12:08 -07:00
Wavesonics
d4502dc227 MacOS sandboxing 2026-06-02 20:54:18 -07:00
Wavesonics
fd8f857001 Merge branch 'macos-sandboxing' into develop
# Conflicts:
#	common/src/commonMain/composeResources/values/strings_desktop.xml
2026-06-02 20:52:18 -07:00
Wavesonics
fcf25c8caf Merge branch 'macos-sandboxing' into develop
# Conflicts:
#	common/src/commonMain/composeResources/values/strings_desktop.xml
2026-06-02 20:50:21 -07:00
Wavesonics
0fe9dc8ea8 Strings 2026-06-02 20:49:50 -07:00
Wavesonics
f392b06ba2 MacOS publish fixes 2026-06-02 20:49:08 -07:00
Adam Brown
6c705d11bb
Prepared for release: v3.1.1 2026-06-02 00:29:07 -07:00
Adam Brown
afcef30793
Build fix: Update ProjectEntityDatabaseDatasource factory 2026-06-02 00:27:58 -07:00