From 1a37d148a3cf2d4d1658e52c0f492ff9c22def81 Mon Sep 17 00:00:00 2001 From: Trezy Date: Thu, 07 May 2026 17:26:00 +0000 Subject: [PATCH] feat: migrate legacy script/index_hook data to scripts table and drop columns Signed-off-by: Trezy Signed-off-by: Trezy --- src/lexicon.rs | 169 +++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------- src/main.rs | 2 -- src/record_handler.rs | 2 -- migrations/postgres/20260502000001_migrate_legacy_scripts.sql | 26 ++++++++++++++++++++++++++ migrations/sqlite/20260502000001_migrate_legacy_scripts.sql | 26 ++++++++++++++++++++++++++ src/admin/lexicons.rs | 58 ++++++---------------------------------------------------- src/admin/network_lexicons.rs | 4 ---- src/admin/types.rs | 4 ---- src/lua/scripts.rs | 3 +-- src/lua/xrpc_api.rs | 20 ++++++++------------ src/oauth/client_auth.rs | 6 ------ src/xrpc/procedure.rs | 3 +-- src/xrpc/query.rs | 3 +-- web/src/lib/api.ts | 2 -- web/src/types/lexicons.ts | 4 ---- web/src/app/dashboard/lexicons/page.tsx | 14 -------------- web/src/app/dashboard/lexicons/[id]/lexicon-detail.tsx | 14 +------------- web/src/app/dashboard/lexicons/new/page.tsx | 33 ++------------------------------- 18 file(s) changed, 81 insertion(s)(+), 312 deletion(s)(-) diff --git a/src/lexicon.rs b/src/lexicon.rs --- a/src/lexicon.rs +++ b/src/lexicon.rs @@ -79,10 +79,6 @@ pub target_collection: Option, /// For procedures: the action this procedure performs (create, update, delete, upsert). pub action: ProcedureAction, - /// Optional Lua script that replaces the built-in handler. - pub script: Option, - /// Optional Lua script that runs when a record in this collection is indexed. - pub index_hook: Option, /// Optional per-NSID token cost for rate limiting. pub token_cost: Option, /// Optional space type NSID indicating this lexicon is designed for use within spaces of that type. @@ -96,8 +92,6 @@ revision: i32, target_collection: Option, action: ProcedureAction, - script: Option, - index_hook: Option, token_cost: Option, ) -> Result { let id = raw @@ -146,8 +140,6 @@ revision, target_collection, action, - script, - index_hook, token_cost, space_type, }) @@ -182,11 +174,9 @@ i32, Option, Option, - Option, - Option, Option, )> = sqlx::query_as( - "SELECT id, lexicon_json, revision, target_collection, action, script, index_hook, token_cost FROM lexicons", + "SELECT id, lexicon_json, revision, target_collection, action, token_cost FROM lexicons", ) .fetch_all(db) .await @@ -196,17 +186,7 @@ inner.clear(); let mut loaded = 0u32; - for ( - id, - json_str, - revision, - target_collection, - action_str, - script, - index_hook, - token_cost, - ) in rows - { + for (id, json_str, revision, target_collection, action_str, token_cost) in rows { let json: Value = match serde_json::from_str(&json_str) { Ok(v) => v, Err(e) => { @@ -226,8 +206,6 @@ revision, target_collection, action, - script, - index_hook, token_cost.map(|c| c as u32), ) { Ok(parsed) => { @@ -290,12 +268,6 @@ .filter(|lex| lex.lexicon_type == LexiconType::Procedure) .map(|lex| lex.id.clone()) .collect() - } - - /// Get the index_hook for a record-type lexicon by its collection NSID. - pub async fn get_index_hook(&self, collection: &str) -> Option { - let inner = self.inner.read().await; - inner.get(collection).and_then(|lex| lex.index_hook.clone()) } /// Return the total count of registered lexicons. @@ -393,8 +365,6 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); assert_eq!(parsed.id, "games.gamesgamesgamesgames.game"); @@ -412,8 +382,6 @@ 2, Some("games.gamesgamesgamesgames.game".into()), ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); @@ -435,8 +403,6 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); assert_eq!(parsed.lexicon_type, LexiconType::Procedure); @@ -452,8 +418,6 @@ None, ProcedureAction::Delete, None, - None, - None, ) .unwrap(); assert_eq!(parsed.action, ProcedureAction::Delete); @@ -467,8 +431,6 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); assert_eq!(parsed.lexicon_type, LexiconType::Definitions); @@ -477,7 +439,7 @@ #[test] fn parse_missing_id_returns_error() { let raw = json!({"lexicon": 1, "defs": {}}); - let result = ParsedLexicon::parse(raw, 1, None, ProcedureAction::Upsert, None, None, None); + let result = ParsedLexicon::parse(raw, 1, None, ProcedureAction::Upsert, None); assert!(result.is_err()); assert!(result.unwrap_err().contains("id")); } @@ -485,16 +447,8 @@ #[test] fn parse_preserves_raw_json() { let raw = record_lexicon_json(); - let parsed = ParsedLexicon::parse( - raw.clone(), - 1, - None, - ProcedureAction::Upsert, - None, - None, - None, - ) - .unwrap(); + let parsed = + ParsedLexicon::parse(raw.clone(), 1, None, ProcedureAction::Upsert, None).unwrap(); assert_eq!(parsed.raw, raw); } @@ -505,8 +459,6 @@ 1, Some("custom.collection".into()), ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); @@ -532,8 +484,6 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); reg.upsert(parsed).await; @@ -552,8 +502,6 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); reg.upsert(v1).await; @@ -563,8 +511,6 @@ 5, None, ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); @@ -588,8 +534,6 @@ 1, None, ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); @@ -621,27 +565,16 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); - let query = ParsedLexicon::parse( - query_lexicon_json(), - 1, - None, - ProcedureAction::Upsert, - None, - None, - None, - ) - .unwrap(); + let query = + ParsedLexicon::parse(query_lexicon_json(), 1, None, ProcedureAction::Upsert, None) + .unwrap(); let procedure = ParsedLexicon::parse( procedure_lexicon_json(), 1, None, ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); @@ -650,8 +583,6 @@ 1, None, ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); @@ -723,85 +654,6 @@ assert_eq!(ProcedureAction::Upsert.to_optional_str(), None); } - // ----------------------------------------------------------------------- - // index_hook - // ----------------------------------------------------------------------- - - #[test] - fn parse_preserves_index_hook() { - let parsed = ParsedLexicon::parse( - record_lexicon_json(), - 1, - None, - ProcedureAction::Upsert, - None, - Some("function handle() end".into()), - None, - ) - .unwrap(); - assert_eq!(parsed.index_hook, Some("function handle() end".into())); - } - - #[test] - fn parse_index_hook_none_by_default() { - let parsed = ParsedLexicon::parse( - record_lexicon_json(), - 1, - None, - ProcedureAction::Upsert, - None, - None, - None, - ) - .unwrap(); - assert!(parsed.index_hook.is_none()); - } - - #[tokio::test] - async fn registry_get_index_hook_returns_script() { - let reg = LexiconRegistry::new(); - let parsed = ParsedLexicon::parse( - record_lexicon_json(), - 1, - None, - ProcedureAction::Upsert, - None, - Some("function handle() log('hook') end".into()), - None, - ) - .unwrap(); - reg.upsert(parsed).await; - - let script = reg.get_index_hook("games.gamesgamesgamesgames.game").await; - assert_eq!(script, Some("function handle() log('hook') end".into())); - } - - #[tokio::test] - async fn registry_get_index_hook_returns_none_when_absent() { - let reg = LexiconRegistry::new(); - let parsed = ParsedLexicon::parse( - record_lexicon_json(), - 1, - None, - ProcedureAction::Upsert, - None, - None, - None, - ) - .unwrap(); - reg.upsert(parsed).await; - - let script = reg.get_index_hook("games.gamesgamesgamesgames.game").await; - assert!(script.is_none()); - } - - #[tokio::test] - async fn registry_get_index_hook_returns_none_for_unknown() { - let reg = LexiconRegistry::new(); - let script = reg.get_index_hook("nonexistent").await; - assert!(script.is_none()); - } - #[test] fn parse_space_type_from_lexicon() { let raw = json!({ @@ -821,8 +673,7 @@ } } }); - let parsed = - ParsedLexicon::parse(raw, 1, None, ProcedureAction::Upsert, None, None, None).unwrap(); + let parsed = ParsedLexicon::parse(raw, 1, None, ProcedureAction::Upsert, None).unwrap(); assert_eq!(parsed.space_type.as_deref(), Some("com.example.forum")); } @@ -833,8 +684,6 @@ 1, None, ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); diff --git a/src/main.rs b/src/main.rs --- a/src/main.rs +++ b/src/main.rs @@ -138,8 +138,6 @@ target_collection.clone(), ProcedureAction::Upsert, None, - None, - None, ) { Ok(parsed) => { let now = db::now_rfc3339(); diff --git a/src/record_handler.rs b/src/record_handler.rs --- a/src/record_handler.rs +++ b/src/record_handler.rs @@ -303,8 +303,6 @@ target_collection.clone(), ProcedureAction::Upsert, None, - None, - None, ) { Ok(p) => p, Err(e) => { diff --git a/migrations/postgres/20260502000001_migrate_legacy_scripts.sql b/migrations/postgres/20260502000001_migrate_legacy_scripts.sql new file mode 100644 --- /dev/null +++ b/migrations/postgres/20260502000001_migrate_legacy_scripts.sql @@ -0,0 +1,26 @@ +-- Migrate legacy index_hook and script columns into the trigger-keyed +-- scripts table, then drop the old columns. + +-- 1. index_hook -> record.index: +INSERT INTO scripts (id, body, script_type, created_at, updated_at) +SELECT 'record.index:' || id, index_hook, 'lua', NOW(), NOW() + FROM lexicons + WHERE index_hook IS NOT NULL +ON CONFLICT (id) DO NOTHING; + +-- 2. script -> xrpc.query: or xrpc.procedure: +INSERT INTO scripts (id, body, script_type, created_at, updated_at) +SELECT 'xrpc.' || + CASE (lexicon_json::jsonb)->'defs'->'main'->>'type' + WHEN 'query' THEN 'query' + WHEN 'procedure' THEN 'procedure' + END || ':' || id, + script, 'lua', NOW(), NOW() + FROM lexicons + WHERE script IS NOT NULL + AND (lexicon_json::jsonb)->'defs'->'main'->>'type' IN ('query', 'procedure') +ON CONFLICT (id) DO NOTHING; + +-- 3. Drop legacy columns. +ALTER TABLE lexicons DROP COLUMN index_hook; +ALTER TABLE lexicons DROP COLUMN script; diff --git a/migrations/sqlite/20260502000001_migrate_legacy_scripts.sql b/migrations/sqlite/20260502000001_migrate_legacy_scripts.sql new file mode 100644 --- /dev/null +++ b/migrations/sqlite/20260502000001_migrate_legacy_scripts.sql @@ -0,0 +1,26 @@ +-- Migrate legacy index_hook and script columns into the trigger-keyed +-- scripts table, then drop the old columns. + +-- 1. index_hook -> record.index: +INSERT INTO scripts (id, body, script_type, created_at, updated_at) +SELECT 'record.index:' || id, index_hook, 'lua', datetime('now'), datetime('now') + FROM lexicons + WHERE index_hook IS NOT NULL +ON CONFLICT (id) DO NOTHING; + +-- 2. script -> xrpc.query: or xrpc.procedure: +INSERT INTO scripts (id, body, script_type, created_at, updated_at) +SELECT 'xrpc.' || + CASE json_extract(lexicon_json, '$.defs.main.type') + WHEN 'query' THEN 'query' + WHEN 'procedure' THEN 'procedure' + END || ':' || id, + script, 'lua', datetime('now'), datetime('now') + FROM lexicons + WHERE script IS NOT NULL + AND json_extract(lexicon_json, '$.defs.main.type') IN ('query', 'procedure') +ON CONFLICT (id) DO NOTHING; + +-- 3. Drop legacy columns. +ALTER TABLE lexicons DROP COLUMN index_hook; +ALTER TABLE lexicons DROP COLUMN script; diff --git a/src/admin/lexicons.rs b/src/admin/lexicons.rs --- a/src/admin/lexicons.rs +++ b/src/admin/lexicons.rs @@ -60,39 +60,24 @@ 1, body.target_collection.clone(), action.clone(), - body.script.clone(), - body.index_hook.clone(), body.token_cost.map(|c| c as u32), ) .map_err(|e| AppError::BadRequest(format!("failed to parse lexicon: {e}")))?; - // Validate script if provided - if let Some(ref script) = body.script { - crate::lua::validate_script(script).map_err(AppError::BadRequest)?; - } - - // Validate index_hook if provided - if let Some(ref script) = body.index_hook { - crate::lua::validate_script(script).map_err(AppError::BadRequest)?; - } - let action_str = action.to_optional_str(); - let has_script = body.script.is_some(); let lexicon_json_str = serde_json::to_string(&body.lexicon_json).unwrap_or_default(); let now = now_rfc3339(); // Upsert into database let sql = adapt_sql( r#" - INSERT INTO lexicons (id, lexicon_json, backfill, target_collection, action, script, index_hook, token_cost, source, created_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'manual', ?) + INSERT INTO lexicons (id, lexicon_json, backfill, target_collection, action, token_cost, source, created_at) + VALUES (?, ?, ?, ?, ?, ?, 'manual', ?) ON CONFLICT (id) DO UPDATE SET lexicon_json = EXCLUDED.lexicon_json, backfill = EXCLUDED.backfill, target_collection = EXCLUDED.target_collection, action = EXCLUDED.action, - script = EXCLUDED.script, - index_hook = EXCLUDED.index_hook, token_cost = EXCLUDED.token_cost, source = 'manual', revision = lexicons.revision + 1, @@ -107,8 +92,6 @@ .bind(if body.backfill { 1_i32 } else { 0_i32 }) .bind(&body.target_collection) .bind(action_str) - .bind(&body.script) - .bind(&body.index_hook) .bind(body.token_cost) .bind(&now) .bind(&now) @@ -124,8 +107,6 @@ revision, body.target_collection, action, - body.script, - body.index_hook.clone(), body.token_cost.map(|c| c as u32), ) .map_err(|e| AppError::Internal(format!("failed to re-parse lexicon: {e}")))?; @@ -156,8 +137,6 @@ subject: Some(id.clone()), detail: serde_json::json!({ "revision": revision, - "has_script": has_script, - "has_index_hook": body.index_hook.is_some(), "source": "manual", }), }, @@ -182,7 +161,7 @@ auth.require(Permission::LexiconsRead).await?; let backend = state.db_backend; let sql = adapt_sql( - "SELECT id, revision, lexicon_json, backfill, action, target_collection, script, index_hook, source, authority_did, last_fetched_at, created_at, updated_at, token_cost FROM lexicons ORDER BY id", + "SELECT id, revision, lexicon_json, backfill, action, target_collection, source, authority_did, last_fetched_at, created_at, updated_at, token_cost FROM lexicons ORDER BY id", backend, ); #[allow(clippy::type_complexity)] @@ -191,8 +170,6 @@ i32, String, i32, - Option, - Option, Option, Option, String, @@ -216,8 +193,6 @@ backfill, action, target_collection, - script, - index_hook, source, authority_did, last_fetched_at, @@ -226,15 +201,8 @@ token_cost, )| { let json: Value = serde_json::from_str(&json_str).unwrap_or_default(); - let parsed = ParsedLexicon::parse( - json, - revision, - None, - ProcedureAction::Upsert, - None, - None, - None, - ); + let parsed = + ParsedLexicon::parse(json, revision, None, ProcedureAction::Upsert, None); let lexicon_type = parsed .as_ref() .map(|p| format!("{:?}", p.lexicon_type).to_lowercase()) @@ -251,8 +219,6 @@ backfill: backfill != 0, action, target_collection, - has_script: script.is_some(), - has_index_hook: index_hook.is_some(), source, authority_did, last_fetched_at, @@ -277,7 +243,7 @@ auth.require(Permission::LexiconsRead).await?; let backend = state.db_backend; let sql = adapt_sql( - "SELECT id, revision, lexicon_json, backfill, action, target_collection, script, index_hook, source, authority_did, last_fetched_at, created_at, updated_at, token_cost FROM lexicons WHERE id = ?", + "SELECT id, revision, lexicon_json, backfill, action, target_collection, source, authority_did, last_fetched_at, created_at, updated_at, token_cost FROM lexicons WHERE id = ?", backend, ); #[allow(clippy::type_complexity)] @@ -286,8 +252,6 @@ i32, String, i32, - Option, - Option, Option, Option, String, @@ -309,8 +273,6 @@ backfill, action, target_collection, - script, - index_hook, source, authority_did, last_fetched_at, @@ -327,13 +289,9 @@ None, ProcedureAction::Upsert, None, - None, - None, ) .map(|p| format!("{:?}", p.lexicon_type).to_lowercase()) .unwrap_or_else(|_| "unknown".into()); - - let has_script = script.is_some(); Ok(Json(serde_json::json!({ "id": id, @@ -343,10 +301,6 @@ "backfill": backfill != 0, "action": action, "target_collection": target_collection, - "has_script": has_script, - "script": script, - "has_index_hook": index_hook.is_some(), - "index_hook": index_hook, "source": source, "authority_did": authority_did, "last_fetched_at": last_fetched_at, diff --git a/src/admin/network_lexicons.rs b/src/admin/network_lexicons.rs --- a/src/admin/network_lexicons.rs +++ b/src/admin/network_lexicons.rs @@ -72,8 +72,6 @@ body.target_collection.clone(), ProcedureAction::Upsert, None, - None, - None, ) .map_err(|e| AppError::BadRequest(format!("failed to parse lexicon: {e}")))?; @@ -120,8 +118,6 @@ revision, body.target_collection, ProcedureAction::Upsert, - None, - None, None, ) .map_err(|e| AppError::Internal(format!("failed to re-parse lexicon: {e}")))?; diff --git a/src/admin/types.rs b/src/admin/types.rs --- a/src/admin/types.rs +++ b/src/admin/types.rs @@ -13,8 +13,6 @@ pub(super) backfill: bool, pub(super) action: Option, pub(super) target_collection: Option, - pub(super) has_script: bool, - pub(super) has_index_hook: bool, pub(super) source: String, pub(super) authority_did: Option, pub(super) last_fetched_at: Option, @@ -33,8 +31,6 @@ pub(super) backfill: bool, pub(super) target_collection: Option, pub(super) action: Option, - pub(super) script: Option, - pub(super) index_hook: Option, pub(super) token_cost: Option, } diff --git a/src/lua/scripts.rs b/src/lua/scripts.rs --- a/src/lua/scripts.rs +++ b/src/lua/scripts.rs @@ -415,8 +415,7 @@ register_default_apis(&lua, &state_arc, &script.id, Some(payload.did))?; // Legacy globals (action, uri, did, collection, rkey, record) for - // back-compat with scripts written against the old `index_hook` - // surface. + // convenience / backwards compatibility. context::set_hook_context( &lua, payload.action, diff --git a/src/lua/xrpc_api.rs b/src/lua/xrpc_api.rs --- a/src/lua/xrpc_api.rs +++ b/src/lua/xrpc_api.rs @@ -336,7 +336,7 @@ .unwrap(); } - fn make_query_lexicon(id: &str, script: Option<&str>) -> ParsedLexicon { + fn make_query_lexicon(id: &str) -> ParsedLexicon { ParsedLexicon { id: id.to_string(), lexicon_type: LexiconType::Query, @@ -349,14 +349,12 @@ revision: 1, target_collection: None, action: ProcedureAction::Create, - script: script.map(|s| s.to_string()), - index_hook: None, token_cost: None, space_type: None, } } - fn make_procedure_lexicon(id: &str, script: Option<&str>) -> ParsedLexicon { + fn make_procedure_lexicon(id: &str) -> ParsedLexicon { ParsedLexicon { id: id.to_string(), lexicon_type: LexiconType::Procedure, @@ -369,8 +367,6 @@ revision: 1, target_collection: None, action: ProcedureAction::Create, - script: script.map(|s| s.to_string()), - index_hook: None, token_cost: None, space_type: None, } @@ -463,7 +459,7 @@ let state = test_state(); // Register a scripted query that returns a static response - let lexicon = make_query_lexicon("test.echo", None); + let lexicon = make_query_lexicon("test.echo"); state.lexicons.upsert(lexicon).await; seed_script( &state, @@ -488,7 +484,7 @@ async fn query_local_script_receives_params() { let state = test_state(); - let lexicon = make_query_lexicon("test.greet", None); + let lexicon = make_query_lexicon("test.greet"); state.lexicons.upsert(lexicon).await; seed_script( &state, @@ -517,7 +513,7 @@ async fn query_local_script_receives_caller_did() { let state = test_state(); - let lexicon = make_query_lexicon("test.whoami", None); + let lexicon = make_query_lexicon("test.whoami"); state.lexicons.upsert(lexicon).await; seed_script( &state, @@ -562,7 +558,7 @@ async fn query_rejects_procedure_lexicon() { let state = test_state(); - let lexicon = make_procedure_lexicon("test.create", None); + let lexicon = make_procedure_lexicon("test.create"); state.lexicons.upsert(lexicon).await; let mut params = HashMap::new(); @@ -576,7 +572,7 @@ async fn procedure_rejects_query_lexicon() { let state = test_state(); - let lexicon = make_query_lexicon("test.echo", Some("function handle() end")); + let lexicon = make_query_lexicon("test.echo"); state.lexicons.upsert(lexicon).await; let claims = Claims::internal("did:plc:test".into()); @@ -597,7 +593,7 @@ let state = test_state(); // Register a simple query that the outer script will call - let inner_lexicon = make_query_lexicon("test.inner", None); + let inner_lexicon = make_query_lexicon("test.inner"); state.lexicons.upsert(inner_lexicon).await; seed_script( &state, diff --git a/src/oauth/client_auth.rs b/src/oauth/client_auth.rs --- a/src/oauth/client_auth.rs +++ b/src/oauth/client_auth.rs @@ -375,8 +375,6 @@ None, crate::lexicon::ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); reg.upsert(parsed).await; @@ -435,8 +433,6 @@ None, crate::lexicon::ProcedureAction::Upsert, None, - None, - None, ) .unwrap(); reg.upsert(parsed).await; @@ -486,8 +482,6 @@ 1, None, crate::lexicon::ProcedureAction::Upsert, - None, - None, None, ) .unwrap(); diff --git a/src/xrpc/procedure.rs b/src/xrpc/procedure.rs --- a/src/xrpc/procedure.rs +++ b/src/xrpc/procedure.rs @@ -19,8 +19,7 @@ lexicon: &crate::lexicon::ParsedLexicon, ) -> Result { // Trigger-keyed dispatch: a script bound at `xrpc.procedure:` - // overrides the default PDS-write flow. The legacy `lexicon.script` - // column is no longer read. + // overrides the default PDS-write flow. let trigger = format!("xrpc.procedure:{}", lexicon.id); if let Some(resolved) = crate::lua::resolve(state, &trigger).await { // Delegation guard preserved from origin/dev: scripts that run diff --git a/src/xrpc/query.rs b/src/xrpc/query.rs --- a/src/xrpc/query.rs +++ b/src/xrpc/query.rs @@ -16,8 +16,7 @@ claims: Option<&Claims>, ) -> Result { // Trigger-keyed dispatch: a script bound at `xrpc.query:` - // overrides the default list / get-record flow. The legacy - // `lexicon.script` column is no longer read. + // overrides the default list / get-record flow. let trigger = format!("xrpc.query:{}", lexicon.id); if let Some(resolved) = crate::lua::resolve(state, &trigger).await { return crate::lua::execute_query_script( diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -141,8 +141,6 @@ backfill?: boolean; target_collection?: string; action?: string; - script?: string; - index_hook?: string; token_cost?: number | null; }) { return apiFetch<{ id: string; revision: number }>("/admin/lexicons", { diff --git a/web/src/types/lexicons.ts b/web/src/types/lexicons.ts --- a/web/src/types/lexicons.ts +++ b/web/src/types/lexicons.ts @@ -5,8 +5,6 @@ backfill: boolean action: string | null target_collection: string | null - has_script: boolean - has_index_hook: boolean source: string authority_did: string | null last_fetched_at: string | null @@ -17,6 +15,4 @@ export interface LexiconDetail extends LexiconSummary { lexicon_json: Record - script: string | null - index_hook: string | null } diff --git a/web/src/app/dashboard/lexicons/page.tsx b/web/src/app/dashboard/lexicons/page.tsx --- a/web/src/app/dashboard/lexicons/page.tsx +++ b/web/src/app/dashboard/lexicons/page.tsx @@ -150,20 +150,6 @@ enableSorting: true, }, { - id: "has_script", - accessorKey: "has_script", - header: ({ column }) => ( - - ), - cell: ({ row }) => - row.original.has_script ? ( - Lua - ) : ( - "--" - ), - enableSorting: true, - }, - { id: "backfill", accessorKey: "backfill", header: ({ column }) => ( diff --git a/web/src/app/dashboard/lexicons/[id]/lexicon-detail.tsx b/web/src/app/dashboard/lexicons/[id]/lexicon-detail.tsx --- a/web/src/app/dashboard/lexicons/[id]/lexicon-detail.tsx +++ b/web/src/app/dashboard/lexicons/[id]/lexicon-detail.tsx @@ -44,11 +44,6 @@ const [deleting, setDeleting] = useState(false); const [saving, setSaving] = useState(false); - // Editable text state. The lexicon page used to edit `script` and - // `index_hook` columns inline via lua editors; those columns are - // now managed via the Scripts subsystem (see "Scripts targeting - // this lexicon" panel below). We pass the existing values through - // unchanged on save so legacy data isn't accidentally NULLed. const [jsonText, setJsonText] = useState(""); const [originalJson, setOriginalJson] = useState(""); const [tokenCost, setTokenCost] = useState(""); @@ -89,11 +84,6 @@ await uploadLexicon({ lexicon_json: lexiconJson, backfill: lexicon.backfill, - // Preserve any legacy script / index_hook values verbatim — we - // no longer edit them here, but leaving them out of the body - // would NULL the columns on upsert and lose data. - script: lexicon.script ?? undefined, - index_hook: lexicon.index_hook ?? undefined, token_cost: tokenCost ? Number(tokenCost) : null, }); load(); @@ -262,9 +252,7 @@ {/* JSON editor only — scripts (record-event handlers, XRPC handlers, label-arrival handlers) are managed via the - "Scripts targeting this lexicon" panel above. The legacy - `script` / `index_hook` columns on the lexicons table are - preserved as-is on save but no longer edited here. */} + "Scripts targeting this lexicon" panel above. */} { - if (scriptManuallyEdited.current) return; - if (localMainType === "procedure") { - setScript(procedureScript(localTargetCollection)); - } else if (localMainType === "query") { - setScript(queryScript(localTargetCollection)); - } - }, [localMainType, localTargetCollection]); - - function handleScriptChange(value: string) { - scriptManuallyEdited.current = true; - setScript(value); - } - - // Reset manual-edit flag when type changes const prevType = useRef(localMainType); useEffect(() => { if (prevType.current !== localMainType) { - scriptManuallyEdited.current = false; prevType.current = localMainType; } }, [localMainType]); @@ -139,7 +115,6 @@ await uploadLexicon({ lexicon_json: lexiconJson, backfill: localMainType === "record" && backfill, - script: showScript && script ? script : undefined, }); router.push("/dashboard/lexicons"); } catch (e: unknown) { @@ -211,10 +186,6 @@ className="flex-1 min-h-0" jsonValue={json} onJsonChange={setJson} - luaValue={showScript ? script : undefined} - onLuaChange={showScript ? handleScriptChange : undefined} - luaCompletions={showScript ? luaCompletions : undefined} - collections={showScript ? collections : undefined} /> -- tangled.sh