@@ -81,7 +81,13 @@ export async function action({ request, params }: ActionFunctionArgs) {
8181 return json ( { error : "Method not allowed" } , { status : 405 } ) ;
8282 }
8383
84- const body = await request . json ( ) ;
84+ let body : unknown ;
85+ try {
86+ body = await request . json ( ) ;
87+ } catch {
88+ return json ( { error : "Invalid JSON body" } , { status : 400 } ) ;
89+ }
90+
8591 const parsed = UpdateModelSchema . safeParse ( body ) ;
8692
8793 if ( ! parsed . success ) {
@@ -90,59 +96,56 @@ export async function action({ request, params }: ActionFunctionArgs) {
9096
9197 const { modelName, matchPattern, startDate, pricingTiers } = parsed . data ;
9298
93- // Validate regex if provided
99+ // Validate regex if provided — strip (?i) POSIX flag since our registry handles it
94100 if ( matchPattern ) {
95101 try {
96- new RegExp ( matchPattern ) ;
102+ const testPattern = matchPattern . startsWith ( "(?i)" ) ? matchPattern . slice ( 4 ) : matchPattern ;
103+ new RegExp ( testPattern ) ;
97104 } catch {
98105 return json ( { error : "Invalid regex in matchPattern" } , { status : 400 } ) ;
99106 }
100107 }
101108
102- // Update model fields
103- const model = await prisma . llmModel . update ( {
104- where : { id : modelId } ,
105- data : {
106- ...( modelName !== undefined && { modelName } ) ,
107- ...( matchPattern !== undefined && { matchPattern } ) ,
108- ...( startDate !== undefined && { startDate : startDate ? new Date ( startDate ) : null } ) ,
109- } ,
110- } ) ;
111-
112- // If pricing tiers provided, replace them entirely
113- if ( pricingTiers ) {
114- // Delete existing tiers (cascades to prices)
115- await prisma . llmPricingTier . deleteMany ( { where : { modelId } } ) ;
116-
117- // Create new tiers
118- for ( const tier of pricingTiers ) {
119- await prisma . llmPricingTier . create ( {
120- data : {
121- modelId,
122- name : tier . name ,
123- isDefault : tier . isDefault ,
124- priority : tier . priority ,
125- conditions : tier . conditions ,
126- prices : {
127- create : Object . entries ( tier . prices ) . map ( ( [ usageType , price ] ) => ( {
128- modelId,
129- usageType,
130- price,
131- } ) ) ,
109+ // Update model + tiers atomically
110+ const updated = await prisma . $transaction ( async ( tx ) => {
111+ await tx . llmModel . update ( {
112+ where : { id : modelId } ,
113+ data : {
114+ ...( modelName !== undefined && { modelName } ) ,
115+ ...( matchPattern !== undefined && { matchPattern } ) ,
116+ ...( startDate !== undefined && { startDate : startDate ? new Date ( startDate ) : null } ) ,
117+ } ,
118+ } ) ;
119+
120+ if ( pricingTiers ) {
121+ await tx . llmPricingTier . deleteMany ( { where : { modelId } } ) ;
122+
123+ for ( const tier of pricingTiers ) {
124+ await tx . llmPricingTier . create ( {
125+ data : {
126+ modelId,
127+ name : tier . name ,
128+ isDefault : tier . isDefault ,
129+ priority : tier . priority ,
130+ conditions : tier . conditions ,
131+ prices : {
132+ create : Object . entries ( tier . prices ) . map ( ( [ usageType , price ] ) => ( {
133+ modelId,
134+ usageType,
135+ price,
136+ } ) ) ,
137+ } ,
132138 } ,
133- } ,
134- } ) ;
139+ } ) ;
140+ }
135141 }
136- }
137142
138- const updated = await prisma . llmModel . findUnique ( {
139- where : { id : modelId } ,
140- include : {
141- pricingTiers : {
142- include : { prices : true } ,
143- orderBy : { priority : "asc" } ,
143+ return tx . llmModel . findUnique ( {
144+ where : { id : modelId } ,
145+ include : {
146+ pricingTiers : { include : { prices : true } , orderBy : { priority : "asc" } } ,
144147 } ,
145- } ,
148+ } ) ;
146149 } ) ;
147150
148151 return json ( { model : updated } ) ;
0 commit comments