From 5cb1f5a317ac2561cea23c49047574c07e1f8656 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 5 Sep 2026 15:49:28 +0800 Subject: [PATCH 1/2] fix(core): switch dev Supabase key to cnsupa --- README.md | 14 +++++++++++++- docs/daemon.md | 6 ++++++ flicknote-core/src/config.rs | 10 ++++++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f878e41..dc89c3c 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,11 @@ flicknote daemon restart `flicknote login` authenticates and then installs, starts, and verifies the user daemon. `flicknote logout` stops and uninstalls it before clearing the session and local database. -Use `--force` only for explicit recovery when cleanup cannot be confirmed: +After upgrading an existing dev installation for the cnsupa authentication cutover, +run `flicknote login --force` once. This stops and uninstalls the existing daemon, +replaces the old session, and installs, starts, and verifies the daemon again. It +does not delete the local database. `flicknote logout --force` is reserved for +explicit recovery when service cleanup cannot be confirmed: ```bash flicknote login --force @@ -180,6 +184,14 @@ Environment variables: - `FLICKNOTE_API_URL` — API Worker base URL for share links - `FLICKNOTE_GATEWAY_URL` — Gateway origin for attachment operations and `gateway request` +For the default `dev` environment, `FLICKNOTE_SUPABASE_KEY` uses the opaque +cnsupa publishable key +(`sb_publishable_4VEs5DX9YlkHuViFbmRMQb_f_LPrdOR`), not the retired JWT-shaped +anon key. The value is sent through Supabase's existing `apikey` header. +Existing dev users must upgrade and run `flicknote login --force` once to +replace the old session before normal sync; explicit config-file and environment +key overrides continue to work for custom environments. + `apiUrl` and `gatewayUrl` can also be set in `config.json`. After changing either value, restart the daemon with `flicknote daemon restart`. Configure the two endpoint values together; setting only one is rejected. diff --git a/docs/daemon.md b/docs/daemon.md index 11d2694..faa9529 100644 --- a/docs/daemon.md +++ b/docs/daemon.md @@ -42,6 +42,12 @@ local state while reporting the unresolved service cleanup. removing the old session. A failed forced authentication does not restore the old session or service. +After upgrading an existing dev installation for the cnsupa cutover, run +`flicknote login --force` once before normal sync. The forced login then +authenticates with the opaque publishable key and installs, starts, and verifies +the daemon through the existing lifecycle. It does not automatically delete the +local PowerSync database or perform a release or deployment. + ## Service commands The same commands select a user-level launchd service on macOS and a user-level diff --git a/flicknote-core/src/config.rs b/flicknote-core/src/config.rs index f03a31e..3d5a33a 100644 --- a/flicknote-core/src/config.rs +++ b/flicknote-core/src/config.rs @@ -218,7 +218,7 @@ fn builtin_defaults(env: &str) -> EndpointDefaults { ), _ => ( "https://dev-auth.flicknote.app", - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzY1NTM1NTg4LCJleHAiOjE5MjMyMTU1ODh9.7ErMPvghlVm6mew-IKjSShP1Lf6wTCbNgs9ufuh3yqo", + "sb_publishable_4VEs5DX9YlkHuViFbmRMQb_f_LPrdOR", "https://dev-sync.flicknote.app", "https://dev-api.flicknote.app/api/v1", "https://dev-gw.flicknote.app", @@ -281,7 +281,10 @@ mod tests { assert_eq!(defaults.powersync_url, "https://dev-sync.flicknote.app"); assert_eq!(defaults.api_url, "https://dev-api.flicknote.app/api/v1"); assert_eq!(defaults.gateway_url, "https://dev-gw.flicknote.app"); - assert!(!defaults.supabase_anon_key.is_empty()); + assert_eq!( + defaults.supabase_anon_key, + "sb_publishable_4VEs5DX9YlkHuViFbmRMQb_f_LPrdOR" + ); } #[test] @@ -304,6 +307,7 @@ mod tests { fn test_env_var_overrides_builtin() { with_clean_env(None, || { unsafe { std::env::set_var("FLICKNOTE_SUPABASE_URL", "https://custom.example.com") }; + unsafe { std::env::set_var("FLICKNOTE_SUPABASE_KEY", "custom-publishable-key") }; unsafe { std::env::set_var( "XDG_CONFIG_HOME", @@ -324,6 +328,7 @@ mod tests { }; let cfg = Config::load().expect("Config::load should succeed"); assert_eq!(cfg.supabase_url, "https://custom.example.com"); + assert_eq!(cfg.supabase_anon_key, "custom-publishable-key"); }); } @@ -351,6 +356,7 @@ mod tests { }; let cfg = Config::load().expect("Config::load should succeed"); assert_eq!(cfg.supabase_url, "https://file.example.com"); + assert_eq!(cfg.supabase_anon_key, "key"); assert_eq!(cfg.api_url, "https://api.example.com/v1"); assert_eq!(cfg.gateway_url, "https://gateway.example.com"); }); From 4f7487b7b9b9acb36918b2406e4267cf95bc6ab4 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 5 Sep 2026 15:55:15 +0800 Subject: [PATCH 2/2] fix(cli): tighten cnsupa cutover coverage --- README.md | 14 +++++++------- flicknote-core/src/config.rs | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dc89c3c..9225702 100644 --- a/README.md +++ b/README.md @@ -184,13 +184,13 @@ Environment variables: - `FLICKNOTE_API_URL` — API Worker base URL for share links - `FLICKNOTE_GATEWAY_URL` — Gateway origin for attachment operations and `gateway request` -For the default `dev` environment, `FLICKNOTE_SUPABASE_KEY` uses the opaque -cnsupa publishable key -(`sb_publishable_4VEs5DX9YlkHuViFbmRMQb_f_LPrdOR`), not the retired JWT-shaped -anon key. The value is sent through Supabase's existing `apikey` header. -Existing dev users must upgrade and run `flicknote login --force` once to -replace the old session before normal sync; explicit config-file and environment -key overrides continue to work for custom environments. +For the default `dev` environment, the built-in `FLICKNOTE_SUPABASE_KEY` value +in the [runtime configuration](flicknote-core/src/config.rs) is an opaque cnsupa +publishable key, not the retired JWT-shaped anon key. The value is sent through +Supabase's existing `apikey` header. Existing dev users must upgrade and run +`flicknote login --force` once to replace the old session before normal sync; +explicit config-file and environment key overrides continue to work for custom +environments. `apiUrl` and `gatewayUrl` can also be set in `config.json`. After changing either value, restart the daemon with `flicknote daemon restart`. Configure the two diff --git a/flicknote-core/src/config.rs b/flicknote-core/src/config.rs index 3d5a33a..cd7d535 100644 --- a/flicknote-core/src/config.rs +++ b/flicknote-core/src/config.rs @@ -287,6 +287,28 @@ mod tests { ); } + #[test] + fn test_config_load_uses_dev_defaults_without_config() { + with_clean_env(None, || { + let config_home = tempfile::tempdir().expect("config tempdir"); + let data_home = tempfile::tempdir().expect("data tempdir"); + unsafe { + std::env::set_var("XDG_CONFIG_HOME", config_home.path()); + std::env::set_var("XDG_DATA_HOME", data_home.path()); + } + + let config = Config::load().expect("Config::load should use dev defaults"); + assert_eq!(config.supabase_url, "https://dev-auth.flicknote.app"); + assert_eq!( + config.supabase_anon_key, + "sb_publishable_4VEs5DX9YlkHuViFbmRMQb_f_LPrdOR" + ); + assert_eq!(config.powersync_url, "https://dev-sync.flicknote.app"); + assert_eq!(config.api_url, "https://dev-api.flicknote.app/api/v1"); + assert_eq!(config.gateway_url, "https://dev-gw.flicknote.app"); + }); + } + #[test] fn test_builtin_defaults_prod() { let defaults = builtin_defaults("prod");