1- import { Organization , Project } from "@trigger.dev/database" ;
1+ import type { Organization , Project } from "@trigger.dev/database" ;
22import {
33 BillingClient ,
4- Limits ,
5- SetPlanBody ,
6- UsageSeriesParams ,
7- UsageResult ,
4+ type Limits ,
5+ type SetPlanBody ,
6+ type UsageSeriesParams ,
7+ type UsageResult ,
8+ defaultMachine as defaultMachineFromPlatform ,
9+ machines as machinesFromPlatform ,
10+ type MachineCode ,
811} from "@trigger.dev/platform/v3" ;
912import { createCache , DefaultStatefulContext , Namespace } from "@unkey/cache" ;
1013import { MemoryStore } from "@unkey/cache/stores" ;
@@ -17,6 +20,9 @@ import { logger } from "~/services/logger.server";
1720import { newProjectPath , organizationBillingPath } from "~/utils/pathBuilder" ;
1821import { singleton } from "~/utils/singleton" ;
1922import { RedisCacheStore } from "./unkey/redisCacheStore.server" ;
23+ import { existsSync , readFileSync } from "node:fs" ;
24+ import { z } from "zod" ;
25+ import { MachinePresetName } from "@trigger.dev/core/v3" ;
2026
2127function initializeClient ( ) {
2228 if ( isCloud ( ) && process . env . BILLING_API_URL && process . env . BILLING_API_KEY ) {
@@ -67,6 +73,111 @@ function initializePlatformCache() {
6773
6874const platformCache = singleton ( "platformCache" , initializePlatformCache ) ;
6975
76+ type Machines = typeof machinesFromPlatform ;
77+
78+ const MachineOverrideValues = z . object ( {
79+ cpu : z . number ( ) ,
80+ memory : z . number ( ) ,
81+ } ) ;
82+ type MachineOverrideValues = z . infer < typeof MachineOverrideValues > ;
83+
84+ const MachineOverrides = z . record ( MachinePresetName , MachineOverrideValues . partial ( ) ) ;
85+ type MachineOverrides = z . infer < typeof MachineOverrides > ;
86+
87+ const MachinePresetOverrides = z . object ( {
88+ defaultMachine : MachinePresetName . optional ( ) ,
89+ machines : MachineOverrides . optional ( ) ,
90+ } ) ;
91+
92+ function initializeMachinePresets ( ) : {
93+ defaultMachine : MachineCode ;
94+ machines : Machines ;
95+ } {
96+ const overrides = getMachinePresetOverrides ( ) ;
97+
98+ if ( ! overrides ) {
99+ return {
100+ defaultMachine : defaultMachineFromPlatform ,
101+ machines : machinesFromPlatform ,
102+ } ;
103+ }
104+
105+ return {
106+ defaultMachine : overrideDefaultMachine ( defaultMachineFromPlatform , overrides . defaultMachine ) ,
107+ machines : overrideMachines ( machinesFromPlatform , overrides . machines ) ,
108+ } ;
109+ }
110+
111+ export const { defaultMachine, machines } = singleton ( "machinePresets" , initializeMachinePresets ) ;
112+
113+ function overrideDefaultMachine ( defaultMachine : MachineCode , override ?: MachineCode ) : MachineCode {
114+ if ( ! override ) {
115+ return defaultMachine ;
116+ }
117+
118+ return override ;
119+ }
120+
121+ function overrideMachines ( machines : Machines , overrides ?: MachineOverrides ) : Machines {
122+ if ( ! overrides ) {
123+ return machines ;
124+ }
125+
126+ const mergedMachines = {
127+ ...machines ,
128+ } ;
129+
130+ for ( const machine of Object . keys ( overrides ) as MachinePresetName [ ] ) {
131+ mergedMachines [ machine ] = {
132+ ...mergedMachines [ machine ] ,
133+ ...overrides [ machine ] ,
134+ } ;
135+ }
136+
137+ return mergedMachines ;
138+ }
139+
140+ function getMachinePresetOverrides ( ) {
141+ const path = env . MACHINE_PRESETS_OVERRIDE_PATH ;
142+ if ( ! path ) {
143+ return ;
144+ }
145+
146+ const overrides = safeReadMachinePresetOverrides ( path ) ;
147+ if ( ! overrides ) {
148+ return ;
149+ }
150+
151+ const parsed = MachinePresetOverrides . safeParse ( overrides ) ;
152+
153+ if ( ! parsed . success ) {
154+ logger . error ( "Error parsing machine preset overrides" , { path, error : parsed . error } ) ;
155+ return ;
156+ }
157+
158+ return parsed . data ;
159+ }
160+
161+ function safeReadMachinePresetOverrides ( path : string ) {
162+ try {
163+ const fileExists = existsSync ( path ) ;
164+ if ( ! fileExists ) {
165+ logger . error ( "Machine preset overrides file does not exist" , { path } ) ;
166+ return ;
167+ }
168+
169+ const fileContents = readFileSync ( path , "utf8" ) ;
170+
171+ return JSON . parse ( fileContents ) ;
172+ } catch ( error ) {
173+ logger . error ( "Error reading machine preset overrides" , {
174+ path,
175+ error : error instanceof Error ? error . message : String ( error ) ,
176+ } ) ;
177+ return ;
178+ }
179+ }
180+
70181export async function getCurrentPlan ( orgId : string ) {
71182 if ( ! client ) return undefined ;
72183
0 commit comments