@@ -18,11 +18,13 @@ import {
1818 labels ,
1919 labelLines ,
2020 characters ,
21+ routeConfigs ,
2122 type NewLabelLine ,
2223} from "../src/db/schema/index.js" ;
23- import { eq } from "drizzle-orm" ;
24+ import { eq , and } from "drizzle-orm" ;
2425import { calculateContentHash } from "../src/lib/hash.js" ;
2526import { hashPassword } from "../src/services/auth.service.js" ;
27+ import type { IncomingJump } from "@branchforge/shared" ;
2628
2729const TEST_EMAIL = "tech-badges-test@example.com" ;
2830const TEST_PASSWORD = "testpassword123" ;
@@ -139,6 +141,33 @@ async function seedTechnicalBadgesData() {
139141 console . log ( "✅ Using existing test project file" ) ;
140142 }
141143
144+ // Create route config for outgoing jump display
145+ const TEST_ROUTE_KEY = "tech_test" ;
146+ const [ existingRouteConfig ] = await db
147+ . select ( )
148+ . from ( routeConfigs )
149+ . where (
150+ and (
151+ eq ( routeConfigs . projectId , testProject . id ) ,
152+ eq ( routeConfigs . routeKey , TEST_ROUTE_KEY )
153+ )
154+ )
155+ . limit ( 1 ) ;
156+
157+ if ( ! existingRouteConfig ) {
158+ await db . insert ( routeConfigs ) . values ( {
159+ projectId : testProject . id ,
160+ routeKey : TEST_ROUTE_KEY ,
161+ routeName : "Tech Test Route" ,
162+ jumpPrefix : "tech_test_" ,
163+ sortOrder : 0 ,
164+ isShared : false ,
165+ } ) ;
166+ console . log ( `✅ Created route config: ${ TEST_ROUTE_KEY } ` ) ;
167+ } else {
168+ console . log ( `✅ Using existing route config: ${ TEST_ROUTE_KEY } ` ) ;
169+ }
170+
142171 // Clean up existing test label
143172 const [ existingLabel ] = await db
144173 . select ( )
@@ -160,6 +189,7 @@ async function seedTechnicalBadgesData() {
160189 projectFileId : projectFileId ! ,
161190 title : TEST_LABEL_TITLE ,
162191 labelNumber : 1 ,
192+ route : TEST_ROUTE_KEY ,
163193 sequenceOrder : 0 ,
164194 visibility : "EXCLUSIVE" ,
165195 status : "DRAFT" ,
@@ -574,6 +604,168 @@ async function seedTechnicalBadgesData() {
574604 await db . insert ( labelLines ) . values ( testLines ) ;
575605 console . log ( `✅ Created ${ testLines . length } test lines\n` ) ;
576606
607+ // Build incoming jumps for target labels
608+ const targetLabelMap = new Map (
609+ createdTargetLabels . map ( ( l ) => [ l . labelName , l . id ] )
610+ ) ;
611+
612+ const incomingJumpsByTarget : Record < string , IncomingJump [ ] > = {
613+ label_fight : [
614+ {
615+ sourceLabelId : labelId ,
616+ sourceLabelTitle : TEST_LABEL_TITLE ,
617+ sourceLabelName : TEST_LABEL_TITLE ,
618+ jumpType : "MENU_CHOICE" ,
619+ choiceText : "Fight" ,
620+ } ,
621+ {
622+ sourceLabelId : labelId ,
623+ sourceLabelTitle : TEST_LABEL_TITLE ,
624+ sourceLabelName : TEST_LABEL_TITLE ,
625+ jumpType : "MENU_CHOICE" ,
626+ choiceText : "The Kingdom" ,
627+ } ,
628+ ] ,
629+ label_run : [
630+ {
631+ sourceLabelId : labelId ,
632+ sourceLabelTitle : TEST_LABEL_TITLE ,
633+ sourceLabelName : TEST_LABEL_TITLE ,
634+ jumpType : "MENU_CHOICE" ,
635+ choiceText : "Run away" ,
636+ conditions : {
637+ variables : [ "has_stamina" ] ,
638+ } ,
639+ } ,
640+ {
641+ sourceLabelId : labelId ,
642+ sourceLabelTitle : TEST_LABEL_TITLE ,
643+ sourceLabelName : TEST_LABEL_TITLE ,
644+ jumpType : "MENU_CHOICE" ,
645+ choiceText : "The Rebels" ,
646+ } ,
647+ ] ,
648+ label_talk : [
649+ {
650+ sourceLabelId : labelId ,
651+ sourceLabelTitle : TEST_LABEL_TITLE ,
652+ sourceLabelName : TEST_LABEL_TITLE ,
653+ jumpType : "MENU_CHOICE" ,
654+ choiceText : "Talk" ,
655+ } ,
656+ {
657+ sourceLabelId : labelId ,
658+ sourceLabelTitle : TEST_LABEL_TITLE ,
659+ sourceLabelName : TEST_LABEL_TITLE ,
660+ jumpType : "MENU_CHOICE" ,
661+ choiceText : "Stay Neutral" ,
662+ } ,
663+ ] ,
664+ label_light : [
665+ {
666+ sourceLabelId : labelId ,
667+ sourceLabelTitle : TEST_LABEL_TITLE ,
668+ sourceLabelName : TEST_LABEL_TITLE ,
669+ jumpType : "MENU_CHOICE" ,
670+ choiceText : "Light path" ,
671+ } ,
672+ ] ,
673+ label_dark : [
674+ {
675+ sourceLabelId : labelId ,
676+ sourceLabelTitle : TEST_LABEL_TITLE ,
677+ sourceLabelName : TEST_LABEL_TITLE ,
678+ jumpType : "MENU_CHOICE" ,
679+ choiceText : "Dark path" ,
680+ } ,
681+ ] ,
682+ label_gold : [
683+ {
684+ sourceLabelId : labelId ,
685+ sourceLabelTitle : TEST_LABEL_TITLE ,
686+ sourceLabelName : TEST_LABEL_TITLE ,
687+ jumpType : "MENU_CHOICE" ,
688+ choiceText : "Gold coins" ,
689+ } ,
690+ {
691+ sourceLabelId : labelId ,
692+ sourceLabelTitle : TEST_LABEL_TITLE ,
693+ sourceLabelName : TEST_LABEL_TITLE ,
694+ jumpType : "MENU_CHOICE" ,
695+ choiceText : "Aggressive approach" ,
696+ } ,
697+ ] ,
698+ label_gem : [
699+ {
700+ sourceLabelId : labelId ,
701+ sourceLabelTitle : TEST_LABEL_TITLE ,
702+ sourceLabelName : TEST_LABEL_TITLE ,
703+ jumpType : "MENU_CHOICE" ,
704+ choiceText : "Magic gem" ,
705+ conditions : {
706+ variables : [ "has_gem" ] ,
707+ } ,
708+ } ,
709+ {
710+ sourceLabelId : labelId ,
711+ sourceLabelTitle : TEST_LABEL_TITLE ,
712+ sourceLabelName : TEST_LABEL_TITLE ,
713+ jumpType : "MENU_CHOICE" ,
714+ choiceText : "Stealthy approach" ,
715+ } ,
716+ ] ,
717+ label_nothing : [
718+ {
719+ sourceLabelId : labelId ,
720+ sourceLabelTitle : TEST_LABEL_TITLE ,
721+ sourceLabelName : TEST_LABEL_TITLE ,
722+ jumpType : "MENU_CHOICE" ,
723+ choiceText : "Nothing" ,
724+ } ,
725+ {
726+ sourceLabelId : labelId ,
727+ sourceLabelTitle : TEST_LABEL_TITLE ,
728+ sourceLabelName : TEST_LABEL_TITLE ,
729+ jumpType : "MENU_CHOICE" ,
730+ choiceText : "Diplomatic approach" ,
731+ } ,
732+ ] ,
733+ chapter_two_scene_one : [
734+ {
735+ sourceLabelId : labelId ,
736+ sourceLabelTitle : TEST_LABEL_TITLE ,
737+ sourceLabelName : TEST_LABEL_TITLE ,
738+ jumpType : "AUTOMATIC" ,
739+ choiceText : "Automatic jump" ,
740+ } ,
741+ ...createdTargetLabels
742+ . filter ( ( l ) =>
743+ [ "label_gold" , "label_gem" , "label_nothing" ] . includes ( l . labelName )
744+ )
745+ . map ( ( l ) => ( {
746+ sourceLabelId : l . id ,
747+ sourceLabelTitle : targetLabels . find (
748+ ( t ) => t . labelName === l . labelName
749+ ) ! . name ,
750+ sourceLabelName : l . labelName ,
751+ jumpType : "AUTOMATIC" as const ,
752+ choiceText : "Automatic jump" as const ,
753+ } ) ) ,
754+ ] ,
755+ } ;
756+
757+ for ( const [ labelName , jumps ] of Object . entries ( incomingJumpsByTarget ) ) {
758+ const targetId = targetLabelMap . get ( labelName ) ;
759+ if ( targetId ) {
760+ await db
761+ . update ( labels )
762+ . set ( { incomingJumps : jumps } )
763+ . where ( eq ( labels . id , targetId ) ) ;
764+ console . log ( `✅ Added ${ jumps . length } incoming jump(s) to ${ labelName } ` ) ;
765+ }
766+ }
767+ console . log ( ) ;
768+
577769 // Summary
578770 console . log ( "🎉 Technical badges test data seeded successfully!\n" ) ;
579771 console . log ( "Test features included:" ) ;
@@ -586,6 +778,8 @@ async function seedTechnicalBadgesData() {
586778 console . log ( " ✅ Variables conditions" ) ;
587779 console . log ( " ✅ Visual statements (SCENE, SHOW, HIDE)" ) ;
588780 console . log ( " ✅ Jump targets" ) ;
781+ console . log ( " ✅ Incoming jumps on target labels" ) ;
782+ console . log ( " ✅ Outgoing jump (route-based prefix via route config)" ) ;
589783 console . log ( " ✅ Combinations of multiple features" ) ;
590784 console . log (
591785 ` ✅ ${ createdTargetLabels . length } target labels created for testing resolution\n`
0 commit comments