11import { createClerkClient } from '@clerk/backend' ;
2+ import { isClerkAPIResponseError } from '@clerk/shared/error' ;
23import { parsePublishableKey } from '@clerk/shared/keys' ;
34import { isStaging } from '@clerk/shared/utils' ;
45import { test as setup } from '@playwright/test' ;
@@ -18,62 +19,112 @@ setup('cleanup instances ', async () => {
1819 } )
1920 . filter ( Boolean ) ;
2021
22+ const errors : Array < { instance : string ; error : Error ; operation : string } > = [ ] ;
23+
2124 for ( const entry of entries ) {
22- console . log ( `Cleanup for ${ entry . secretKey . replace ( / ( s k _ ( t e s t | l i v e ) _ ) ( .+ ) ( ...) / , '$1***$4' ) } ` ) ;
23- const clerkClient = createClerkClient ( { secretKey : entry . secretKey , apiUrl : entry . apiUrl } ) ;
24- const { data : usersWithEmail } = await clerkClient . users . getUserList ( {
25- orderBy : '-created_at' ,
26- query : 'clerkcookie' ,
27- limit : 150 ,
28- } ) ;
25+ const instanceKey = entry . secretKey . replace ( / ( s k _ ( t e s t | l i v e ) _ ) ( .+ ) ( ...) / , '$1***$4' ) ;
26+ console . log ( `Cleanup for ${ instanceKey } ` ) ;
2927
30- const { data : usersWithPhoneNumber } = await clerkClient . users . getUserList ( {
31- orderBy : '-created_at' ,
32- query : '55501' ,
33- limit : 150 ,
34- } ) ;
28+ try {
29+ const clerkClient = createClerkClient ( { secretKey : entry . secretKey , apiUrl : entry . apiUrl } ) ;
3530
36- const users = [ ...usersWithEmail , ...usersWithPhoneNumber ] ;
31+ // Get users
32+ let users : any [ ] = [ ] ;
33+ try {
34+ const { data : usersWithEmail } = await clerkClient . users . getUserList ( {
35+ orderBy : '-created_at' ,
36+ query : 'clerkcookie' ,
37+ limit : 150 ,
38+ } ) ;
3739
38- const { data : orgs } = await clerkClient . organizations
39- . getOrganizationList ( {
40- limit : 150 ,
41- } )
42- . catch ( ( ) => ( { data : [ ] } ) ) ;
40+ const { data : usersWithPhoneNumber } = await clerkClient . users . getUserList ( {
41+ orderBy : '-created_at' ,
42+ query : '55501' ,
43+ limit : 150 ,
44+ } ) ;
4345
44- const usersToDelete = batchElements ( skipObjectsThatWereCreatedWithinTheLast10Minutes ( users ) , 5 ) ;
45- const orgsToDelete = batchElements ( skipObjectsThatWereCreatedWithinTheLast10Minutes ( orgs ) , 5 ) ;
46+ users = [ ...usersWithEmail , ...usersWithPhoneNumber ] ;
47+ } catch ( error ) {
48+ errors . push ( { instance : instanceKey , error : error as Error , operation : 'getUserList' } ) ;
49+ console . error ( `Error getting users for ${ instanceKey } :` , error ) ;
50+ users = [ ] ; // Continue with empty users list
51+ }
4652
47- for ( const batch of usersToDelete ) {
48- console . log ( `Starting batch...` ) ;
49- await Promise . all (
50- batch . map ( user => {
51- console . log (
52- `Cleaning up user ${ user . id } (${ user . emailAddresses ?. [ 0 ] ?. emailAddress || user . phoneNumbers ?. [ 0 ] ?. phoneNumber } ) (${ new Date (
53- user . createdAt ,
54- ) . toISOString ( ) } )`,
55- ) ;
56- return clerkClient . users . deleteUser ( user . id ) . catch ( error => {
57- console . error ( `Error deleting user ${ user . id } :` , error ) ;
58- } ) ;
59- } ) ,
60- ) ;
61- await new Promise ( r => setTimeout ( r , 1000 ) ) ;
62- }
53+ // Get organizations
54+ let orgs : any [ ] = [ ] ;
55+ try {
56+ const { data : orgsData } = await clerkClient . organizations . getOrganizationList ( {
57+ limit : 150 ,
58+ } ) ;
59+ orgs = orgsData ;
60+ } catch ( error ) {
61+ // Treat 404 (not found) and 403 (forbidden) as "no orgs"
62+ // 404 = no organizations exist, 403 = no permission to access organizations
63+ if ( isClerkAPIResponseError ( error ) && ( error . status === 404 || error . status === 403 ) ) {
64+ orgs = [ ] ;
65+ } else {
66+ errors . push ( { instance : instanceKey , error : error as Error , operation : 'getOrganizationList' } ) ;
67+ console . error ( `Error getting organizations for ${ instanceKey } :` , error ) ;
68+ orgs = [ ] ; // Continue with empty orgs list
69+ }
70+ }
71+
72+ const usersToDelete = batchElements ( skipObjectsThatWereCreatedWithinTheLast10Minutes ( users ) , 5 ) ;
73+ const orgsToDelete = batchElements ( skipObjectsThatWereCreatedWithinTheLast10Minutes ( orgs ) , 5 ) ;
6374
64- for ( const batch of orgsToDelete ) {
65- console . log ( `Starting batch...` ) ;
66- await Promise . all (
67- batch . map ( org => {
68- console . log ( `Cleaning up org ${ org . id } (${ org . name } ) (${ new Date ( org . createdAt ) . toISOString ( ) } )` ) ;
69- return clerkClient . organizations . deleteOrganization ( org . id ) . catch ( error => {
70- console . error ( `Error deleting org ${ org . id } :` , error ) ;
71- } ) ;
72- } ) ,
73- ) ;
74- await new Promise ( r => setTimeout ( r , 1000 ) ) ;
75+ // Delete users
76+ for ( const batch of usersToDelete ) {
77+ console . log ( `Starting user deletion batch...` ) ;
78+ await Promise . all (
79+ batch . map ( user => {
80+ console . log (
81+ `Cleaning up user ${ user . id } (${ user . emailAddresses ?. [ 0 ] ?. emailAddress || user . phoneNumbers ?. [ 0 ] ?. phoneNumber } ) (${ new Date (
82+ user . createdAt ,
83+ ) . toISOString ( ) } )`,
84+ ) ;
85+ return clerkClient . users . deleteUser ( user . id ) . catch ( error => {
86+ console . error ( `Error deleting user ${ user . id } :` , error ) ;
87+ } ) ;
88+ } ) ,
89+ ) ;
90+ await new Promise ( r => setTimeout ( r , 1000 ) ) ;
91+ }
92+
93+ // Delete organizations
94+ for ( const batch of orgsToDelete ) {
95+ console . log ( `Starting organization deletion batch...` ) ;
96+ await Promise . all (
97+ batch . map ( org => {
98+ console . log ( `Cleaning up org ${ org . id } (${ org . name } ) (${ new Date ( org . createdAt ) . toISOString ( ) } )` ) ;
99+ return clerkClient . organizations . deleteOrganization ( org . id ) . catch ( error => {
100+ console . error ( `Error deleting org ${ org . id } :` , error ) ;
101+ } ) ;
102+ } ) ,
103+ ) ;
104+ await new Promise ( r => setTimeout ( r , 1000 ) ) ;
105+ }
106+ } catch ( error ) {
107+ errors . push ( { instance : instanceKey , error : error as Error , operation : 'general' } ) ;
108+ console . error ( `General error during cleanup for ${ instanceKey } :` , error ) ;
75109 }
76110 }
111+
112+ // Report all errors at the end
113+ if ( errors . length > 0 ) {
114+ console . log ( '\n=== CLEANUP ERRORS SUMMARY ===' ) ;
115+ errors . forEach ( ( { instance, error, operation } ) => {
116+ console . log ( `Instance: ${ instance } ` ) ;
117+ console . log ( `Operation: ${ operation } ` ) ;
118+ console . log ( `Error: ${ error . message } ` ) ;
119+ if ( isClerkAPIResponseError ( error ) ) {
120+ console . log ( `Status: ${ error . status } ` ) ;
121+ }
122+ console . log ( '---' ) ;
123+ } ) ;
124+ console . log ( `Total errors: ${ errors . length } ` ) ;
125+ } else {
126+ console . log ( '\n✅ Cleanup completed successfully with no errors' ) ;
127+ }
77128} ) ;
78129
79130const skipObjectsThatWereCreatedWithinTheLast10Minutes = < T extends { createdAt : string } > ( objects : T [ ] ) : T [ ] => {
0 commit comments