@@ -282,10 +282,25 @@ router.get("/:appId/versions/:versionId", async (req, res) => {
282282 try {
283283 const data = await ascFetch (
284284 account ,
285- `/v1/appStoreVersions/${ versionId } ?fields[appStoreVersions]=versionString,appStoreState,platform,createdDate,releaseType,earliestReleaseDate,downloadable`
285+ `/v1/appStoreVersions/${ versionId } ?fields[appStoreVersions]=versionString,appStoreState,platform,createdDate,releaseType,earliestReleaseDate,downloadable,reviewType&include=appStoreVersionPhasedRelease&fields[appStoreVersionPhasedReleases]=phasedReleaseState,currentDayNumber,startDate,totalPauseDuration `
286286 ) ;
287287
288288 const attrs = data . data . attributes ;
289+
290+ let phasedRelease = null ;
291+ if ( data . included ) {
292+ const pr = data . included . find ( ( inc ) => inc . type === "appStoreVersionPhasedReleases" ) ;
293+ if ( pr ) {
294+ phasedRelease = {
295+ id : pr . id ,
296+ phasedReleaseState : pr . attributes . phasedReleaseState ,
297+ currentDayNumber : pr . attributes . currentDayNumber ,
298+ startDate : pr . attributes . startDate ,
299+ totalPauseDuration : pr . attributes . totalPauseDuration ,
300+ } ;
301+ }
302+ }
303+
289304 const result = {
290305 id : data . data . id ,
291306 versionString : attrs . versionString ,
@@ -295,6 +310,8 @@ router.get("/:appId/versions/:versionId", async (req, res) => {
295310 releaseType : attrs . releaseType ,
296311 earliestReleaseDate : attrs . earliestReleaseDate ,
297312 downloadable : attrs . downloadable ,
313+ reviewType : attrs . reviewType ,
314+ phasedRelease,
298315 } ;
299316
300317 apiCache . set ( cacheKey , result ) ;
@@ -305,6 +322,139 @@ router.get("/:appId/versions/:versionId", async (req, res) => {
305322 }
306323} ) ;
307324
325+ // ── Version Settings (release type, rating reset) ───────────────────────────
326+
327+ router . patch ( "/:appId/versions/:versionId" , async ( req , res ) => {
328+ const { versionId } = req . params ;
329+ const { accountId, releaseType, earliestReleaseDate, resetRatingSummary } = req . body ;
330+
331+ if ( ! accountId ) {
332+ return res . status ( 400 ) . json ( { error : "accountId is required" } ) ;
333+ }
334+
335+ const accounts = getAccounts ( ) ;
336+ const account = accounts . find ( ( a ) => a . id === accountId ) ;
337+ if ( ! account ) return res . status ( 400 ) . json ( { error : "Account not found" } ) ;
338+
339+ const attributes = { } ;
340+ if ( releaseType !== undefined ) attributes . releaseType = releaseType ;
341+ if ( earliestReleaseDate !== undefined ) attributes . earliestReleaseDate = earliestReleaseDate ;
342+ if ( resetRatingSummary !== undefined ) attributes . resetRatingSummary = resetRatingSummary ;
343+
344+ try {
345+ await ascFetch ( account , `/v1/appStoreVersions/${ versionId } ` , {
346+ method : "PATCH" ,
347+ body : {
348+ data : { type : "appStoreVersions" , id : versionId , attributes } ,
349+ } ,
350+ } ) ;
351+
352+ apiCache . deleteByPrefix ( `apps:version-detail:${ versionId } :` ) ;
353+ res . json ( { success : true } ) ;
354+ } catch ( err ) {
355+ console . error ( `Failed to update version ${ versionId } :` , err . message ) ;
356+ res . status ( 502 ) . json ( { error : err . message } ) ;
357+ }
358+ } ) ;
359+
360+ // ── Phased Release ──────────────────────────────────────────────────────────
361+
362+ router . post ( "/:appId/versions/:versionId/phased-release" , async ( req , res ) => {
363+ const { versionId } = req . params ;
364+ const { accountId, phasedReleaseState } = req . body ;
365+
366+ if ( ! accountId ) {
367+ return res . status ( 400 ) . json ( { error : "accountId is required" } ) ;
368+ }
369+
370+ const accounts = getAccounts ( ) ;
371+ const account = accounts . find ( ( a ) => a . id === accountId ) ;
372+ if ( ! account ) return res . status ( 400 ) . json ( { error : "Account not found" } ) ;
373+
374+ try {
375+ const data = await ascFetch ( account , "/v1/appStoreVersionPhasedReleases" , {
376+ method : "POST" ,
377+ body : {
378+ data : {
379+ type : "appStoreVersionPhasedReleases" ,
380+ attributes : { phasedReleaseState : phasedReleaseState || "INACTIVE" } ,
381+ relationships : {
382+ appStoreVersion : { data : { type : "appStoreVersions" , id : versionId } } ,
383+ } ,
384+ } ,
385+ } ,
386+ } ) ;
387+
388+ apiCache . deleteByPrefix ( `apps:version-detail:${ versionId } :` ) ;
389+ res . json ( {
390+ id : data . data . id ,
391+ phasedReleaseState : data . data . attributes . phasedReleaseState ,
392+ currentDayNumber : data . data . attributes . currentDayNumber ,
393+ startDate : data . data . attributes . startDate ,
394+ totalPauseDuration : data . data . attributes . totalPauseDuration ,
395+ } ) ;
396+ } catch ( err ) {
397+ console . error ( `Failed to create phased release for version ${ versionId } :` , err . message ) ;
398+ res . status ( 502 ) . json ( { error : err . message } ) ;
399+ }
400+ } ) ;
401+
402+ router . patch ( "/:appId/versions/:versionId/phased-release/:phasedReleaseId" , async ( req , res ) => {
403+ const { versionId, phasedReleaseId } = req . params ;
404+ const { accountId, phasedReleaseState } = req . body ;
405+
406+ if ( ! accountId ) {
407+ return res . status ( 400 ) . json ( { error : "accountId is required" } ) ;
408+ }
409+
410+ const accounts = getAccounts ( ) ;
411+ const account = accounts . find ( ( a ) => a . id === accountId ) ;
412+ if ( ! account ) return res . status ( 400 ) . json ( { error : "Account not found" } ) ;
413+
414+ try {
415+ const data = await ascFetch ( account , `/v1/appStoreVersionPhasedReleases/${ phasedReleaseId } ` , {
416+ method : "PATCH" ,
417+ body : {
418+ data : {
419+ type : "appStoreVersionPhasedReleases" ,
420+ id : phasedReleaseId ,
421+ attributes : { phasedReleaseState } ,
422+ } ,
423+ } ,
424+ } ) ;
425+
426+ apiCache . deleteByPrefix ( `apps:version-detail:${ versionId } :` ) ;
427+ res . json ( {
428+ id : data . data . id ,
429+ phasedReleaseState : data . data . attributes . phasedReleaseState ,
430+ currentDayNumber : data . data . attributes . currentDayNumber ,
431+ startDate : data . data . attributes . startDate ,
432+ totalPauseDuration : data . data . attributes . totalPauseDuration ,
433+ } ) ;
434+ } catch ( err ) {
435+ console . error ( `Failed to update phased release ${ phasedReleaseId } :` , err . message ) ;
436+ res . status ( 502 ) . json ( { error : err . message } ) ;
437+ }
438+ } ) ;
439+
440+ router . delete ( "/:appId/versions/:versionId/phased-release/:phasedReleaseId" , async ( req , res ) => {
441+ const { versionId, phasedReleaseId } = req . params ;
442+ const { accountId } = req . query ;
443+
444+ const accounts = getAccounts ( ) ;
445+ const account = accounts . find ( ( a ) => a . id === accountId ) || accounts [ 0 ] ;
446+ if ( ! account ) return res . status ( 400 ) . json ( { error : "No accounts configured" } ) ;
447+
448+ try {
449+ await ascFetch ( account , `/v1/appStoreVersionPhasedReleases/${ phasedReleaseId } ` , { method : "DELETE" } ) ;
450+ apiCache . deleteByPrefix ( `apps:version-detail:${ versionId } :` ) ;
451+ res . json ( { success : true } ) ;
452+ } catch ( err ) {
453+ console . error ( `Failed to delete phased release ${ phasedReleaseId } :` , err . message ) ;
454+ res . status ( 502 ) . json ( { error : err . message } ) ;
455+ }
456+ } ) ;
457+
308458router . get ( "/:appId/builds" , async ( req , res ) => {
309459 const { appId } = req . params ;
310460 const { accountId } = req . query ;
0 commit comments